160 lines
4.0 KiB
JavaScript
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');
|
|
};
|