feat(planning): grille hebdomadaire complète avec API et filtres

- Connexion API via proxy Angular (résolution CORS, base path /api)
- Import CSS ng-zorro global pour les modales et composants
- Filtres Camion/Show câblés sur l'affichage de la grille
- Camions affichés via TrucksService (linkés au show du même créneau)
- Panneau de détails : spectacles + camions du jour sélectionné
- Modale de création de spectacle stylisée avec fond et centrage
- Positionnement précis des events à la minute dans leur créneau
- Auto-scroll vers l'heure courante au chargement
- Ligne "maintenant" sur la colonne du jour actuel
- Régénération des services OpenAPI (nouveaux noms de types)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 20:36:03 +02:00
parent 150b97cd2e
commit 654b297e2e
3131 changed files with 149304 additions and 104334 deletions
+131 -345
View File
@@ -34,7 +34,6 @@ const ipv4_1 = require("./ipv4");
const regular_expressions_1 = require("./v6/regular-expressions");
const address_error_1 = require("./address-error");
const common_1 = require("./common");
const isCorrect6 = common.isCorrect(constants6.BITS);
function assert(condition) {
if (!condition) {
throw new Error('Assertion failed.');
@@ -78,6 +77,7 @@ function unsignByte(b) {
}
/**
* Represents an IPv6 address
* @class Address6
* @param {string} address - An IPv6 address string
* @param {number} [groups=8] - How many octets to parse
* @example
@@ -94,14 +94,18 @@ class Address6 {
// #region Attributes
/**
* Returns true if the given address is in the subnet of the current address
* @memberof Address6
* @instance
* @returns {boolean}
*/
this.isInSubnet = common.isInSubnet;
/**
* Returns true if the address is correct, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
this.isCorrect = isCorrect6;
this.isCorrect = common.isCorrect(constants6.BITS);
if (optionalGroups === undefined) {
this.groups = constants6.GROUPS;
}
@@ -132,13 +136,6 @@ class Address6 {
this.addressMinusSuffix = address;
this.parsedAddress = this.parse(this.addressMinusSuffix);
}
/**
* Returns true if the given string is a valid IPv6 address (with optional
* CIDR subnet and zone identifier), false otherwise. Host bits in the
* subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict
* network-address validation compare `correctForm()` to
* `startAddress().correctForm()`, or use `networkForm()`.
*/
static isValid(address) {
try {
// eslint-disable-next-line no-new
@@ -150,8 +147,9 @@ class Address6 {
}
}
/**
* Convert a BigInt to a v6 address object. The value must be in the
* range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
* Convert a BigInt to a v6 address object
* @memberof Address6
* @static
* @param {bigint} bigInt - a BigInt to convert
* @returns {Address6}
* @example
@@ -160,21 +158,19 @@ class Address6 {
* address.correctForm(); // '::e8:d4a5:1000'
*/
static fromBigInt(bigInt) {
if (bigInt < 0n || bigInt > (1n << BigInt(constants6.BITS)) - 1n) {
throw new address_error_1.AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
}
const hex = bigInt.toString(16).padStart(32, '0');
const groups = [];
for (let i = 0; i < constants6.GROUPS; i++) {
let i;
for (i = 0; i < constants6.GROUPS; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
* Parse a URL (with optional bracketed host and port) into an address and
* port. Returns either `{ address, port }` on success or
* `{ error, address: null, port: null }` if the URL could not be parsed.
* Ports are returned as numbers (or `null` if absent or out of range).
* Convert a URL (with optional port number) to an address object
* @memberof Address6
* @static
* @param {string} url - a URL with optional port number
* @example
* var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
* addressAndPort.address.correctForm(); // 'ffff::'
@@ -233,92 +229,10 @@ class Address6 {
port,
};
}
/**
* Construct an `Address6` from an address and a hex subnet mask given as
* separate strings (e.g. as returned by Node's `os.networkInterfaces()`).
* Throws `AddressError` if the mask is non-contiguous (e.g.
* `ffff::ffff`).
* @example
* var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::');
* address.subnetMask; // 64
*/
static fromAddressAndMask(address, mask) {
const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
return new Address6(`${address}/${bits}`);
}
/**
* Construct an `Address6` from an address and a Cisco-style wildcard mask
* given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`).
* The wildcard mask is the bitwise inverse of the subnet mask. Throws
* `AddressError` if the mask is non-contiguous.
* @example
* var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff');
* address.subnetMask; // 64
*/
static fromAddressAndWildcardMask(address, wildcardMask) {
const wildcard = new Address6(wildcardMask).bigInt();
const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
// eslint-disable-next-line no-bitwise
const mask = wildcard ^ allOnes;
const bits = common.prefixLengthFromMask(mask, constants6.BITS);
return new Address6(`${address}/${bits}`);
}
/**
* Construct an `Address6` from a wildcard pattern with trailing `*`
* groups. The number of trailing wildcards determines the prefix
* length: each `*` represents 16 bits. `::` is expanded to zero groups
* (not wildcards) before evaluating trailing wildcards.
*
* Only trailing whole-group wildcards are supported. Partial-group
* wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g.
* `*::1`) throw `AddressError`.
* @example
* Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32'
* Address6.fromWildcard('2001:db8::*').subnet; // '/112'
* Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0'
*/
static fromWildcard(input) {
if (input.includes('%') || input.includes('/')) {
throw new address_error_1.AddressError('Wildcard pattern must not include a zone or CIDR suffix');
}
const halves = input.split('::');
if (halves.length > 2) {
throw new address_error_1.AddressError("Wildcard pattern cannot contain more than one '::'");
}
let groups;
if (halves.length === 2) {
const left = halves[0] === '' ? [] : halves[0].split(':');
const right = halves[1] === '' ? [] : halves[1].split(':');
const remaining = constants6.GROUPS - left.length - right.length;
if (remaining < 1) {
throw new address_error_1.AddressError("Wildcard pattern with '::' has too many groups");
}
groups = [...left, ...new Array(remaining).fill('0'), ...right];
}
else {
groups = input.split(':');
}
if (groups.length !== constants6.GROUPS) {
throw new address_error_1.AddressError('Wildcard pattern must have 8 groups');
}
let firstWildcard = -1;
for (let i = 0; i < groups.length; i++) {
if (groups[i] === '*') {
if (firstWildcard === -1) {
firstWildcard = i;
}
}
else if (firstWildcard !== -1) {
throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)');
}
}
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
const replaced = groups.map((g) => (g === '*' ? '0' : g));
const subnetBits = constants6.BITS - trailing * 16;
return new Address6(`${replaced.join(':')}/${subnetBits}`);
}
/**
* Create an IPv6-mapped address given an IPv4 address
* @memberof Address6
* @static
* @param {string} address - An IPv4 address string
* @returns {Address6}
* @example
@@ -333,6 +247,8 @@ class Address6 {
}
/**
* Return an address from ip6.arpa form
* @memberof Address6
* @static
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
* @returns {Adress6}
* @example
@@ -357,6 +273,8 @@ class Address6 {
}
/**
* Return the Microsoft UNC transcription of the address
* @memberof Address6
* @instance
* @returns {String} the Microsoft UNC transcription of the address
*/
microsoftTranscription() {
@@ -364,6 +282,8 @@ class Address6 {
}
/**
* Return the first n bits of the address, defaulting to the subnet mask
* @memberof Address6
* @instance
* @param {number} [mask=subnet] - the number of bits to mask
* @returns {String} the first n bits of the address as a string
*/
@@ -372,6 +292,8 @@ class Address6 {
}
/**
* Return the number of possible subnets of a given size in the address
* @memberof Address6
* @instance
* @param {number} [subnetSize=128] - the subnet size
* @returns {String}
*/
@@ -387,6 +309,8 @@ class Address6 {
}
/**
* Helper function getting start address.
* @memberof Address6
* @instance
* @returns {bigint}
*/
_startAddress() {
@@ -395,6 +319,8 @@ class Address6 {
/**
* The first address in the range given by this address' subnet
* Often referred to as the Network Address.
* @memberof Address6
* @instance
* @returns {Address6}
*/
startAddress() {
@@ -403,6 +329,8 @@ class Address6 {
/**
* The first host address in the range given by this address's subnet ie
* the first address after the Network Address
* @memberof Address6
* @instance
* @returns {Address6}
*/
startAddressExclusive() {
@@ -411,6 +339,8 @@ class Address6 {
}
/**
* Helper function getting end address.
* @memberof Address6
* @instance
* @returns {bigint}
*/
_endAddress() {
@@ -419,6 +349,8 @@ class Address6 {
/**
* The last address in the range given by this address' subnet
* Often referred to as the Broadcast
* @memberof Address6
* @instance
* @returns {Address6}
*/
endAddress() {
@@ -427,6 +359,8 @@ class Address6 {
/**
* The last host address in the range given by this address's subnet ie
* the last address prior to the Broadcast Address
* @memberof Address6
* @instance
* @returns {Address6}
*/
endAddressExclusive() {
@@ -434,73 +368,36 @@ class Address6 {
return Address6.fromBigInt(this._endAddress() - adjust);
}
/**
* The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
* `/64`. Returns an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
subnetMaskAddress() {
return Address6.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`));
}
/**
* The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a
* `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns
* an `Address6`; call `.correctForm()` for the string.
* @returns {Address6}
*/
wildcardMask() {
return Address6.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`));
}
/**
* The network address in CIDR string form, e.g. `2001:db8::/32` for
* `2001:db8::1/32`. For an address with no explicit subnet the prefix
* is `/128`, e.g. `networkForm()` on `2001:db8::1` returns
* `2001:db8::1/128`.
* @returns {string}
*/
networkForm() {
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
}
/**
* Return the scope of the address. The 4-bit scope field
* ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7))
* is only defined for multicast addresses; for unicast addresses the scope
* is derived from the address type per
* [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6).
* Return the scope of the address
* @memberof Address6
* @instance
* @returns {String}
*/
getScope() {
const type = this.getType();
if (type === 'Multicast' || type.startsWith('Multicast ')) {
const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
return scope || 'Unknown';
let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
if (this.getType() === 'Global unicast' && scope !== 'Link local') {
scope = 'Global';
}
// RFC 4291 §2.5.3: the loopback address is treated as having Link-Local
// scope. (Multicast scope 1, "Interface-Local", is a different concept
// used only for loopback transmission of multicast.)
if (type === 'Link-local unicast' || type === 'Loopback') {
return 'Link local';
}
// RFC 4007 §6: the unspecified address has no scope.
if (type === 'Unspecified') {
return 'Unknown';
}
return 'Global';
return scope || 'Unknown';
}
/**
* Return the type of the address
* @memberof Address6
* @instance
* @returns {String}
*/
getType() {
for (let i = 0; i < TYPE_SUBNETS.length; i++) {
const entry = TYPE_SUBNETS[i];
if (this.isInSubnet(entry[0])) {
return entry[1];
for (const subnet of Object.keys(constants6.TYPES)) {
if (this.isInSubnet(new Address6(subnet))) {
return constants6.TYPES[subnet];
}
}
return 'Global unicast';
}
/**
* Return the bits in the given range as a BigInt
* @memberof Address6
* @instance
* @returns {bigint}
*/
getBits(start, end) {
@@ -508,6 +405,8 @@ class Address6 {
}
/**
* Return the bits in the given range as a base-2 string
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsBase2(start, end) {
@@ -515,6 +414,8 @@ class Address6 {
}
/**
* Return the bits in the given range as a base-16 string
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsBase16(start, end) {
@@ -528,6 +429,8 @@ class Address6 {
}
/**
* Return the bits that are set past the subnet mask length
* @memberof Address6
* @instance
* @returns {String}
*/
getBitsPastSubnet() {
@@ -535,8 +438,10 @@ class Address6 {
}
/**
* Return the reversed ip6.arpa form of the address
* @memberof Address6
* @param {Object} options
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
* @instance
* @returns {String}
*/
reverseForm(options) {
@@ -562,10 +467,10 @@ class Address6 {
return 'ip6.arpa.';
}
/**
* Returns the address in correct form, per
* [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
* stripped, the longest run of zero groups collapsed to `::`, and hex digits
* lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
* Return the correct form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
correctForm() {
let i;
@@ -609,6 +514,8 @@ class Address6 {
}
/**
* Return a zero-padded base-2 string representation of the address
* @memberof Address6
* @instance
* @returns {String}
* @example
* var address = new Address6('2001:4860:4001:803::1011');
@@ -617,22 +524,10 @@ class Address6 {
* // 0000000000000000000000000000000000000000000000000001000000010001'
*/
binaryZeroPad() {
if (this._binaryZeroPad === undefined) {
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
}
return this._binaryZeroPad;
return this.bigInt().toString(2).padStart(constants6.BITS, '0');
}
/**
* Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the
* trailing IPv4 address into `this.address4` / `this.parsedAddress4` and
* returning the address with the v4 portion converted to two v6 groups.
* Used internally by `parse()`.
*/
// TODO: Improve the semantics of this helper function
parse4in6(address) {
if (address.indexOf('.') === -1) {
return address;
}
const groups = address.split(':');
const lastGroup = groups.slice(-1)[0];
const address4 = lastGroup.match(constants4.RE_ADDRESS);
@@ -641,12 +536,7 @@ class Address6 {
this.address4 = new ipv4_1.Address4(this.parsedAddress4);
for (let i = 0; i < this.address4.groups; i++) {
if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
// The prefix groups haven't been through the bad-character check
// yet, so escape them before including in the error HTML.
const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join('.');
const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
const separator = groups.length > 1 ? ':' : '';
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`);
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join('.')));
}
}
this.v4 = true;
@@ -655,13 +545,6 @@ class Address6 {
}
return address;
}
/**
* Parses an IPv6 address string into its 8 hexadecimal groups (expanding
* any `::` elision and any trailing v4-in-v6 portion) and stores the result
* on `this.parsedAddress`. Called automatically by the constructor; you
* typically don't need to call it directly. Throws `AddressError` if the
* input is malformed.
*/
// TODO: Make private?
parse(address) {
address = this.parse4in6(address);
@@ -711,16 +594,18 @@ class Address6 {
return groups;
}
/**
* Returns the canonical (fully expanded) form of the address: all 8 groups,
* each padded to 4 hex digits, with no `::` collapsing
* (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
* byte-exact comparison.
* Return the canonical form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
canonicalForm() {
return this.parsedAddress.map(paddedHex).join(':');
}
/**
* Return the decimal form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
decimal() {
@@ -728,6 +613,8 @@ class Address6 {
}
/**
* Return the address as a BigInt
* @memberof Address6
* @instance
* @returns {bigint}
*/
bigInt() {
@@ -735,6 +622,8 @@ class Address6 {
}
/**
* Return the last two groups of this address as an IPv4 address string
* @memberof Address6
* @instance
* @returns {Address4}
* @example
* var address = new Address6('2001:4860:4001::1825:bf11');
@@ -742,10 +631,12 @@ class Address6 {
*/
to4() {
const binary = this.binaryZeroPad().split('');
return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16).padStart(8, '0'));
return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16));
}
/**
* Return the v4-in-v6 form of the address
* @memberof Address6
* @instance
* @returns {String}
*/
to4in6() {
@@ -759,10 +650,10 @@ class Address6 {
return correct + infix + address4.address;
}
/**
* Decodes the Teredo tunneling fields embedded in this address. Returns the
* Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
* UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
* group/individual, nonce). Only meaningful for addresses in `2001::/32`.
* Return an object containing the Teredo properties of the address
* @memberof Address6
* @instance
* @returns {Object}
*/
inspectTeredo() {
/*
@@ -793,7 +684,7 @@ class Address6 {
const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
const bitsForClient4 = this.getBits(96, 128);
// eslint-disable-next-line no-bitwise
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'));
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16));
const flagsBase2 = this.getBitsBase2(64, 80);
const coneNat = (0, common_1.testBit)(flagsBase2, 15);
const reserved = (0, common_1.testBit)(flagsBase2, 14);
@@ -816,9 +707,10 @@ class Address6 {
};
}
/**
* Decodes the 6to4 tunneling fields embedded in this address. Returns the
* 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
* addresses in `2002::/16`.
* Return an object containing the 6to4 properties of the address
* @memberof Address6
* @instance
* @returns {Object}
*/
inspect6to4() {
/*
@@ -834,6 +726,8 @@ class Address6 {
}
/**
* Return a v6 6to4 address from a v6 v4inv6 address
* @memberof Address6
* @instance
* @returns {Address6}
*/
to6to4() {
@@ -850,80 +744,9 @@ class Address6 {
return new Address6(addr6to4);
}
/**
* Embed an IPv4 address into a NAT64 IPv6 address using the encoding
* defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
* length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
* than /64 the IPv4 octets are split around the reserved bits 6471.
* @example
* Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221'
* Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::'
*/
static fromAddress4Nat64(address, prefix = '64:ff9b::/96') {
const v4 = new ipv4_1.Address4(address);
const prefix6 = new Address6(prefix);
const pl = prefix6.subnetMask;
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
}
const prefixBits = prefix6.binaryZeroPad();
const v4Bits = v4.binaryZeroPad();
let bits;
if (pl === 96) {
bits = prefixBits.slice(0, 96) + v4Bits;
}
else {
const beforeU = 64 - pl;
bits =
prefixBits.slice(0, pl) +
v4Bits.slice(0, beforeU) +
'00000000' +
v4Bits.slice(beforeU) +
'0'.repeat(128 - 72 - (32 - beforeU));
}
const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
const groups = [];
for (let i = 0; i < 8; i++) {
groups.push(hex.slice(i * 4, (i + 1) * 4));
}
return new Address6(groups.join(':'));
}
/**
* Extract the embedded IPv4 address from a NAT64 IPv6 address using the
* encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
* The default prefix is the well-known prefix `64:ff9b::/96`. Returns
* `null` if this address is not contained within the given prefix.
* @example
* new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33'
*/
toAddress4Nat64(prefix = '64:ff9b::/96') {
const prefix6 = new Address6(prefix);
const pl = prefix6.subnetMask;
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
}
if (!this.isInSubnet(prefix6)) {
return null;
}
const bits = this.binaryZeroPad();
let v4Bits;
if (pl === 96) {
v4Bits = bits.slice(96, 128);
}
else {
const beforeU = 64 - pl;
v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU));
}
const octets = [];
for (let i = 0; i < 4; i++) {
octets.push(parseInt(v4Bits.slice(i * 8, (i + 1) * 8), 2).toString());
}
return new ipv4_1.Address4(octets.join('.'));
}
/**
* Return a byte array.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
* Return a byte array
* @memberof Address6
* @instance
* @returns {Array}
*/
toByteArray() {
@@ -937,27 +760,27 @@ class Address6 {
return bytes;
}
/**
* Return an unsigned byte array.
*
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
* Return an unsigned byte array
* @memberof Address6
* @instance
* @returns {Array}
*/
toUnsignedByteArray() {
return this.toByteArray().map(unsignByte);
}
/**
* Convert a byte array to an Address6 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
* Convert a byte array to an Address6 object
* @memberof Address6
* @static
* @returns {Address6}
*/
static fromByteArray(bytes) {
return this.fromUnsignedByteArray(bytes.map(unsignByte));
}
/**
* Convert an unsigned byte array to an Address6 object.
*
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
* Convert an unsigned byte array to an Address6 object
* @memberof Address6
* @static
* @returns {Address6}
*/
static fromUnsignedByteArray(bytes) {
@@ -972,6 +795,8 @@ class Address6 {
}
/**
* Returns true if the address is in the canonical form, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isCanonical() {
@@ -979,6 +804,8 @@ class Address6 {
}
/**
* Returns true if the address is a link local address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isLinkLocal() {
@@ -991,81 +818,53 @@ class Address6 {
}
/**
* Returns true if the address is a multicast address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isMulticast() {
const type = this.getType();
return type === 'Multicast' || type.startsWith('Multicast ');
return this.getType() === 'Multicast';
}
/**
* Returns true if the address was written in v4-in-v6 dotted-quad notation
* (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
* and does not reflect whether the address bits lie in the IPv4-mapped
* (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
* Returns true if the address is a v4-in-v6 address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
is4() {
return this.v4;
}
/**
* Returns true if the address is an IPv4-mapped IPv6 address in
* `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)),
* false otherwise. Unlike {@link is4}, this checks the underlying address
* bits rather than the textual notation, so `::ffff:127.0.0.1` and
* `::ffff:7f00:1` both return true.
* @returns {boolean}
*/
isMapped4() {
return this.isInSubnet(IPV4_MAPPED_SUBNET);
}
/**
* Returns true if the address is a Teredo address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isTeredo() {
return this.isInSubnet(TEREDO_SUBNET);
return this.isInSubnet(new Address6('2001::/32'));
}
/**
* Returns true if the address is a 6to4 address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
is6to4() {
return this.isInSubnet(SIX_TO_FOUR_SUBNET);
return this.isInSubnet(new Address6('2002::/16'));
}
/**
* Returns true if the address is a loopback address, false otherwise
* @memberof Address6
* @instance
* @returns {boolean}
*/
isLoopback() {
return this.getType() === 'Loopback';
}
/**
* Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses.
* @returns {boolean}
*/
isULA() {
return this.isInSubnet(ULA_SUBNET);
}
/**
* Returns true if the address is the unspecified address `::`.
* @returns {boolean}
*/
isUnspecified() {
return this.getType() === 'Unspecified';
}
/**
* Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)).
* @returns {boolean}
*/
isDocumentation() {
return this.isInSubnet(DOCUMENTATION_SUBNET);
}
// #endregion
// #region HTML
/**
* Returns the address as an HTTP URL with the host bracketed, e.g.
* `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended,
* e.g. `http://[2001:db8::1]:8080/`.
* @returns {String} the address in link form with a default port of 80
*/
href(optionalPort) {
if (optionalPort === undefined) {
@@ -1077,12 +876,7 @@ class Address6 {
return `http://[${this.correctForm()}]${optionalPort}/`;
}
/**
* Returns an HTML `<a>` element whose `href` encodes the address in a URL
* hash fragment (default prefix `/#address=`). Useful for linking between
* pages of an address-inspector UI.
* @param options.className - CSS class for the rendered `<a>` element
* @param options.prefix - hash prefix prepended to the address (default `/#address=`)
* @param options.v4 - when true, render the address in v4-in-v6 form
* @returns {String} a link suitable for conveying the address via a URL hash
*/
link(options) {
if (!options) {
@@ -1102,13 +896,10 @@ class Address6 {
formFunction = this.to4in6;
}
const form = formFunction.call(this);
const safeHref = helpers.escapeHtml(`${options.prefix}${form}`);
const safeForm = helpers.escapeHtml(form);
if (options.className) {
const safeClass = helpers.escapeHtml(options.className);
return `<a href="${safeHref}" class="${safeClass}">${safeForm}</a>`;
return `<a href="${options.prefix}${form}" class="${options.className}">${form}</a>`;
}
return `<a href="${safeHref}">${safeForm}</a>`;
return `<a href="${options.prefix}${form}">${form}</a>`;
}
/**
* Groups an address
@@ -1117,13 +908,13 @@ class Address6 {
group() {
if (this.elidedGroups === 0) {
// The simple case
return helpers.simpleGroup(this.addressMinusSuffix).join(':');
return helpers.simpleGroup(this.address).join(':');
}
assert(typeof this.elidedGroups === 'number');
assert(typeof this.elisionBegin === 'number');
// The elided case
const output = [];
const [left, right] = this.addressMinusSuffix.split('::');
const [left, right] = this.address.split('::');
if (left.length) {
output.push(...helpers.simpleGroup(left));
}
@@ -1153,6 +944,8 @@ class Address6 {
/**
* Generate a regular expression string that can be used to find or validate
* all variations of this address
* @memberof Address6
* @instance
* @param {boolean} substringSearch
* @returns {string}
*/
@@ -1197,6 +990,8 @@ class Address6 {
/**
* Generate a regular expression that can be used to find or validate all
* variations of this address.
* @memberof Address6
* @instance
* @param {boolean} substringSearch
* @returns {RegExp}
*/
@@ -1205,13 +1000,4 @@ class Address6 {
}
}
exports.Address6 = Address6;
const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [
new Address6(subnet),
constants6.TYPES[subnet],
]);
const TEREDO_SUBNET = new Address6('2001::/32');
const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
const ULA_SUBNET = new Address6('fc00::/7');
const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
//# sourceMappingURL=ipv6.js.map