mediawiki-title
Advanced tools
Comparing version 0.6.5 to 0.7.1
525
lib/index.js
@@ -1,6 +0,6 @@ | ||
"use strict"; | ||
'use strict'; | ||
var sanitizeIP = require('./ip'); | ||
var utils = require('./utils'); | ||
var phpCharToUpper = require('./mediawiki.Title.phpCharToUpper.js'); | ||
const sanitizeIP = require('./ip'); | ||
const utils = require('./utils'); | ||
const phpCharToUpper = require('./mediawiki.Title.phpCharToUpper.js'); | ||
@@ -13,20 +13,6 @@ /** | ||
*/ | ||
// We're using String.fromCharCode because the symbol itself is not liked by JSCS | ||
// and String.fromCodePoint() is around only starting from ES6 | ||
var UTF_8_REPLACEMENT = String.fromCharCode(0xFFFD); | ||
const UTF_8_REPLACEMENT = '�'; | ||
// Polyfill for array.find for node 0.10 support. | ||
function arrayFind(array, predicate) { | ||
for (var i = 0; i < array.length; i++) { | ||
if (predicate(array[i])) { | ||
return array[i]; | ||
} | ||
} | ||
return undefined; | ||
} | ||
/** | ||
* Convert db-key to readable text. | ||
* | ||
* @param {string} s | ||
@@ -67,32 +53,17 @@ * @return {string} | ||
/** | ||
* Represents a wiki namespace | ||
* | ||
* @param {number} id The namespace identifier | ||
* @param {SiteInfo} siteInfo The site metadata information. | ||
* @constructor | ||
*/ | ||
function Namespace(id, siteInfo) { | ||
this._siteInfo = siteInfo; | ||
this._id = Number(id); | ||
} | ||
function _getNSIndex(nsName, siteInfo) { | ||
function canonicalName(name) { | ||
return name.toUpperCase().replace(/_/g, ' '); | ||
} | ||
var name = canonicalName(nsName); | ||
var index = arrayFind(Object.keys(siteInfo.namespaces), function(nsId) { | ||
var ns = siteInfo.namespaces[nsId]; | ||
return ns.canonical && canonicalName(ns.canonical) === name | ||
|| ns['*'] && canonicalName(ns['*']) === name | ||
|| ns.name && canonicalName(ns.name) === name; | ||
const canonicalName = (name) => name.toUpperCase().replace(/_/g, ' '); | ||
const name = canonicalName(nsName); | ||
let index = Object.keys(siteInfo.namespaces).find((nsId) => { | ||
const ns = siteInfo.namespaces[nsId]; | ||
return ns.canonical && canonicalName(ns.canonical) === name || | ||
ns['*'] && canonicalName(ns['*']) === name || | ||
ns.name && canonicalName(ns.name) === name; | ||
}); | ||
if (!index) { | ||
// Not found within canonical names, try aliases | ||
index = arrayFind(siteInfo.namespacealiases, function(alias) { | ||
return name === canonicalName(alias['*'] || alias.alias); | ||
}); | ||
index = siteInfo.namespacealiases.find((alias) => | ||
name === canonicalName(alias['*'] || alias.alias)); | ||
if (index !== undefined) { | ||
index = '' + index.id; | ||
index = `${index.id}`; | ||
} | ||
@@ -103,29 +74,72 @@ } | ||
/** | ||
* Creates a namespace instance from namespace text or a namespace alias | ||
* | ||
* @param {string} text Namespace name text. | ||
* @param {SiteInfo} siteInfo the site information. | ||
* @returns {Namespace|undefined} a namespace or undefined if it wasn't found. | ||
*/ | ||
Namespace.fromText = function(text, siteInfo) { | ||
var index = _getNSIndex(text, siteInfo); | ||
if (index !== undefined) { | ||
return new Namespace(index, siteInfo); | ||
class Namespace { | ||
/** | ||
* Represents a wiki namespace | ||
* @param {number} id The namespace identifier | ||
* @param {SiteInfo} siteInfo The site metadata information. | ||
* @class | ||
*/ | ||
constructor(id, siteInfo) { | ||
this._siteInfo = siteInfo; | ||
this._id = Number(id); | ||
} | ||
return undefined; | ||
}; | ||
/** | ||
* Creates a namespace object for a `Main` namespace. | ||
* | ||
* @param {SiteInfo} siteInfo the site information. | ||
* @returns {Namespace} | ||
*/ | ||
Namespace.main = function(siteInfo) { | ||
return new Namespace(0, siteInfo); | ||
}; | ||
isATalkNamespace() { | ||
// See https://www.mediawiki.org/wiki/Manual:Namespace#Subject_and_talk_namespaces | ||
return this._id % 2 === 1; | ||
} | ||
/** | ||
* Get the normalized localized name string for this namespace. | ||
* @return {string} | ||
*/ | ||
getNormalizedText() { | ||
const nsInfo = this._siteInfo.namespaces[`${this._id}`]; | ||
const nsName = nsInfo['*'] || nsInfo.name; | ||
return nsName.replace(/ /g, '_'); | ||
} | ||
/** | ||
* Get the canonical non-localized name string for this namespace. | ||
* @return {string} | ||
*/ | ||
getCanonicalText() { | ||
return this._siteInfo.namespaces[`${this._id}`].canonical.replace(/ /g, '_'); | ||
} | ||
/** | ||
* Are subpages allowed for this namespace? | ||
* @return {boolean} | ||
*/ | ||
subpagesAllowed() { | ||
const subpages = this._siteInfo.namespaces[`${this._id}`].subpages; | ||
return subpages !== undefined && subpages !== false; | ||
} | ||
/** | ||
* Creates a namespace instance from namespace text or a namespace alias | ||
* @param {string} text Namespace name text. | ||
* @param {SiteInfo} siteInfo the site information. | ||
* @return {Namespace|undefined} a namespace or undefined if it wasn't found. | ||
*/ | ||
static fromText(text, siteInfo) { | ||
const index = _getNSIndex(text, siteInfo); | ||
if (index !== undefined) { | ||
return new Namespace(index, siteInfo); | ||
} | ||
return undefined; | ||
} | ||
/** | ||
* Creates a namespace object for a `Main` namespace. | ||
* @param {SiteInfo} siteInfo the site information. | ||
* @return {Namespace} | ||
*/ | ||
static main(siteInfo) { | ||
return new Namespace(0, siteInfo); | ||
} | ||
} | ||
/* Namespace id definitions from Defines.php in mediawiki-core */ | ||
var nameSpaceIds = { | ||
const nameSpaceIds = { | ||
Media: -2, | ||
@@ -148,3 +162,3 @@ Special: -1, | ||
Category: 14, | ||
CategoryTalk: 15, | ||
CategoryTalk: 15 | ||
}; | ||
@@ -155,46 +169,13 @@ nameSpaceIds.Image = nameSpaceIds.File; | ||
/* Define a boolean is<ns> function for every namespace */ | ||
for (var ns in nameSpaceIds) { | ||
(function(id) { | ||
Namespace.prototype['is' + ns] = function() { | ||
return this._id === id; | ||
}; | ||
})(nameSpaceIds[ns]); | ||
for (const ns in nameSpaceIds) { | ||
if (Object.prototype.hasOwnProperty.call(nameSpaceIds, ns)) { | ||
(function (id) { | ||
Namespace.prototype[`is${ns}`] = function () { | ||
return this._id === id; | ||
}; | ||
}(nameSpaceIds[ns])); | ||
} | ||
} | ||
Namespace.prototype.isATalkNamespace = function() { | ||
// See https://www.mediawiki.org/wiki/Manual:Namespace#Subject_and_talk_namespaces | ||
return this._id % 2 === 1; | ||
}; | ||
/** | ||
* Get the normalized localized name string for this namespace. | ||
* | ||
* @returns {string} | ||
*/ | ||
Namespace.prototype.getNormalizedText = function() { | ||
var nsInfo = this._siteInfo.namespaces[this._id + '']; | ||
var nsName = nsInfo['*'] || nsInfo.name; | ||
return nsName.replace(/ /g, '_'); | ||
}; | ||
/** | ||
* Get the canonical non-localized name string for this namespace. | ||
* | ||
* @returns {string} | ||
*/ | ||
Namespace.prototype.getCanonicalText = function() { | ||
return this._siteInfo.namespaces[this._id + ''].canonical.replace(/ /g, '_'); | ||
}; | ||
/** | ||
* Are subpages allowed for this namespace? | ||
* | ||
* @returns {boolean} | ||
*/ | ||
Namespace.prototype.subpagesAllowed = function() { | ||
var subpages = this._siteInfo.namespaces[this._id + ''].subpages; | ||
return subpages !== undefined && subpages !== false; | ||
}; | ||
var regexCache = {}; | ||
const regexCache = {}; | ||
function _createInvalidTitleRegex(legalTitleChars) { | ||
@@ -205,4 +186,4 @@ if (regexCache[legalTitleChars]) { | ||
// Any character not allowed is forbidden | ||
regexCache[legalTitleChars] = new RegExp('[^' + | ||
utils.convertByteClassToUnicodeClass(legalTitleChars) + ']' + | ||
regexCache[legalTitleChars] = new RegExp(`[^${ | ||
utils.convertByteClassToUnicodeClass(legalTitleChars)}]` + | ||
// URL percent encoding sequences interfere with the ability | ||
@@ -219,14 +200,14 @@ // to round-trip titles -- you can't link to them consistently. | ||
function _capitalizeTitle(result, siteInfo) { | ||
var nsCase = siteInfo.namespaces[result.namespace._id + ''].case; | ||
const nsCase = siteInfo.namespaces[`${result.namespace._id}`].case; | ||
if (nsCase === 'first-letter') { | ||
// This special casing is from core's `Language::ucfirst` | ||
// Grep for definitions in core/languages/classes/ | ||
if (result.title[0] === 'i' && (siteInfo.general.lang === 'az' | ||
|| siteInfo.general.lang === 'tr' | ||
|| siteInfo.general.lang === 'kaa' | ||
|| siteInfo.general.lang === 'kk')) { | ||
result.title = 'İ' + result.title.substr(1); | ||
if (result.title[0] === 'i' && (siteInfo.general.lang === 'az' || | ||
siteInfo.general.lang === 'tr' || | ||
siteInfo.general.lang === 'kaa' || | ||
siteInfo.general.lang === 'kk')) { | ||
result.title = `İ${result.title.substr(1)}`; | ||
} else if (!/^[A-Z]/.test(result.title)) { | ||
var firstCharacter = result.title.charAt(0); | ||
var upperCasedFirstLetter = phpCharToUpper(firstCharacter); | ||
const firstCharacter = result.title.charAt(0); | ||
const upperCasedFirstLetter = phpCharToUpper(firstCharacter); | ||
result.title = upperCasedFirstLetter + result.title.substr(1); | ||
@@ -239,7 +220,7 @@ } | ||
function _splitNamespace(title, siteInfo, defaultNs) { | ||
var prefixRegex = /^(.+?)_*:_*(.*)$/; | ||
var match = title.match(prefixRegex); | ||
const prefixRegex = /^(.+?)_*:_*(.*)$/; | ||
const match = title.match(prefixRegex); | ||
if (match) { | ||
var namespaceText = match[1]; | ||
var ns = Namespace.fromText(namespaceText, siteInfo); | ||
const namespaceText = match[1]; | ||
const ns = Namespace.fromText(namespaceText, siteInfo); | ||
if (ns !== undefined) { | ||
@@ -253,3 +234,3 @@ return { | ||
return { | ||
title: title, | ||
title, | ||
namespace: (defaultNs !== undefined) ? defaultNs : Namespace.main(siteInfo) | ||
@@ -260,7 +241,7 @@ }; | ||
function _checkLegalTitleCharacters(title, siteInfo) { | ||
var match = title.match(_createInvalidTitleRegex(siteInfo.general.legaltitlechars)); | ||
const match = title.match(_createInvalidTitleRegex(siteInfo.general.legaltitlechars)); | ||
if (match) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-characters', | ||
title: title, | ||
title, | ||
errors: match[0] | ||
@@ -276,3 +257,3 @@ }); | ||
type: 'title-invalid-empty', | ||
title: title | ||
title | ||
}); | ||
@@ -287,3 +268,3 @@ } | ||
if (title.indexOf('.') !== -1 && ( | ||
title === '.' || title === '..' || | ||
title === '.' || title === '..' || | ||
title.indexOf('./') === 0 || | ||
@@ -297,3 +278,3 @@ title.indexOf('../') === 0 || | ||
type: 'title-invalid-relative', | ||
title: title | ||
title | ||
}); | ||
@@ -305,7 +286,7 @@ } | ||
function _checkTalkNamespace(title, siteInfo) { | ||
var split = _splitNamespace(title, siteInfo); | ||
const split = _splitNamespace(title, siteInfo); | ||
if (split.namespace && !split.namespace.isMain()) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-talk-namespace', | ||
title: title | ||
title | ||
}); | ||
@@ -316,8 +297,8 @@ } | ||
function _checkMaxLength(title, namespace) { | ||
var maxLength = namespace.isSpecial() ? 512 : 256; | ||
if (title.length > maxLength) { | ||
const maxLength = namespace.isSpecial() ? 512 : 255; | ||
if (Buffer.byteLength(title, 'utf8') > maxLength) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-too-long', | ||
title: title, | ||
maxLength: maxLength | ||
title, | ||
maxLength | ||
}); | ||
@@ -328,8 +309,6 @@ } | ||
function _fixSpecialName(title, siteInfo) { | ||
var parts = title.split('/'); | ||
var first = parts[0].toUpperCase(); | ||
var alias = arrayFind(siteInfo.specialpagealiases || [], function(o) { | ||
return arrayFind(o.aliases, function(a) { | ||
return a.toUpperCase() === first; | ||
}) !== undefined; | ||
const parts = title.split('/'); | ||
const first = parts[0].toUpperCase(); | ||
const alias = (siteInfo.specialpagealiases || []).find((o) => { | ||
return o.aliases.find((a) => a.toUpperCase() === first) !== undefined; | ||
}); | ||
@@ -343,158 +322,156 @@ if (alias) { | ||
/** | ||
* Creates a new title object with article the dbKey and namespace | ||
* | ||
* @param {string} key The article title in a form of the dbKey. | ||
* @param {Namespace|number} namespace The article namespace. | ||
* @param {SiteInfo} siteInfo The site metadata. | ||
* @param {string} [fragment] The fragment of the title. | ||
* @constructor | ||
*/ | ||
function Title(key, namespace, siteInfo, fragment) { | ||
this._key = key; | ||
this._namespace = namespace.constructor.name === 'Namespace' ? | ||
namespace : new Namespace(namespace, siteInfo); | ||
this._siteInfo = siteInfo; | ||
this._fragment = fragment; | ||
} | ||
class Title { | ||
/** | ||
* Creates a new title object with article the dbKey and namespace | ||
* @param {string} key The article title in a form of the dbKey. | ||
* @param {Namespace|number} namespace The article namespace. | ||
* @param {SiteInfo} siteInfo The site metadata. | ||
* @param {string} [fragment] The fragment of the title. | ||
* @class | ||
*/ | ||
constructor(key, namespace, siteInfo, fragment) { | ||
this._key = key; | ||
if (namespace.constructor.name === 'Namespace') { | ||
this._namespace = namespace; | ||
} else { | ||
this._namespace = new Namespace(namespace, siteInfo); | ||
} | ||
this._siteInfo = siteInfo; | ||
this._fragment = fragment; | ||
} | ||
/** | ||
* Normalize a title according to the rules of <domain> | ||
* | ||
* @param {string} title The page title to normalize. | ||
* @param {SiteInfo} siteInfo The site information. | ||
* @param {Namespace|number} defaultNs A default namespace. | ||
* | ||
* @returns {Title} The resulting title object. | ||
*/ | ||
Title.newFromText = function(title, siteInfo, defaultNs) { | ||
if (typeof title !== 'string') { | ||
throw new TypeError('Invalid type of title parameter. Must be a string'); | ||
/** | ||
* Returns the normalized article title | ||
* @return {string} | ||
*/ | ||
getKey() { | ||
return this._key; | ||
} | ||
if (typeof siteInfo !== 'object') { | ||
throw new TypeError('Invalid type of siteInfo parameter. Must be a string'); | ||
/** | ||
* Returns the normalized article title and namespace. | ||
* @return {string} | ||
*/ | ||
getPrefixedDBKey() { | ||
let normalized = this._key; | ||
if (!this._namespace.isMain()) { | ||
normalized = `${this._namespace.getNormalizedText()}:${normalized}`; | ||
} | ||
return normalized; | ||
} | ||
title = title | ||
// Strip Unicode bidi override characters. | ||
.replace(/[\u200E\u200F\u202A-\u202E]/g, '') | ||
// Clean up whitespace | ||
.replace(/[ _\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/g, '_') | ||
// Trim _ from beginning and end | ||
.replace(/(?:^_+)|(?:_+$)/g, ''); | ||
/** | ||
* Get the full page name (transformed by #text) | ||
* | ||
* Example: "File:Example image.svg" for "File:Example_image.svg". | ||
* @return {string} | ||
*/ | ||
getPrefixedText() { | ||
return text(this.getPrefixedDBKey()); | ||
} | ||
if (title.indexOf(UTF_8_REPLACEMENT) !== -1) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-utf8', | ||
title: title | ||
}); | ||
/** | ||
* Returns the normalized fragment part of the original title | ||
* @return {string|undefined} | ||
*/ | ||
getFragment() { | ||
return this._fragment; | ||
} | ||
// Initial colon indicates main namespace rather than specified default | ||
// but should not create invalid {ns,title} pairs such as {0,Project:Foo} | ||
if (title !== '' && title[0] === ':') { | ||
title = title.substr(1).replace(/^_+/, ''); | ||
defaultNs = 0; | ||
/** | ||
* Returns the namespace of an article. | ||
* @return {Namespace} | ||
*/ | ||
getNamespace() { | ||
return this._namespace; | ||
} | ||
_checkEmptyTitle(title); | ||
/** | ||
* Normalize a title according to the rules of <domain> | ||
* @param {string} title The page title to normalize. | ||
* @param {SiteInfo} siteInfo The site information. | ||
* @param {Namespace|number} [defaultNs] A default namespace. | ||
* | ||
* @return {Title} The resulting title object. | ||
*/ | ||
static newFromText(title, siteInfo, defaultNs) { | ||
if (typeof title !== 'string') { | ||
throw new TypeError('Invalid type of title parameter. Must be a string'); | ||
} | ||
if (typeof siteInfo !== 'object') { | ||
throw new TypeError('Invalid type of siteInfo parameter. Must be an object'); | ||
} | ||
defaultNs = defaultNs === undefined ? defaultNs : | ||
defaultNs.constructor.name === 'Namespace' ? | ||
defaultNs : new Namespace(defaultNs, siteInfo); | ||
title = title | ||
// Strip Unicode bidi override characters. | ||
.replace(/[\u200E\u200F\u202A-\u202E]/g, '') | ||
// Clean up whitespace | ||
.replace(/[ _\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/g, '_') | ||
// Trim _ from beginning and end | ||
.replace(/(?:^_+)|(?:_+$)/g, ''); | ||
var result = _splitNamespace(title, siteInfo, defaultNs); | ||
if (result.namespace.isTalk()) { | ||
_checkTalkNamespace(result.title, siteInfo); | ||
} | ||
var fragmentIndex = result.title.indexOf('#'); | ||
if (fragmentIndex >= 0) { | ||
var fragment = result.title.substr(fragmentIndex); | ||
result.fragment = fragment.substr(1); | ||
result.title = result.title | ||
.substring(0, result.title.length - fragment.length) | ||
.replace(/_+$/, ''); | ||
} | ||
if (title.indexOf(UTF_8_REPLACEMENT) !== -1) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-utf8', | ||
title | ||
}); | ||
} | ||
_checkLegalTitleCharacters(result.title, siteInfo); | ||
_checkRelativeTitle(result.title); | ||
// Magic tilde sequences? Nu-uh! | ||
if (result.title.indexOf('~~~') !== -1) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-magic-tilde', | ||
title: title | ||
}); | ||
} | ||
_checkMaxLength(result.title, result.namespace); | ||
// Initial colon indicates main namespace rather than specified default | ||
// but should not create invalid {ns,title} pairs such as {0,Project:Foo} | ||
if (title !== '' && title[0] === ':') { | ||
title = title.substr(1).replace(/^_+/, ''); | ||
defaultNs = 0; | ||
} | ||
result = _capitalizeTitle(result, siteInfo); | ||
_checkEmptyTitle(title); | ||
if (!result.namespace.isMain()) { | ||
_checkEmptyTitle(result.title); | ||
} | ||
if (defaultNs !== undefined && defaultNs.constructor.name !== 'Namespace') { | ||
defaultNs = new Namespace(defaultNs, siteInfo); | ||
} | ||
if (result.namespace.isUser() || result.namespace.isUserTalk()) { | ||
result.title = sanitizeIP(result.title); | ||
} | ||
let result = _splitNamespace(title, siteInfo, defaultNs); | ||
if (result.namespace.isTalk()) { | ||
_checkTalkNamespace(result.title, siteInfo); | ||
} | ||
const fragmentIndex = result.title.indexOf('#'); | ||
if (fragmentIndex >= 0) { | ||
const fragment = result.title.substr(fragmentIndex); | ||
result.fragment = fragment.substr(1); | ||
result.title = result.title | ||
.substring(0, result.title.length - fragment.length) | ||
.replace(/_+$/, ''); | ||
} | ||
if (result.namespace.isSpecial()) { | ||
result.title = _fixSpecialName(result.title, siteInfo); | ||
} | ||
_checkLegalTitleCharacters(result.title, siteInfo); | ||
_checkRelativeTitle(result.title); | ||
// Magic tilde sequences? Nu-uh! | ||
if (result.title.indexOf('~~~') !== -1) { | ||
throw new utils.TitleError({ | ||
type: 'title-invalid-magic-tilde', | ||
title | ||
}); | ||
} | ||
_checkMaxLength(result.title, result.namespace); | ||
return new Title(result.title, result.namespace, siteInfo, result.fragment); | ||
}; | ||
result = _capitalizeTitle(result, siteInfo); | ||
/** | ||
* Returns the normalized article title | ||
* | ||
* @returns {string} | ||
*/ | ||
Title.prototype.getKey = function() { | ||
return this._key; | ||
}; | ||
if (!result.namespace.isMain()) { | ||
_checkEmptyTitle(result.title); | ||
} | ||
/** | ||
* Returns the normalized article title and namespace. | ||
* | ||
* @returns {string} | ||
*/ | ||
Title.prototype.getPrefixedDBKey = function() { | ||
var normalized = this._key; | ||
if (!this._namespace.isMain()) { | ||
normalized = this._namespace.getNormalizedText() + ':' + normalized; | ||
} | ||
return normalized; | ||
}; | ||
if (result.namespace.isUser() || result.namespace.isUserTalk()) { | ||
result.title = sanitizeIP(result.title); | ||
} | ||
/** | ||
* Get the full page name (transformed by #text) | ||
* | ||
* Example: "File:Example image.svg" for "File:Example_image.svg". | ||
* | ||
* @return {string} | ||
*/ | ||
Title.prototype.getPrefixedText = function() { | ||
return text(this.getPrefixedDBKey()); | ||
}; | ||
if (result.namespace.isSpecial()) { | ||
result.title = _fixSpecialName(result.title, siteInfo); | ||
} | ||
/** | ||
* Returns the normalized fragment part of the original title | ||
* | ||
* @returns {string|undefined} | ||
*/ | ||
Title.prototype.getFragment = function() { | ||
return this._fragment; | ||
}; | ||
return new Title(result.title, result.namespace, siteInfo, result.fragment); | ||
} | ||
} | ||
/** | ||
* Returns the namespace of an article. | ||
* | ||
* @returns {Namespace} | ||
*/ | ||
Title.prototype.getNamespace = function() { | ||
return this._namespace; | ||
}; | ||
module.exports = {}; | ||
module.exports.Namespace = Namespace; | ||
module.exports.Title = Title; |
@@ -1,2 +0,2 @@ | ||
"use strict"; | ||
'use strict'; | ||
@@ -10,6 +10,6 @@ function substrCount(string, substr) { | ||
} | ||
// jscs:disable maximumLineLength | ||
var IP_STRING_REGEX = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?(?:\/(12[0-8]|1[01][0-9]|[1-9]?\d))?$/; | ||
var IP_V4_STRING_REGEX = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])(?:\/(3[0-2]|[12]?\d))?$/; | ||
// jscs:enable maximumLineLength | ||
/* eslint-disable-next-line max-len */ | ||
const IP_STRING_REGEX = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?(?:\/(12[0-8]|1[01][0-9]|[1-9]?\d))?$/; | ||
/* eslint-disable-next-line max-len */ | ||
const IP_V4_STRING_REGEX = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])(?:\/(3[0-2]|[12]?\d))?$/; | ||
@@ -27,4 +27,4 @@ module.exports = function sanitizeIP(ip) { | ||
return ip.split('.') | ||
.map(function(block) { | ||
var simplified = block.replace(/^0+/, ''); | ||
.map((block) => { | ||
const simplified = block.replace(/^0+/, ''); | ||
if (!simplified.length) { | ||
@@ -39,11 +39,11 @@ return '0'; | ||
// Expand zero abbreviations | ||
var abbrevPos = ip.indexOf('::'); | ||
const abbrevPos = ip.indexOf('::'); | ||
if (abbrevPos !== -1) { | ||
// We know this is valid IPv6. Find the last index of the | ||
// address before any CIDR number (e.g. "a:b:c::/24"). | ||
var CIDRStart = ip.indexOf('/'); | ||
var addressEnd = CIDRStart !== -1 ? CIDRStart - 1 : ip.length - 1; | ||
var repeat; | ||
var extra; | ||
var pad; | ||
const CIDRStart = ip.indexOf('/'); | ||
const addressEnd = CIDRStart !== -1 ? CIDRStart - 1 : ip.length - 1; | ||
let repeat; | ||
let extra; | ||
let pad; | ||
if (abbrevPos === 0) { | ||
@@ -69,2 +69,2 @@ // If the '::' is at the beginning... | ||
return ip.replace(/(^|:)0+([0-9A-Fa-f]{1,4})/g, '$1$2'); | ||
}; | ||
}; |
@@ -1,255 +0,255 @@ | ||
// This file can't be parsed by JSDuck due to <https://github.com/tenderlove/rkelly/issues/35>. | ||
// (It is excluded in jsduck.json.) | ||
'use strict'; | ||
// ESLint suggests unquoting some object keys, which would render the file unparseable by Opera 12. | ||
/* eslint-disable quote-props */ | ||
( function () { | ||
var toUpperMapping = { | ||
'ß': 'ß', | ||
'ʼn': 'ʼn', | ||
'Dž': 'Dž', | ||
'dž': 'Dž', | ||
'Lj': 'Lj', | ||
'lj': 'Lj', | ||
'Nj': 'Nj', | ||
'nj': 'Nj', | ||
'ǰ': 'ǰ', | ||
'Dz': 'Dz', | ||
'dz': 'Dz', | ||
'ʝ': 'Ʝ', | ||
'ͅ': 'ͅ', | ||
'ΐ': 'ΐ', | ||
'ΰ': 'ΰ', | ||
'և': 'և', | ||
'ᏸ': 'Ᏸ', | ||
'ᏹ': 'Ᏹ', | ||
'ᏺ': 'Ᏺ', | ||
'ᏻ': 'Ᏻ', | ||
'ᏼ': 'Ᏼ', | ||
'ᏽ': 'Ᏽ', | ||
'ẖ': 'ẖ', | ||
'ẗ': 'ẗ', | ||
'ẘ': 'ẘ', | ||
'ẙ': 'ẙ', | ||
'ẚ': 'ẚ', | ||
'ὐ': 'ὐ', | ||
'ὒ': 'ὒ', | ||
'ὔ': 'ὔ', | ||
'ὖ': 'ὖ', | ||
'ᾀ': 'ᾈ', | ||
'ᾁ': 'ᾉ', | ||
'ᾂ': 'ᾊ', | ||
'ᾃ': 'ᾋ', | ||
'ᾄ': 'ᾌ', | ||
'ᾅ': 'ᾍ', | ||
'ᾆ': 'ᾎ', | ||
'ᾇ': 'ᾏ', | ||
'ᾈ': 'ᾈ', | ||
'ᾉ': 'ᾉ', | ||
'ᾊ': 'ᾊ', | ||
'ᾋ': 'ᾋ', | ||
'ᾌ': 'ᾌ', | ||
'ᾍ': 'ᾍ', | ||
'ᾎ': 'ᾎ', | ||
'ᾏ': 'ᾏ', | ||
'ᾐ': 'ᾘ', | ||
'ᾑ': 'ᾙ', | ||
'ᾒ': 'ᾚ', | ||
'ᾓ': 'ᾛ', | ||
'ᾔ': 'ᾜ', | ||
'ᾕ': 'ᾝ', | ||
'ᾖ': 'ᾞ', | ||
'ᾗ': 'ᾟ', | ||
'ᾘ': 'ᾘ', | ||
'ᾙ': 'ᾙ', | ||
'ᾚ': 'ᾚ', | ||
'ᾛ': 'ᾛ', | ||
'ᾜ': 'ᾜ', | ||
'ᾝ': 'ᾝ', | ||
'ᾞ': 'ᾞ', | ||
'ᾟ': 'ᾟ', | ||
'ᾠ': 'ᾨ', | ||
'ᾡ': 'ᾩ', | ||
'ᾢ': 'ᾪ', | ||
'ᾣ': 'ᾫ', | ||
'ᾤ': 'ᾬ', | ||
'ᾥ': 'ᾭ', | ||
'ᾦ': 'ᾮ', | ||
'ᾧ': 'ᾯ', | ||
'ᾨ': 'ᾨ', | ||
'ᾩ': 'ᾩ', | ||
'ᾪ': 'ᾪ', | ||
'ᾫ': 'ᾫ', | ||
'ᾬ': 'ᾬ', | ||
'ᾭ': 'ᾭ', | ||
'ᾮ': 'ᾮ', | ||
'ᾯ': 'ᾯ', | ||
'ᾲ': 'ᾲ', | ||
'ᾳ': 'ᾼ', | ||
'ᾴ': 'ᾴ', | ||
'ᾶ': 'ᾶ', | ||
'ᾷ': 'ᾷ', | ||
'ᾼ': 'ᾼ', | ||
'ῂ': 'ῂ', | ||
'ῃ': 'ῌ', | ||
'ῄ': 'ῄ', | ||
'ῆ': 'ῆ', | ||
'ῇ': 'ῇ', | ||
'ῌ': 'ῌ', | ||
'ῒ': 'ῒ', | ||
'ΐ': 'ΐ', | ||
'ῖ': 'ῖ', | ||
'ῗ': 'ῗ', | ||
'ῢ': 'ῢ', | ||
'ΰ': 'ΰ', | ||
'ῤ': 'ῤ', | ||
'ῦ': 'ῦ', | ||
'ῧ': 'ῧ', | ||
'ῲ': 'ῲ', | ||
'ῳ': 'ῼ', | ||
'ῴ': 'ῴ', | ||
'ῶ': 'ῶ', | ||
'ῷ': 'ῷ', | ||
'ῼ': 'ῼ', | ||
'ⅰ': 'ⅰ', | ||
'ⅱ': 'ⅱ', | ||
'ⅲ': 'ⅲ', | ||
'ⅳ': 'ⅳ', | ||
'ⅴ': 'ⅴ', | ||
'ⅵ': 'ⅵ', | ||
'ⅶ': 'ⅶ', | ||
'ⅷ': 'ⅷ', | ||
'ⅸ': 'ⅸ', | ||
'ⅹ': 'ⅹ', | ||
'ⅺ': 'ⅺ', | ||
'ⅻ': 'ⅻ', | ||
'ⅼ': 'ⅼ', | ||
'ⅽ': 'ⅽ', | ||
'ⅾ': 'ⅾ', | ||
'ⅿ': 'ⅿ', | ||
'ⓐ': 'ⓐ', | ||
'ⓑ': 'ⓑ', | ||
'ⓒ': 'ⓒ', | ||
'ⓓ': 'ⓓ', | ||
'ⓔ': 'ⓔ', | ||
'ⓕ': 'ⓕ', | ||
'ⓖ': 'ⓖ', | ||
'ⓗ': 'ⓗ', | ||
'ⓘ': 'ⓘ', | ||
'ⓙ': 'ⓙ', | ||
'ⓚ': 'ⓚ', | ||
'ⓛ': 'ⓛ', | ||
'ⓜ': 'ⓜ', | ||
'ⓝ': 'ⓝ', | ||
'ⓞ': 'ⓞ', | ||
'ⓟ': 'ⓟ', | ||
'ⓠ': 'ⓠ', | ||
'ⓡ': 'ⓡ', | ||
'ⓢ': 'ⓢ', | ||
'ⓣ': 'ⓣ', | ||
'ⓤ': 'ⓤ', | ||
'ⓥ': 'ⓥ', | ||
'ⓦ': 'ⓦ', | ||
'ⓧ': 'ⓧ', | ||
'ⓨ': 'ⓨ', | ||
'ⓩ': 'ⓩ', | ||
'ꞵ': 'Ꞵ', | ||
'ꞷ': 'Ꞷ', | ||
'ꭓ': 'Ꭓ', | ||
'ꭰ': 'Ꭰ', | ||
'ꭱ': 'Ꭱ', | ||
'ꭲ': 'Ꭲ', | ||
'ꭳ': 'Ꭳ', | ||
'ꭴ': 'Ꭴ', | ||
'ꭵ': 'Ꭵ', | ||
'ꭶ': 'Ꭶ', | ||
'ꭷ': 'Ꭷ', | ||
'ꭸ': 'Ꭸ', | ||
'ꭹ': 'Ꭹ', | ||
'ꭺ': 'Ꭺ', | ||
'ꭻ': 'Ꭻ', | ||
'ꭼ': 'Ꭼ', | ||
'ꭽ': 'Ꭽ', | ||
'ꭾ': 'Ꭾ', | ||
'ꭿ': 'Ꭿ', | ||
'ꮀ': 'Ꮀ', | ||
'ꮁ': 'Ꮁ', | ||
'ꮂ': 'Ꮂ', | ||
'ꮃ': 'Ꮃ', | ||
'ꮄ': 'Ꮄ', | ||
'ꮅ': 'Ꮅ', | ||
'ꮆ': 'Ꮆ', | ||
'ꮇ': 'Ꮇ', | ||
'ꮈ': 'Ꮈ', | ||
'ꮉ': 'Ꮉ', | ||
'ꮊ': 'Ꮊ', | ||
'ꮋ': 'Ꮋ', | ||
'ꮌ': 'Ꮌ', | ||
'ꮍ': 'Ꮍ', | ||
'ꮎ': 'Ꮎ', | ||
'ꮏ': 'Ꮏ', | ||
'ꮐ': 'Ꮐ', | ||
'ꮑ': 'Ꮑ', | ||
'ꮒ': 'Ꮒ', | ||
'ꮓ': 'Ꮓ', | ||
'ꮔ': 'Ꮔ', | ||
'ꮕ': 'Ꮕ', | ||
'ꮖ': 'Ꮖ', | ||
'ꮗ': 'Ꮗ', | ||
'ꮘ': 'Ꮘ', | ||
'ꮙ': 'Ꮙ', | ||
'ꮚ': 'Ꮚ', | ||
'ꮛ': 'Ꮛ', | ||
'ꮜ': 'Ꮜ', | ||
'ꮝ': 'Ꮝ', | ||
'ꮞ': 'Ꮞ', | ||
'ꮟ': 'Ꮟ', | ||
'ꮠ': 'Ꮠ', | ||
'ꮡ': 'Ꮡ', | ||
'ꮢ': 'Ꮢ', | ||
'ꮣ': 'Ꮣ', | ||
'ꮤ': 'Ꮤ', | ||
'ꮥ': 'Ꮥ', | ||
'ꮦ': 'Ꮦ', | ||
'ꮧ': 'Ꮧ', | ||
'ꮨ': 'Ꮨ', | ||
'ꮩ': 'Ꮩ', | ||
'ꮪ': 'Ꮪ', | ||
'ꮫ': 'Ꮫ', | ||
'ꮬ': 'Ꮬ', | ||
'ꮭ': 'Ꮭ', | ||
'ꮮ': 'Ꮮ', | ||
'ꮯ': 'Ꮯ', | ||
'ꮰ': 'Ꮰ', | ||
'ꮱ': 'Ꮱ', | ||
'ꮲ': 'Ꮲ', | ||
'ꮳ': 'Ꮳ', | ||
'ꮴ': 'Ꮴ', | ||
'ꮵ': 'Ꮵ', | ||
'ꮶ': 'Ꮶ', | ||
'ꮷ': 'Ꮷ', | ||
'ꮸ': 'Ꮸ', | ||
'ꮹ': 'Ꮹ', | ||
'ꮺ': 'Ꮺ', | ||
'ꮻ': 'Ꮻ', | ||
'ꮼ': 'Ꮼ', | ||
'ꮽ': 'Ꮽ', | ||
'ꮾ': 'Ꮾ', | ||
'ꮿ': 'Ꮿ', | ||
'ff': 'ff', | ||
'fi': 'fi', | ||
'fl': 'fl', | ||
'ffi': 'ffi', | ||
'ffl': 'ffl', | ||
'ſt': 'ſt', | ||
'st': 'st', | ||
'ﬓ': 'ﬓ', | ||
'ﬔ': 'ﬔ', | ||
'ﬕ': 'ﬕ', | ||
'ﬖ': 'ﬖ', | ||
'ﬗ': 'ﬗ' | ||
}; | ||
module.exports = function ( chr ) { | ||
var mapped = toUpperMapping[ chr ]; | ||
return mapped || chr.toUpperCase(); | ||
}; | ||
}() ); | ||
(function () { | ||
const toUpperMapping = { | ||
'ß': 'ß', | ||
'ʼn': 'ʼn', | ||
'Dž': 'Dž', | ||
'dž': 'Dž', | ||
'Lj': 'Lj', | ||
'lj': 'Lj', | ||
'Nj': 'Nj', | ||
'nj': 'Nj', | ||
'ǰ': 'ǰ', | ||
'Dz': 'Dz', | ||
'dz': 'Dz', | ||
'ʝ': 'Ʝ', | ||
'ͅ': 'ͅ', | ||
'ΐ': 'ΐ', | ||
'ΰ': 'ΰ', | ||
'և': 'և', | ||
'ᏸ': 'Ᏸ', | ||
'ᏹ': 'Ᏹ', | ||
'ᏺ': 'Ᏺ', | ||
'ᏻ': 'Ᏻ', | ||
'ᏼ': 'Ᏼ', | ||
'ᏽ': 'Ᏽ', | ||
'ẖ': 'ẖ', | ||
'ẗ': 'ẗ', | ||
'ẘ': 'ẘ', | ||
'ẙ': 'ẙ', | ||
'ẚ': 'ẚ', | ||
'ὐ': 'ὐ', | ||
'ὒ': 'ὒ', | ||
'ὔ': 'ὔ', | ||
'ὖ': 'ὖ', | ||
'ᾀ': 'ᾈ', | ||
'ᾁ': 'ᾉ', | ||
'ᾂ': 'ᾊ', | ||
'ᾃ': 'ᾋ', | ||
'ᾄ': 'ᾌ', | ||
'ᾅ': 'ᾍ', | ||
'ᾆ': 'ᾎ', | ||
'ᾇ': 'ᾏ', | ||
'ᾈ': 'ᾈ', | ||
'ᾉ': 'ᾉ', | ||
'ᾊ': 'ᾊ', | ||
'ᾋ': 'ᾋ', | ||
'ᾌ': 'ᾌ', | ||
'ᾍ': 'ᾍ', | ||
'ᾎ': 'ᾎ', | ||
'ᾏ': 'ᾏ', | ||
'ᾐ': 'ᾘ', | ||
'ᾑ': 'ᾙ', | ||
'ᾒ': 'ᾚ', | ||
'ᾓ': 'ᾛ', | ||
'ᾔ': 'ᾜ', | ||
'ᾕ': 'ᾝ', | ||
'ᾖ': 'ᾞ', | ||
'ᾗ': 'ᾟ', | ||
'ᾘ': 'ᾘ', | ||
'ᾙ': 'ᾙ', | ||
'ᾚ': 'ᾚ', | ||
'ᾛ': 'ᾛ', | ||
'ᾜ': 'ᾜ', | ||
'ᾝ': 'ᾝ', | ||
'ᾞ': 'ᾞ', | ||
'ᾟ': 'ᾟ', | ||
'ᾠ': 'ᾨ', | ||
'ᾡ': 'ᾩ', | ||
'ᾢ': 'ᾪ', | ||
'ᾣ': 'ᾫ', | ||
'ᾤ': 'ᾬ', | ||
'ᾥ': 'ᾭ', | ||
'ᾦ': 'ᾮ', | ||
'ᾧ': 'ᾯ', | ||
'ᾨ': 'ᾨ', | ||
'ᾩ': 'ᾩ', | ||
'ᾪ': 'ᾪ', | ||
'ᾫ': 'ᾫ', | ||
'ᾬ': 'ᾬ', | ||
'ᾭ': 'ᾭ', | ||
'ᾮ': 'ᾮ', | ||
'ᾯ': 'ᾯ', | ||
'ᾲ': 'ᾲ', | ||
'ᾳ': 'ᾼ', | ||
'ᾴ': 'ᾴ', | ||
'ᾶ': 'ᾶ', | ||
'ᾷ': 'ᾷ', | ||
'ᾼ': 'ᾼ', | ||
'ῂ': 'ῂ', | ||
'ῃ': 'ῌ', | ||
'ῄ': 'ῄ', | ||
'ῆ': 'ῆ', | ||
'ῇ': 'ῇ', | ||
'ῌ': 'ῌ', | ||
'ῒ': 'ῒ', | ||
'ΐ': 'ΐ', | ||
'ῖ': 'ῖ', | ||
'ῗ': 'ῗ', | ||
'ῢ': 'ῢ', | ||
'ΰ': 'ΰ', | ||
'ῤ': 'ῤ', | ||
'ῦ': 'ῦ', | ||
'ῧ': 'ῧ', | ||
'ῲ': 'ῲ', | ||
'ῳ': 'ῼ', | ||
'ῴ': 'ῴ', | ||
'ῶ': 'ῶ', | ||
'ῷ': 'ῷ', | ||
'ῼ': 'ῼ', | ||
'ⅰ': 'ⅰ', | ||
'ⅱ': 'ⅱ', | ||
'ⅲ': 'ⅲ', | ||
'ⅳ': 'ⅳ', | ||
'ⅴ': 'ⅴ', | ||
'ⅵ': 'ⅵ', | ||
'ⅶ': 'ⅶ', | ||
'ⅷ': 'ⅷ', | ||
'ⅸ': 'ⅸ', | ||
'ⅹ': 'ⅹ', | ||
'ⅺ': 'ⅺ', | ||
'ⅻ': 'ⅻ', | ||
'ⅼ': 'ⅼ', | ||
'ⅽ': 'ⅽ', | ||
'ⅾ': 'ⅾ', | ||
'ⅿ': 'ⅿ', | ||
'ⓐ': 'ⓐ', | ||
'ⓑ': 'ⓑ', | ||
'ⓒ': 'ⓒ', | ||
'ⓓ': 'ⓓ', | ||
'ⓔ': 'ⓔ', | ||
'ⓕ': 'ⓕ', | ||
'ⓖ': 'ⓖ', | ||
'ⓗ': 'ⓗ', | ||
'ⓘ': 'ⓘ', | ||
'ⓙ': 'ⓙ', | ||
'ⓚ': 'ⓚ', | ||
'ⓛ': 'ⓛ', | ||
'ⓜ': 'ⓜ', | ||
'ⓝ': 'ⓝ', | ||
'ⓞ': 'ⓞ', | ||
'ⓟ': 'ⓟ', | ||
'ⓠ': 'ⓠ', | ||
'ⓡ': 'ⓡ', | ||
'ⓢ': 'ⓢ', | ||
'ⓣ': 'ⓣ', | ||
'ⓤ': 'ⓤ', | ||
'ⓥ': 'ⓥ', | ||
'ⓦ': 'ⓦ', | ||
'ⓧ': 'ⓧ', | ||
'ⓨ': 'ⓨ', | ||
'ⓩ': 'ⓩ', | ||
'ꞵ': 'Ꞵ', | ||
'ꞷ': 'Ꞷ', | ||
'ꭓ': 'Ꭓ', | ||
'ꭰ': 'Ꭰ', | ||
'ꭱ': 'Ꭱ', | ||
'ꭲ': 'Ꭲ', | ||
'ꭳ': 'Ꭳ', | ||
'ꭴ': 'Ꭴ', | ||
'ꭵ': 'Ꭵ', | ||
'ꭶ': 'Ꭶ', | ||
'ꭷ': 'Ꭷ', | ||
'ꭸ': 'Ꭸ', | ||
'ꭹ': 'Ꭹ', | ||
'ꭺ': 'Ꭺ', | ||
'ꭻ': 'Ꭻ', | ||
'ꭼ': 'Ꭼ', | ||
'ꭽ': 'Ꭽ', | ||
'ꭾ': 'Ꭾ', | ||
'ꭿ': 'Ꭿ', | ||
'ꮀ': 'Ꮀ', | ||
'ꮁ': 'Ꮁ', | ||
'ꮂ': 'Ꮂ', | ||
'ꮃ': 'Ꮃ', | ||
'ꮄ': 'Ꮄ', | ||
'ꮅ': 'Ꮅ', | ||
'ꮆ': 'Ꮆ', | ||
'ꮇ': 'Ꮇ', | ||
'ꮈ': 'Ꮈ', | ||
'ꮉ': 'Ꮉ', | ||
'ꮊ': 'Ꮊ', | ||
'ꮋ': 'Ꮋ', | ||
'ꮌ': 'Ꮌ', | ||
'ꮍ': 'Ꮍ', | ||
'ꮎ': 'Ꮎ', | ||
'ꮏ': 'Ꮏ', | ||
'ꮐ': 'Ꮐ', | ||
'ꮑ': 'Ꮑ', | ||
'ꮒ': 'Ꮒ', | ||
'ꮓ': 'Ꮓ', | ||
'ꮔ': 'Ꮔ', | ||
'ꮕ': 'Ꮕ', | ||
'ꮖ': 'Ꮖ', | ||
'ꮗ': 'Ꮗ', | ||
'ꮘ': 'Ꮘ', | ||
'ꮙ': 'Ꮙ', | ||
'ꮚ': 'Ꮚ', | ||
'ꮛ': 'Ꮛ', | ||
'ꮜ': 'Ꮜ', | ||
'ꮝ': 'Ꮝ', | ||
'ꮞ': 'Ꮞ', | ||
'ꮟ': 'Ꮟ', | ||
'ꮠ': 'Ꮠ', | ||
'ꮡ': 'Ꮡ', | ||
'ꮢ': 'Ꮢ', | ||
'ꮣ': 'Ꮣ', | ||
'ꮤ': 'Ꮤ', | ||
'ꮥ': 'Ꮥ', | ||
'ꮦ': 'Ꮦ', | ||
'ꮧ': 'Ꮧ', | ||
'ꮨ': 'Ꮨ', | ||
'ꮩ': 'Ꮩ', | ||
'ꮪ': 'Ꮪ', | ||
'ꮫ': 'Ꮫ', | ||
'ꮬ': 'Ꮬ', | ||
'ꮭ': 'Ꮭ', | ||
'ꮮ': 'Ꮮ', | ||
'ꮯ': 'Ꮯ', | ||
'ꮰ': 'Ꮰ', | ||
'ꮱ': 'Ꮱ', | ||
'ꮲ': 'Ꮲ', | ||
'ꮳ': 'Ꮳ', | ||
'ꮴ': 'Ꮴ', | ||
'ꮵ': 'Ꮵ', | ||
'ꮶ': 'Ꮶ', | ||
'ꮷ': 'Ꮷ', | ||
'ꮸ': 'Ꮸ', | ||
'ꮹ': 'Ꮹ', | ||
'ꮺ': 'Ꮺ', | ||
'ꮻ': 'Ꮻ', | ||
'ꮼ': 'Ꮼ', | ||
'ꮽ': 'Ꮽ', | ||
'ꮾ': 'Ꮾ', | ||
'ꮿ': 'Ꮿ', | ||
'ff': 'ff', | ||
'fi': 'fi', | ||
'fl': 'fl', | ||
'ffi': 'ffi', | ||
'ffl': 'ffl', | ||
'ſt': 'ſt', | ||
'st': 'st', | ||
'ﬓ': 'ﬓ', | ||
'ﬔ': 'ﬔ', | ||
'ﬕ': 'ﬕ', | ||
'ﬖ': 'ﬖ', | ||
'ﬗ': 'ﬗ' | ||
}; | ||
module.exports = (chr) => { | ||
const mapped = toUpperMapping[chr]; | ||
return mapped || chr.toUpperCase(); | ||
}; | ||
}()); |
@@ -1,5 +0,3 @@ | ||
"use strict"; | ||
'use strict'; | ||
var util = require('util'); | ||
module.exports = {}; | ||
@@ -14,34 +12,29 @@ | ||
* Direct port of the mediawiki code | ||
* | ||
* @param {string} byteClass | ||
* @return {string} | ||
*/ | ||
module.exports.convertByteClassToUnicodeClass = function(byteClass) { | ||
var length = byteClass.length; | ||
module.exports.convertByteClassToUnicodeClass = (byteClass) => { | ||
const length = byteClass.length; | ||
// Input token queue | ||
var x0 = ''; | ||
var x1 = ''; | ||
var x2 = ''; | ||
let x0 = ''; | ||
let x1 = ''; | ||
let x2 = ''; | ||
// Decoded queue | ||
var d0 = ''; | ||
var d1 = ''; | ||
var d2 = ''; | ||
let d0 = ''; | ||
// Decoded integer codepoints | ||
var ord0 = 0; | ||
var ord1 = 0; | ||
var ord2 = 0; | ||
let ord0 = 0; | ||
let ord1 = 0; | ||
let ord2 = 0; | ||
// Re-encoded queue | ||
var r0 = ''; | ||
var r1 = ''; | ||
var r2 = ''; | ||
let r0 = ''; | ||
let r1 = ''; | ||
let r2 = ''; | ||
// Output | ||
var out = ''; | ||
let out = ''; | ||
// Flags | ||
var allowUnicode = false; | ||
for (var pos = 0; pos < length; pos++) { | ||
let allowUnicode = false; | ||
for (let pos = 0; pos < length; pos++) { | ||
// Shift the queues down | ||
x2 = x1; | ||
x1 = x0; | ||
d2 = d1; | ||
d1 = d0; | ||
ord2 = ord1; | ||
@@ -52,10 +45,10 @@ ord1 = ord0; | ||
// Load the current input token and decoded values | ||
var inChar = byteClass[pos]; | ||
const inChar = byteClass[pos]; | ||
if (inChar === '\\') { | ||
var m; | ||
if (!!(m = byteClass.substr(pos + 1).match(/^x([0-9a-fA-F]{2})/))) { | ||
let m; | ||
if ((m = byteClass.substr(pos + 1).match(/^x([0-9a-fA-F]{2})/))) { | ||
x0 = inChar + m[0]; | ||
d0 = String.fromCharCode(parseInt(m[1], 16)); | ||
pos += m[0].length; | ||
} else if (!!(m = byteClass.substr(pos + 1).match(/^[0-7]{3}/))) { | ||
} else if ((m = byteClass.substr(pos + 1).match(/^[0-7]{3}/))) { | ||
x0 = inChar + m[0]; | ||
@@ -77,9 +70,9 @@ d0 = String.fromCharCode(parseInt(m[0], 8)); | ||
if (ord0 < 32 || ord0 === 0x7f) { | ||
r0 = '\\x%' + ord0.toString(16); | ||
r0 = `\\x%${ord0.toString(16)}`; | ||
} else if (ord0 >= 0x80) { | ||
// Allow unicode if a single high-bit character appears | ||
r0 = '\\x%' + ord0.toString(16); | ||
r0 = `\\x%${ord0.toString(16)}`; | ||
allowUnicode = true; | ||
} else if ('-\\[]^'.indexOf(d0) !== -1) { | ||
r0 = '\\' + d0; | ||
r0 = `\\${d0}`; | ||
} else { | ||
@@ -97,11 +90,11 @@ r0 = d0; | ||
// Keep the non-unicode section of the range | ||
out += r2 + '-\\x7F'; | ||
out += `${r2}-\\x7F`; | ||
} | ||
} else { | ||
// Normal range | ||
out += r2 + '-' + r0; | ||
out += `${r2}-${r0}`; | ||
} | ||
} | ||
// Reset state to the initial value | ||
x0 = x1 = d0 = d1 = r0 = r1 = ''; | ||
x0 = x1 = d0 = r0 = r1 = ''; | ||
} else if (ord2 < 0x80) { | ||
@@ -124,13 +117,13 @@ // ASCII character | ||
function TitleError(options) { | ||
var self = this; | ||
Error.call(self); | ||
Error.captureStackTrace(self, TitleError); | ||
self.name = self.constructor.name; | ||
self.message = options.type; | ||
Object.keys(options).forEach(function(option) { | ||
self[option] = options[option]; | ||
}); | ||
class TitleError extends Error { | ||
constructor(options) { | ||
super(); | ||
Error.captureStackTrace(this, TitleError); | ||
this.name = this.constructor.name; | ||
this.message = options.type; | ||
Object.keys(options).forEach((option) => { | ||
this[option] = options[option]; | ||
}); | ||
} | ||
} | ||
util.inherits(TitleError, Error); | ||
module.exports.TitleError = TitleError; |
{ | ||
"name": "mediawiki-title", | ||
"version": "0.6.5", | ||
"version": "0.7.1", | ||
"description": "Title normalization library for mediawiki", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "mocha", | ||
"coverage": "istanbul cover _mocha -- -R spec", | ||
"test": "npm run lint && mocha", | ||
"lint": "eslint --max-warnings 0 --ext .js --ext .json .", | ||
"coverage": "nyc --reporter=lcov _mocha", | ||
"coveralls": "cat ./coverage/lcov.info | coveralls" | ||
@@ -27,10 +28,11 @@ }, | ||
"devDependencies": { | ||
"coveralls": "^2.11.6", | ||
"istanbul": "^0.4.2", | ||
"mocha": "^2.3.4", | ||
"mocha-jscs": "^4.0.0", | ||
"mocha-jshint": "^2.2.6", | ||
"mocha-lcov-reporter": "^1.0.0", | ||
"preq": "^0.4.8" | ||
"coveralls": "^3.0.2", | ||
"eslint-config-wikimedia": "^0.10.1", | ||
"eslint-plugin-jsdoc": "^4.1.0", | ||
"eslint-plugin-json": "^1.4.0", | ||
"mocha": "^5.2.0", | ||
"mocha-lcov-reporter": "^1.3.0", | ||
"nyc": "^13.3.0", | ||
"preq": "^0.5.7" | ||
} | ||
} |
'use strict'; | ||
var assert = require('assert'); | ||
var Title = require('../lib/index').Title; | ||
var utils = require('../lib/utils'); | ||
var preq = require('preq'); | ||
const assert = require('assert'); | ||
const Title = require('../lib/index').Title; | ||
const utils = require('../lib/utils'); | ||
const preq = require('preq'); | ||
// Run jshint as part of normal testing | ||
require('mocha-jshint')(); | ||
// Run jscs as part of normal testing | ||
require('mocha-jscs')(); | ||
function doTest(formatversion) { | ||
var siteInfoCache = {}; | ||
var getSiteInfo = function(domain) { | ||
const doTest = (formatversion) => { | ||
const siteInfoCache = {}; | ||
const getSiteInfo = (domain) => { | ||
if (siteInfoCache[domain]) { | ||
@@ -21,3 +16,3 @@ return siteInfoCache[domain]; | ||
siteInfoCache[domain] = preq.post({ | ||
uri: 'https://' + domain + '/w/api.php', | ||
uri: `https://${domain}/w/api.php`, | ||
body: { | ||
@@ -28,13 +23,11 @@ action: 'query', | ||
format: 'json', | ||
formatversion: formatversion | ||
formatversion | ||
} | ||
}) | ||
.then(function(res) { | ||
return res.body.query; | ||
}); | ||
.then((res) => res.body.query); | ||
return siteInfoCache[domain]; | ||
}; | ||
describe('Validation', function () { | ||
var invalidTitles = [ | ||
describe('Validation', () => { | ||
const invalidTitles = [ | ||
['foo�', 'title-invalid-utf8'], | ||
@@ -79,4 +72,5 @@ ['', 'title-invalid-empty'], | ||
// Length | ||
[ new Array(258).join('x'), 'title-invalid-too-long' ], | ||
[ 'Special:' + new Array(514).join('x'), 'title-invalid-too-long' ], | ||
[new Array(258).join('x'), 'title-invalid-too-long'], | ||
[`Special:${new Array(514).join('x')}`, 'title-invalid-too-long'], | ||
[new Array(65).join('\ud83c\udf40'), 'title-invalid-too-long'], | ||
// Namespace prefix without actual title | ||
@@ -88,61 +82,56 @@ ['Talk:', 'title-invalid-empty'], | ||
invalidTitles.forEach(function(testCase) { | ||
var name = testCase[0]; | ||
invalidTitles.forEach((testCase) => { | ||
let name = testCase[0]; | ||
if (name.length > 20) { | ||
name = testCase[0].substr(0, 20) + '...' | ||
name = `${testCase[0].substr(0, 20)}...`; | ||
} | ||
it('should throw ' + testCase[1] + ' error for ' + name, function() { | ||
it(`should throw ${testCase[1]} error for ${name}`, () => { | ||
return getSiteInfo('en.wikipedia.org') | ||
.then(function(siteInfo) { | ||
return Title.newFromText(testCase[0], siteInfo); | ||
}) | ||
.then(function () { | ||
.then((siteInfo) => Title.newFromText(testCase[0], siteInfo)) | ||
.then(() => { | ||
throw new Error('Error should be thrown'); | ||
}, function (e) { | ||
assert.deepEqual(e.message, testCase[1]); | ||
}); | ||
}, (e) => assert.deepEqual(e.message, testCase[1])); | ||
}); | ||
}); | ||
var validTitles = [ | ||
[ 'Sandbox' ], | ||
[ 'A "B"' ], | ||
[ 'A \'B\'' ], | ||
[ '.com' ], | ||
[ '~' ], | ||
[ '#' ], | ||
[ 'Test#Abc' ], | ||
[ '"' ], | ||
[ '\'' ], | ||
[ 'Talk:Sandbox' ], | ||
[ 'Talk:Foo:Sandbox' ], | ||
[ 'File:Example.svg' ], | ||
[ 'File_talk:Example.svg' ], | ||
[ 'Foo/.../Sandbox' ], | ||
[ 'Sandbox/...' ], | ||
[ 'A~~' ], | ||
[ ':A' ], | ||
const validTitles = [ | ||
['Sandbox'], | ||
['A "B"'], | ||
['A \'B\''], | ||
['.com'], | ||
['~'], | ||
['#'], | ||
['Test#Abc'], | ||
['"'], | ||
['\''], | ||
['Talk:Sandbox'], | ||
['Talk:Foo:Sandbox'], | ||
['File:Example.svg'], | ||
['File_talk:Example.svg'], | ||
['Foo/.../Sandbox'], | ||
['Sandbox/...'], | ||
['A~~'], | ||
[':A'], | ||
// Length is 256 total, but only title part matters | ||
[ 'Category:' + new Array(248).join('x') ], | ||
[`Category:${new Array(248).join('x')}`], | ||
// Special pages can have longer titles | ||
[ 'Special:' + new Array(500).join('x') ], | ||
[ new Array(252).join('x') ], | ||
[ new Array(257).join('x') ], | ||
[ '-' ], | ||
[ 'aũ' ], | ||
[ '"Believing_Women"_in_Islam._Unreading_Patriarchal_Interpretations_of_the_Qur\\\'ān'] | ||
[`Special:${new Array(500).join('x')}`], | ||
[new Array(252).join('x')], | ||
[new Array(256).join('x')], | ||
[new Array(64).join('\ud83c\udf40')], | ||
['-'], | ||
['aũ'], | ||
['"Believing_Women"_in_Islam._Unreading_Patriarchal_Interpretations_of_the_Qur\\\'ān'] | ||
]; | ||
validTitles.forEach(function(title) { | ||
var name = title[0]; | ||
validTitles.forEach((title) => { | ||
let name = title[0]; | ||
if (name.length > 20) { | ||
name = title[0].substr(0, 20) + '...' | ||
name = `${title[0].substr(0, 20)}...`; | ||
} | ||
it(name + ' should be valid', function() { | ||
it(`${name} should be valid`, () => { | ||
return getSiteInfo('en.wikipedia.org') | ||
.then(function(siteInfo) { | ||
return Title.newFromText(title[0], siteInfo); | ||
}) | ||
.then((siteInfo) => Title.newFromText(title[0], siteInfo)); | ||
}); | ||
@@ -152,170 +141,163 @@ }); | ||
describe('Normalization', function() { | ||
var testCases = [ | ||
[ 'en.wikipedia.org', 'Test', 'Test'], | ||
[ 'en.wikipedia.org', ':Test', 'Test'], | ||
[ 'en.wikipedia.org', ': Test', 'Test'], | ||
[ 'en.wikipedia.org', ':_Test_', 'Test'], | ||
[ 'en.wikipedia.org', 'Test 123 456 789', 'Test_123_456_789' ], | ||
[ 'en.wikipedia.org', '💩', '💩'], | ||
[ 'en.wikipedia.org', 'Foo:bar', 'Foo:bar'], | ||
[ 'en.wikipedia.org', 'Talk: foo', 'Talk:Foo'], | ||
[ 'en.wikipedia.org', 'int:eger', 'Int:eger'], | ||
[ 'en.wikipedia.org', 'WP:eger', 'Wikipedia:Eger'], | ||
[ 'en.wikipedia.org', 'X-Men (film series) #Gambit', 'X-Men_(film_series)' ], | ||
[ 'en.wikipedia.org', 'Foo _ bar', 'Foo_bar' ], | ||
[ 'en.wikipedia.org', 'Foo \u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000 bar', 'Foo_bar' ], | ||
[ 'en.wikipedia.org', 'Foo\u200E\u200F\u202A\u202B\u202C\u202D\u202Ebar', 'Foobar' ], | ||
describe('Normalization', () => { | ||
const testCases = [ | ||
['en.wikipedia.org', 'Test', 'Test'], | ||
['en.wikipedia.org', ':Test', 'Test'], | ||
['en.wikipedia.org', ': Test', 'Test'], | ||
['en.wikipedia.org', ':_Test_', 'Test'], | ||
['en.wikipedia.org', 'Test 123 456 789', 'Test_123_456_789'], | ||
['en.wikipedia.org', '💩', '💩'], | ||
['en.wikipedia.org', 'Foo:bar', 'Foo:bar'], | ||
['en.wikipedia.org', 'Talk: foo', 'Talk:Foo'], | ||
['en.wikipedia.org', 'int:eger', 'Int:eger'], | ||
['en.wikipedia.org', 'WP:eger', 'Wikipedia:Eger'], | ||
['en.wikipedia.org', 'X-Men (film series) #Gambit', 'X-Men_(film_series)'], | ||
['en.wikipedia.org', 'Foo _ bar', 'Foo_bar'], | ||
['en.wiktionary.org', 'cat', 'cat'], | ||
['en.wiktionary.org', 'Appendix:Glossary', 'Appendix:Glossary'], | ||
// eslint-disable-next-line max-len | ||
['en.wikipedia.org', 'Foo \u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000 bar', 'Foo_bar'], | ||
['en.wikipedia.org', 'Foo\u200E\u200F\u202A\u202B\u202C\u202D\u202Ebar', 'Foobar'], | ||
// Special handling for `i` first character | ||
[ 'tr.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
[ 'az.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
[ 'kk.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
[ 'kaa.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
['tr.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
['az.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
['kk.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
['kaa.wikipedia.org', 'iTestTest', 'İTestTest'], | ||
// User IP sanitizations | ||
[ 'en.wikipedia.org', 'User:::1', 'User:0:0:0:0:0:0:0:1'], | ||
[ 'en.wikipedia.org', 'User:0:0:0:0:0:0:0:1', 'User:0:0:0:0:0:0:0:1'], | ||
[ 'en.wikipedia.org', 'User:127.000.000.001', 'User:127.0.0.1'], | ||
[ 'en.wikipedia.org', 'User:0.0.0.0', 'User:0.0.0.0' ], | ||
[ 'en.wikipedia.org', 'User:00.00.00.00', 'User:0.0.0.0' ], | ||
[ 'en.wikipedia.org', 'User:000.000.000.000', 'User:0.0.0.0'], | ||
[ 'en.wikipedia.org', 'User:141.000.011.253', 'User:141.0.11.253' ], | ||
[ 'en.wikipedia.org', 'User: 1.2.4.5', 'User:1.2.4.5' ], | ||
[ 'en.wikipedia.org', 'User:01.02.04.05', 'User:1.2.4.5' ], | ||
[ 'en.wikipedia.org', 'User:001.002.004.005', 'User:1.2.4.5' ], | ||
[ 'en.wikipedia.org', 'User:010.0.000.1', 'User:10.0.0.1' ], | ||
[ 'en.wikipedia.org', 'User:080.072.250.04', 'User:80.72.250.4' ], | ||
[ 'en.wikipedia.org', 'User:Foo.1000.00', 'User:Foo.1000.00' ], | ||
[ 'en.wikipedia.org', 'User:Bar.01', 'User:Bar.01' ], | ||
[ 'en.wikipedia.org', 'User:Bar.010', 'User:Bar.010' ], | ||
[ 'en.wikipedia.org', 'User:cebc:2004:f::', 'User:CEBC:2004:F:0:0:0:0:0' ], | ||
[ 'en.wikipedia.org', 'User:::', 'User:0:0:0:0:0:0:0:0' ], | ||
[ 'en.wikipedia.org', 'User:0:0:0:1::', 'User:0:0:0:1:0:0:0:0' ], | ||
[ 'en.wikipedia.org', 'User:3f:535::e:fbb', 'User:3F:535:0:0:0:0:E:FBB' ], | ||
[ 'en.wikipedia.org', 'User Talk:::1', 'User_talk:0:0:0:0:0:0:0:1'], | ||
[ 'en.wikipedia.org', 'User_Talk:::1', 'User_talk:0:0:0:0:0:0:0:1'], | ||
[ 'en.wikipedia.org', 'User_talk:::1', 'User_talk:0:0:0:0:0:0:0:1'], | ||
[ 'en.wikipedia.org', 'User_talk:::1/24', 'User_talk:0:0:0:0:0:0:0:1/24'], | ||
['en.wikipedia.org', 'User:::1', 'User:0:0:0:0:0:0:0:1'], | ||
['en.wikipedia.org', 'User:0:0:0:0:0:0:0:1', 'User:0:0:0:0:0:0:0:1'], | ||
['en.wikipedia.org', 'User:127.000.000.001', 'User:127.0.0.1'], | ||
['en.wikipedia.org', 'User:0.0.0.0', 'User:0.0.0.0'], | ||
['en.wikipedia.org', 'User:00.00.00.00', 'User:0.0.0.0'], | ||
['en.wikipedia.org', 'User:000.000.000.000', 'User:0.0.0.0'], | ||
['en.wikipedia.org', 'User:141.000.011.253', 'User:141.0.11.253'], | ||
['en.wikipedia.org', 'User: 1.2.4.5', 'User:1.2.4.5'], | ||
['en.wikipedia.org', 'User:01.02.04.05', 'User:1.2.4.5'], | ||
['en.wikipedia.org', 'User:001.002.004.005', 'User:1.2.4.5'], | ||
['en.wikipedia.org', 'User:010.0.000.1', 'User:10.0.0.1'], | ||
['en.wikipedia.org', 'User:080.072.250.04', 'User:80.72.250.4'], | ||
['en.wikipedia.org', 'User:Foo.1000.00', 'User:Foo.1000.00'], | ||
['en.wikipedia.org', 'User:Bar.01', 'User:Bar.01'], | ||
['en.wikipedia.org', 'User:Bar.010', 'User:Bar.010'], | ||
['en.wikipedia.org', 'User:cebc:2004:f::', 'User:CEBC:2004:F:0:0:0:0:0'], | ||
['en.wikipedia.org', 'User:::', 'User:0:0:0:0:0:0:0:0'], | ||
['en.wikipedia.org', 'User:0:0:0:1::', 'User:0:0:0:1:0:0:0:0'], | ||
['en.wikipedia.org', 'User:3f:535::e:fbb', 'User:3F:535:0:0:0:0:E:FBB'], | ||
['en.wikipedia.org', 'User Talk:::1', 'User_talk:0:0:0:0:0:0:0:1'], | ||
['en.wikipedia.org', 'User_Talk:::1', 'User_talk:0:0:0:0:0:0:0:1'], | ||
['en.wikipedia.org', 'User_talk:::1', 'User_talk:0:0:0:0:0:0:0:1'], | ||
['en.wikipedia.org', 'User_talk:::1/24', 'User_talk:0:0:0:0:0:0:0:1/24'], | ||
// Case-sensitive namespace | ||
[ 'en.wikipedia.org', 'user:pchelolo', 'User:Pchelolo'], | ||
[ 'en.wiktionary.org', 'user:pchelolo', 'User:Pchelolo' ], | ||
[ 'en.wikipedia.org', | ||
['en.wikipedia.org', 'user:pchelolo', 'User:Pchelolo'], | ||
['en.wiktionary.org', 'user:pchelolo', 'User:Pchelolo'], | ||
['en.wikipedia.org', | ||
'list of Neighbours characters (2016)#Tom Quill', | ||
'List_of_Neighbours_characters_(2016)'], | ||
[ 'en.wikipedia.org', 'ß', 'ß' ], | ||
[ 'en.wikipedia.org', 'ʼn', 'ʼn' ], | ||
[ 'en.wikipedia.org', 'ǰ', 'ǰ' ], | ||
[ 'en.wikipedia.org', 'ΐ', 'ΐ' ], | ||
[ 'en.wikipedia.org', 'ΰ', 'ΰ' ], | ||
[ 'en.wikipedia.org', 'և', 'և' ], | ||
[ 'en.wikipedia.org', 'ẖ', 'ẖ' ], | ||
[ 'en.wikipedia.org', 'ẗ', 'ẗ' ], | ||
[ 'en.wikipedia.org', 'ẘ', 'ẘ' ], | ||
[ 'en.wikipedia.org', 'ẙ', 'ẙ' ], | ||
[ 'en.wikipedia.org', 'ẚ', 'ẚ' ], | ||
[ 'en.wikipedia.org', 'ὐ', 'ὐ' ], | ||
[ 'en.wikipedia.org', 'ὒ', 'ὒ' ], | ||
[ 'en.wikipedia.org', 'ὔ', 'ὔ' ], | ||
[ 'en.wikipedia.org', 'ὖ', 'ὖ' ], | ||
[ 'en.wikipedia.org', 'ᾀ', 'ᾈ' ], | ||
[ 'en.wikipedia.org', 'ᾁ', 'ᾉ' ], | ||
[ 'en.wikipedia.org', 'ᾂ', 'ᾊ' ], | ||
[ 'en.wikipedia.org', 'ᾃ', 'ᾋ' ], | ||
[ 'en.wikipedia.org', 'ᾄ', 'ᾌ' ], | ||
[ 'en.wikipedia.org', 'ᾅ', 'ᾍ' ], | ||
[ 'en.wikipedia.org', 'ᾆ', 'ᾎ' ], | ||
[ 'en.wikipedia.org', 'ᾇ', 'ᾏ' ], | ||
[ 'en.wikipedia.org', 'ᾐ', 'ᾘ' ], | ||
[ 'en.wikipedia.org', 'ᾑ', 'ᾙ' ], | ||
[ 'en.wikipedia.org', 'ᾒ', 'ᾚ' ], | ||
[ 'en.wikipedia.org', 'ᾓ', 'ᾛ' ], | ||
[ 'en.wikipedia.org', 'ᾔ', 'ᾜ' ], | ||
[ 'en.wikipedia.org', 'ᾕ', 'ᾝ' ], | ||
[ 'en.wikipedia.org', 'ᾖ', 'ᾞ' ], | ||
[ 'en.wikipedia.org', 'ᾗ', 'ᾟ' ], | ||
[ 'en.wikipedia.org', 'ᾠ', 'ᾨ' ], | ||
[ 'en.wikipedia.org', 'ᾡ', 'ᾩ' ], | ||
[ 'en.wikipedia.org', 'ᾢ', 'ᾪ' ], | ||
[ 'en.wikipedia.org', 'ᾣ', 'ᾫ' ], | ||
[ 'en.wikipedia.org', 'ᾤ', 'ᾬ' ], | ||
[ 'en.wikipedia.org', 'ᾥ', 'ᾭ' ], | ||
[ 'en.wikipedia.org', 'ᾦ', 'ᾮ' ], | ||
[ 'en.wikipedia.org', 'ᾧ', 'ᾯ' ], | ||
[ 'en.wikipedia.org', 'ff', 'ff' ], | ||
[ 'en.wikipedia.org', 'fi', 'fi' ], | ||
[ 'en.wikipedia.org', 'fl', 'fl' ], | ||
[ 'en.wikipedia.org', 'ffi', 'ffi' ], | ||
[ 'en.wikipedia.org', 'ffl', 'ffl' ], | ||
[ 'en.wikipedia.org', 'ſt', 'ſt' ], | ||
[ 'en.wikipedia.org', 'st', 'st' ], | ||
[ 'en.wikipedia.org', 'ﬓ', 'ﬓ' ], | ||
[ 'en.wikipedia.org', 'ﬔ', 'ﬔ' ], | ||
[ 'en.wikipedia.org', 'ﬕ', 'ﬕ' ], | ||
[ 'en.wikipedia.org', 'ﬖ', 'ﬖ' ], | ||
[ 'en.wikipedia.org', 'ﬗ', 'ﬗ' ], | ||
[ 'en.wikipedia.org', 'ⓝ', 'ⓝ' ], | ||
['en.wikipedia.org', 'ß', 'ß'], | ||
['en.wikipedia.org', 'ʼn', 'ʼn'], | ||
['en.wikipedia.org', 'ǰ', 'ǰ'], | ||
['en.wikipedia.org', 'ΐ', 'ΐ'], | ||
['en.wikipedia.org', 'ΰ', 'ΰ'], | ||
['en.wikipedia.org', 'և', 'և'], | ||
['en.wikipedia.org', 'ẖ', 'ẖ'], | ||
['en.wikipedia.org', 'ẗ', 'ẗ'], | ||
['en.wikipedia.org', 'ẘ', 'ẘ'], | ||
['en.wikipedia.org', 'ẙ', 'ẙ'], | ||
['en.wikipedia.org', 'ẚ', 'ẚ'], | ||
['en.wikipedia.org', 'ὐ', 'ὐ'], | ||
['en.wikipedia.org', 'ὒ', 'ὒ'], | ||
['en.wikipedia.org', 'ὔ', 'ὔ'], | ||
['en.wikipedia.org', 'ὖ', 'ὖ'], | ||
['en.wikipedia.org', 'ᾀ', 'ᾈ'], | ||
['en.wikipedia.org', 'ᾁ', 'ᾉ'], | ||
['en.wikipedia.org', 'ᾂ', 'ᾊ'], | ||
['en.wikipedia.org', 'ᾃ', 'ᾋ'], | ||
['en.wikipedia.org', 'ᾄ', 'ᾌ'], | ||
['en.wikipedia.org', 'ᾅ', 'ᾍ'], | ||
['en.wikipedia.org', 'ᾆ', 'ᾎ'], | ||
['en.wikipedia.org', 'ᾇ', 'ᾏ'], | ||
['en.wikipedia.org', 'ᾐ', 'ᾘ'], | ||
['en.wikipedia.org', 'ᾑ', 'ᾙ'], | ||
['en.wikipedia.org', 'ᾒ', 'ᾚ'], | ||
['en.wikipedia.org', 'ᾓ', 'ᾛ'], | ||
['en.wikipedia.org', 'ᾔ', 'ᾜ'], | ||
['en.wikipedia.org', 'ᾕ', 'ᾝ'], | ||
['en.wikipedia.org', 'ᾖ', 'ᾞ'], | ||
['en.wikipedia.org', 'ᾗ', 'ᾟ'], | ||
['en.wikipedia.org', 'ᾠ', 'ᾨ'], | ||
['en.wikipedia.org', 'ᾡ', 'ᾩ'], | ||
['en.wikipedia.org', 'ᾢ', 'ᾪ'], | ||
['en.wikipedia.org', 'ᾣ', 'ᾫ'], | ||
['en.wikipedia.org', 'ᾤ', 'ᾬ'], | ||
['en.wikipedia.org', 'ᾥ', 'ᾭ'], | ||
['en.wikipedia.org', 'ᾦ', 'ᾮ'], | ||
['en.wikipedia.org', 'ᾧ', 'ᾯ'], | ||
['en.wikipedia.org', 'ff', 'ff'], | ||
['en.wikipedia.org', 'fi', 'fi'], | ||
['en.wikipedia.org', 'fl', 'fl'], | ||
['en.wikipedia.org', 'ffi', 'ffi'], | ||
['en.wikipedia.org', 'ffl', 'ffl'], | ||
['en.wikipedia.org', 'ſt', 'ſt'], | ||
['en.wikipedia.org', 'st', 'st'], | ||
['en.wikipedia.org', 'ﬓ', 'ﬓ'], | ||
['en.wikipedia.org', 'ﬔ', 'ﬔ'], | ||
['en.wikipedia.org', 'ﬕ', 'ﬕ'], | ||
['en.wikipedia.org', 'ﬖ', 'ﬖ'], | ||
['en.wikipedia.org', 'ﬗ', 'ﬗ'], | ||
['en.wikipedia.org', 'ⓝ', 'ⓝ'], | ||
// Special page aliases | ||
[ 'en.wikipedia.org', 'Special:NotSpecial', 'Special:NotSpecial' ], | ||
[ 'en.wikipedia.org', 'Special:Lonelypages', 'Special:LonelyPages' ], | ||
[ 'en.wikipedia.org', 'Special:lonelypages', 'Special:LonelyPages' ], | ||
[ 'en.wikipedia.org', 'Special:OrphanedPages', 'Special:LonelyPages' ], | ||
[ 'en.wikipedia.org', 'Special:Contribs/124.106.240.49', 'Special:Contributions/124.106.240.49' ], | ||
[ 'es.wikipedia.org', 'Especial:SpecialPages', 'Especial:PáginasEspeciales' ], | ||
[ 'es.wikipedia.org', 'Especial:Expandir plantillas', 'Especial:Sustituir_plantillas' ], | ||
[ 'es.wikipedia.org', 'Especial:BookSources/9784041047910', 'Especial:FuentesDeLibros/9784041047910' ], | ||
['en.wikipedia.org', 'Special:NotSpecial', 'Special:NotSpecial'], | ||
['en.wikipedia.org', 'Special:Lonelypages', 'Special:LonelyPages'], | ||
['en.wikipedia.org', 'Special:lonelypages', 'Special:LonelyPages'], | ||
['en.wikipedia.org', 'Special:OrphanedPages', 'Special:LonelyPages'], | ||
// eslint-disable-next-line max-len | ||
['en.wikipedia.org', 'Special:Contribs/124.106.240.49', 'Special:Contributions/124.106.240.49'], | ||
['es.wikipedia.org', 'Especial:SpecialPages', 'Especial:PáginasEspeciales'], | ||
['es.wikipedia.org', 'Especial:Expandir plantillas', 'Especial:Sustituir_plantillas'], | ||
// eslint-disable-next-line max-len | ||
['es.wikipedia.org', 'Especial:BookSources/9784041047910', 'Especial:FuentesDeLibros/9784041047910'] | ||
]; | ||
testCases.forEach(function (test) { | ||
it('For ' + test[0] + ' should normalize ' + test[1] + ' to ' + test[2], function() { | ||
testCases.forEach((test) => { | ||
it(`For ${test[0]} should normalize ${test[1]} to ${test[2]}`, () => { | ||
return getSiteInfo(test[0]) | ||
.then(function(siteInfo) { | ||
return Title.newFromText(test[1], siteInfo).getPrefixedDBKey(); | ||
}) | ||
.then(function(res) { | ||
assert.deepEqual(res, test[2]); | ||
}); | ||
.then((siteInfo) => Title.newFromText(test[1], siteInfo).getPrefixedDBKey()) | ||
.then((res) => assert.deepEqual(res, test[2])); | ||
}); | ||
}); | ||
it('Should normalize fragment', function() { | ||
it('Should normalize fragment', () => { | ||
return getSiteInfo('en.wikipedia.org') | ||
.then(function(siteInfo) { | ||
return Title.newFromText('Test#some fragment', siteInfo); | ||
}) | ||
.then(function(res) { | ||
assert.deepEqual(res.getFragment(), 'some_fragment'); | ||
}); | ||
.then((siteInfo) => Title.newFromText('Test#some fragment', siteInfo)) | ||
.then((res) => assert.deepEqual(res.getFragment(), 'some_fragment')); | ||
}); | ||
it('Should normalize and give readable title', function() { | ||
it('Should normalize and give readable title', () => { | ||
return getSiteInfo('en.wikipedia.org') | ||
.then(function(siteInfo) { | ||
return Title.newFromText('X-Men_(film_series)', siteInfo); | ||
}) | ||
.then(function(res) { | ||
assert.deepEqual(res.getPrefixedText(), 'X-Men (film series)'); | ||
}); | ||
.then((siteInfo) => Title.newFromText('X-Men_(film_series)', siteInfo)) | ||
.then((res) => assert.deepEqual(res.getPrefixedText(), 'X-Men (film series)')); | ||
}); | ||
}); | ||
describe('Defaults', function() { | ||
var testCases = [ | ||
[ undefined, 'Example.svg', 0, 'Example.svg' ], | ||
[ 0, 'Example.svg', 0, 'Example.svg' ], | ||
[ 6, 'Example.svg', 6, 'File:Example.svg' ], | ||
[ undefined, 'File:Example.svg', 6, 'File:Example.svg' ], | ||
[ 6, 'File:Example.svg', 6, 'File:Example.svg' ], | ||
[ 2, 'File:Example.svg', 6, 'File:Example.svg' ], | ||
[ 2, 'Test', 2, 'User:Test' ], | ||
[ 2, ':Test', 0, 'Test' ], | ||
[ 0, ':User:Test', 2, 'User:Test' ], | ||
describe('Defaults', () => { | ||
const testCases = [ | ||
[undefined, 'Example.svg', 0, 'Example.svg'], | ||
[0, 'Example.svg', 0, 'Example.svg'], | ||
[6, 'Example.svg', 6, 'File:Example.svg'], | ||
[undefined, 'File:Example.svg', 6, 'File:Example.svg'], | ||
[6, 'File:Example.svg', 6, 'File:Example.svg'], | ||
[2, 'File:Example.svg', 6, 'File:Example.svg'], | ||
[2, 'Test', 2, 'User:Test'], | ||
[2, ':Test', 0, 'Test'], | ||
[0, ':User:Test', 2, 'User:Test'] | ||
]; | ||
testCases.forEach(function (test) { | ||
it('For ns:' + test[0] + ' should default ' + test[1] + ' to ' + test[2], function() { | ||
testCases.forEach((test) => { | ||
it(`For ns:${test[0]} should default ${test[1]} to ${test[2]}`, () => { | ||
return getSiteInfo('en.wikipedia.org') | ||
.then(function(siteInfo) { | ||
var t = Title.newFromText(test[1], siteInfo, test[0]); | ||
.then((siteInfo) => { | ||
const t = Title.newFromText(test[1], siteInfo, test[0]); | ||
return [t.getNamespace()._id, t.getPrefixedDBKey()]; | ||
}) | ||
.then(function(res) { | ||
assert.deepEqual(res[0], test[2]) | ||
.then((res) => { | ||
assert.deepEqual(res[0], test[2]); | ||
assert.deepEqual(res[1], test[3]); | ||
@@ -327,66 +309,66 @@ }); | ||
describe('Utilities', function () { | ||
var data = [ | ||
describe('Utilities', () => { | ||
const data = [ | ||
[ | ||
' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', | ||
' %!"$&\'()*,\\-./0-9:;=?@A-Z\\\\\\^_`a-z~+\\u0080-\\uFFFF', | ||
' %!"$&\'()*,\\-./0-9:;=?@A-Z\\\\\\^_`a-z~+\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'QWERTYf-\\xFF+', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'QWERTY\\x66-\\xFD+', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'QWERTYf-y+', | ||
'QWERTYf-y+', | ||
'QWERTYf-y+' | ||
], | ||
[ | ||
'QWERTYf-\\x80+', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'QWERTY\\x66-\\x80+\\x23', | ||
'QWERTYf-\\x7F+#\\u0080-\\uFFFF', | ||
'QWERTYf-\\x7F+#\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'QWERTY\\x66-\\x80+\\xD3', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF', | ||
'QWERTYf-\\x7F+\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'\\\\\\x99', | ||
'\\\\\\u0080-\\uFFFF', | ||
'\\\\\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'-\\x99', | ||
'\\-\\u0080-\\uFFFF', | ||
'\\-\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'QWERTY\\-\\x99', | ||
'QWERTY\\-\\u0080-\\uFFFF', | ||
'QWERTY\\-\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'\\\\x99', | ||
'\\\\x99', | ||
'\\\\x99' | ||
], | ||
[ | ||
'A-\\x9F', | ||
'A-\\x7F\\u0080-\\uFFFF', | ||
'A-\\x7F\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'\\x66-\\x77QWERTY\\x88-\\x91FXZ', | ||
'f-wQWERTYFXZ\\u0080-\\uFFFF', | ||
'f-wQWERTYFXZ\\u0080-\\uFFFF' | ||
], | ||
[ | ||
'\\x66-\\x99QWERTY\\xAA-\\xEEFXZ', | ||
'f-\\x7FQWERTYFXZ\\u0080-\\uFFFF', | ||
'f-\\x7FQWERTYFXZ\\u0080-\\uFFFF' | ||
] | ||
]; | ||
var idx = 0; | ||
data.forEach(function(test) { | ||
let idx = 0; | ||
data.forEach((test) => { | ||
idx++; | ||
it('Should covert byte range. Test ' + idx, function () { | ||
it(`Should covert byte range. Test ${idx}`, () => { | ||
assert.deepEqual(utils.convertByteClassToUnicodeClass(test[0]), test[1]); | ||
@@ -396,26 +378,22 @@ }); | ||
it('Should fetch domains', function() { | ||
it('Should fetch domains', () => { | ||
return preq.get({ | ||
uri: 'https://en.wikipedia.org/w/api.php?action=sitematrix&format=json' | ||
}) | ||
.then(function(res) { | ||
.then((res) => { | ||
return Object.keys(res.body.sitematrix) | ||
.filter(function(idx) { | ||
return idx !== 'count' && idx !== 'specials'; | ||
.filter((idx) => { | ||
return idx !== 'count' && | ||
idx !== 'specials' && | ||
res.body.sitematrix[idx].site.length; | ||
}) | ||
.map(function (idx) { | ||
return res.body.sitematrix[idx].site[0].url.replace(/^https?:\/\//, ''); | ||
}); | ||
.map((idx) => res.body.sitematrix[idx].site[0].url.replace(/^https?:\/\//, '')); | ||
}) | ||
.then(function (domains) { | ||
describe('Various domains', function() { | ||
domains.forEach(function (domain) { | ||
it('Should work for ' + domain, function() { | ||
.then((domains) => { | ||
describe('Various domains', () => { | ||
domains.forEach((domain) => { | ||
it(`Should work for ${domain}`, () => { | ||
return getSiteInfo(domain) | ||
.then(function(siteInfo) { | ||
return Title.newFromText('1', siteInfo); | ||
}) | ||
.then(function (res) { | ||
assert.deepEqual(res.getPrefixedDBKey(), '1'); | ||
}); | ||
.then((siteInfo) => Title.newFromText('1', siteInfo)) | ||
.then((res) => assert.deepEqual(res.getPrefixedDBKey(), '1')); | ||
}); | ||
@@ -427,5 +405,5 @@ }); | ||
}); | ||
} | ||
}; | ||
doTest(1); | ||
doTest(2); |
Sorry, the diff of this file is not supported yet
56258
8
1240