2021-08-27 08:30:39 +02:00

160 lines
4.0 KiB
JavaScript

'use strict';
var sprintf = require('sprintf-js').sprintf;
var v6 = require('./constants.js');
function groupPossibilities(possibilities) {
return sprintf('(%s)', possibilities.join('|'));
}
function padGroup(group) {
if (group.length < 4) {
return sprintf('0{0,%d}%s', 4 - group.length, group);
}
return group;
}
var ADDRESS_BOUNDARY = '[^A-Fa-f0-9:]';
function simpleRegularExpression(groups) {
var zeroIndexes = [];
groups.forEach(function (group, i) {
var groupInteger = parseInt(group, 16);
if (groupInteger === 0) {
zeroIndexes.push(i);
}
});
// You can technically elide a single 0, this creates the regular expressions
// to match that eventuality
var possibilities = zeroIndexes.map(function (zeroIndex) {
return groups.map(function (group, i) {
if (i === zeroIndex) {
var elision = (i === 0 || i === v6.GROUPS - 1) ? ':' : '';
return groupPossibilities([padGroup(group), elision]);
}
return padGroup(group);
}).join(':');
});
// The simplest case
possibilities.push(groups.map(padGroup).join(':'));
return groupPossibilities(possibilities);
}
function possibleElisions(elidedGroups, moreLeft, moreRight) {
var left = moreLeft ? '' : ':';
var right = moreRight ? '' : ':';
var possibilities = [];
// 1. elision of everything (::)
if (!moreLeft && !moreRight) {
possibilities.push('::');
}
// 2. complete elision of the middle
if (moreLeft && moreRight) {
possibilities.push('');
}
if ((moreRight && !moreLeft) || (!moreRight && moreLeft)) {
// 3. complete elision of one side
possibilities.push(':');
}
// 4. elision from the left side
possibilities.push(sprintf('%s(:0{1,4}){1,%d}', left, elidedGroups - 1));
// 5. elision from the right side
possibilities.push(sprintf('(0{1,4}:){1,%d}%s', elidedGroups - 1, right));
// 6. no elision
possibilities.push(sprintf('(0{1,4}:){%d}0{1,4}', elidedGroups - 1));
// 7. elision (including sloppy elision) from the middle
for (var groups = 1; groups < elidedGroups - 1; groups++) {
for (var position = 1; position < elidedGroups - groups; position++) {
possibilities.push(sprintf('(0{1,4}:){%d}:(0{1,4}:){%d}0{1,4}',
position,
elidedGroups - position - groups - 1));
}
}
return groupPossibilities(possibilities);
}
/**
* Generate a regular expression string that can be used to find or validate
* all variations of this address
* @memberof Address6
* @instance
* @param {string} optionalSubString
* @returns {string}
*/
exports.regularExpressionString = function (optionalSubString) {
if (optionalSubString === undefined) {
optionalSubString = false;
}
var output = [];
// TODO: revisit why this is necessary
var address6 = new this.constructor(this.correctForm());
if (address6.elidedGroups === 0) {
// The simple case
output.push(simpleRegularExpression(address6.parsedAddress));
} else if (address6.elidedGroups === v6.GROUPS) {
// A completely elided address
output.push(possibleElisions(v6.GROUPS));
} else {
// A partially elided address
var halves = address6.address.split('::');
if (halves[0].length) {
output.push(simpleRegularExpression(halves[0].split(':')));
}
output.push(possibleElisions(address6.elidedGroups,
halves[0].length !== 0,
halves[1].length !== 0));
if (halves[1].length) {
output.push(simpleRegularExpression(halves[1].split(':')));
}
output = [output.join(':')];
}
if (!optionalSubString) {
output = [].concat(
'(?=^|',
ADDRESS_BOUNDARY,
'|[^\\w\\:])(', output, ')(?=[^\\w\\:]|',
ADDRESS_BOUNDARY,
'|$)');
}
return output.join('');
};
/**
* Generate a regular expression that can be used to find or validate all
* variations of this address.
* @memberof Address6
* @instance
* @param {string} optionalSubString
* @returns {RegExp}
*/
exports.regularExpression = function (optionalSubstring) {
return new RegExp(this.regularExpressionString(optionalSubstring), 'i');
};