urlpattern-polyfill
Advanced tools
Comparing version 7.0.0 to 8.0.1
// src/path-to-regex-modified.ts | ||
var Part = class { | ||
constructor(type, name, prefix, value, suffix, modifier) { | ||
this.type = 3 /* kFixed */; | ||
this.name = ""; | ||
this.prefix = ""; | ||
this.value = ""; | ||
this.suffix = ""; | ||
this.modifier = 3 /* kNone */; | ||
this.type = type; | ||
this.name = name; | ||
this.prefix = prefix; | ||
this.value = value; | ||
this.suffix = suffix; | ||
this.modifier = modifier; | ||
} | ||
hasCustomName() { | ||
return this.name !== "" && typeof this.name !== "number"; | ||
} | ||
}; | ||
var regexIdentifierStart = /[$_\p{ID_Start}]/u; | ||
var regexIdentifierPart = /[$_\u200C\u200D\p{ID_Continue}]/u; | ||
var kFullWildcardRegex = ".*"; | ||
function isASCII(str, extended) { | ||
@@ -22,3 +42,3 @@ return (extended ? /^[\x00-\xFF]*$/ : /^[\x00-\x7F]*$/).test(str); | ||
if (char === "+" || char === "?") { | ||
tokens.push({ type: "MODIFIER", index: i, value: str[i++] }); | ||
tokens.push({ type: "OTHER_MODIFIER", index: i, value: str[i++] }); | ||
continue; | ||
@@ -103,3 +123,3 @@ } | ||
} | ||
tokens.push({ type: "PATTERN", index: i, value: pattern }); | ||
tokens.push({ type: "REGEX", index: i, value: pattern }); | ||
i = j; | ||
@@ -115,4 +135,5 @@ continue; | ||
const tokens = lexer(str); | ||
const { prefixes = "./" } = options; | ||
const defaultPattern = `[^${escapeString(options.delimiter === void 0 ? "/#?" : options.delimiter)}]+?`; | ||
options.delimiter ?? (options.delimiter = "/#?"); | ||
options.prefixes ?? (options.prefixes = "./"); | ||
const segmentWildcardRegex = `[^${escapeString(options.delimiter)}]+?`; | ||
const result = []; | ||
@@ -128,7 +149,3 @@ let key = 0; | ||
const tryConsumeModifier = () => { | ||
const r = tryConsume("MODIFIER"); | ||
if (r) { | ||
return r; | ||
} | ||
return tryConsume("ASTERISK"); | ||
return tryConsume("OTHER_MODIFIER") ?? tryConsume("ASTERISK"); | ||
}; | ||
@@ -145,3 +162,3 @@ const mustConsume = (type) => { | ||
let value; | ||
while (value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR")) { | ||
while (value = tryConsume("CHAR") ?? tryConsume("ESCAPED_CHAR")) { | ||
result2 += value; | ||
@@ -155,73 +172,104 @@ } | ||
const encodePart = options.encodePart || DefaultEncodePart; | ||
let pendingFixedValue = ""; | ||
const appendToPendingFixedValue = (value) => { | ||
pendingFixedValue += value; | ||
}; | ||
const maybeAddPartFromPendingFixedValue = () => { | ||
if (!pendingFixedValue.length) { | ||
return; | ||
} | ||
result.push(new Part(3 /* kFixed */, "", "", encodePart(pendingFixedValue), "", 3 /* kNone */)); | ||
pendingFixedValue = ""; | ||
}; | ||
const addPart = (prefix, nameToken, regexOrWildcardToken, suffix, modifierToken) => { | ||
let modifier = 3 /* kNone */; | ||
switch (modifierToken) { | ||
case "?": | ||
modifier = 1 /* kOptional */; | ||
break; | ||
case "*": | ||
modifier = 0 /* kZeroOrMore */; | ||
break; | ||
case "+": | ||
modifier = 2 /* kOneOrMore */; | ||
break; | ||
} | ||
if (!nameToken && !regexOrWildcardToken && modifier === 3 /* kNone */) { | ||
appendToPendingFixedValue(prefix); | ||
return; | ||
} | ||
maybeAddPartFromPendingFixedValue(); | ||
if (!nameToken && !regexOrWildcardToken) { | ||
if (!prefix) { | ||
return; | ||
} | ||
result.push(new Part(3 /* kFixed */, "", "", encodePart(prefix), "", modifier)); | ||
return; | ||
} | ||
let regexValue; | ||
if (!regexOrWildcardToken) { | ||
regexValue = segmentWildcardRegex; | ||
} else if (regexOrWildcardToken === "*") { | ||
regexValue = kFullWildcardRegex; | ||
} else { | ||
regexValue = regexOrWildcardToken; | ||
} | ||
let type = 2 /* kRegex */; | ||
if (regexValue === segmentWildcardRegex) { | ||
type = 1 /* kSegmentWildcard */; | ||
regexValue = ""; | ||
} else if (regexValue === kFullWildcardRegex) { | ||
type = 0 /* kFullWildcard */; | ||
regexValue = ""; | ||
} | ||
let name; | ||
if (nameToken) { | ||
name = nameToken; | ||
} else if (regexOrWildcardToken) { | ||
name = key++; | ||
} | ||
if (nameSet.has(name)) { | ||
throw new TypeError(`Duplicate name '${name}'.`); | ||
} | ||
nameSet.add(name); | ||
result.push(new Part(type, name, encodePart(prefix), regexValue, encodePart(suffix), modifier)); | ||
}; | ||
while (i < tokens.length) { | ||
const char = tryConsume("CHAR"); | ||
const name = tryConsume("NAME"); | ||
let pattern = tryConsume("PATTERN"); | ||
if (!name && !pattern && tryConsume("ASTERISK")) { | ||
pattern = ".*"; | ||
const charToken = tryConsume("CHAR"); | ||
const nameToken = tryConsume("NAME"); | ||
let regexOrWildcardToken = tryConsume("REGEX"); | ||
if (!nameToken && !regexOrWildcardToken) { | ||
regexOrWildcardToken = tryConsume("ASTERISK"); | ||
} | ||
if (name || pattern) { | ||
let prefix = char || ""; | ||
if (prefixes.indexOf(prefix) === -1) { | ||
path += prefix; | ||
if (nameToken || regexOrWildcardToken) { | ||
let prefix = charToken ?? ""; | ||
if (options.prefixes.indexOf(prefix) === -1) { | ||
appendToPendingFixedValue(prefix); | ||
prefix = ""; | ||
} | ||
if (path) { | ||
result.push(encodePart(path)); | ||
path = ""; | ||
} | ||
const finalName = name || key++; | ||
if (nameSet.has(finalName)) { | ||
throw new TypeError(`Duplicate name '${finalName}'.`); | ||
} | ||
nameSet.add(finalName); | ||
result.push({ | ||
name: finalName, | ||
prefix: encodePart(prefix), | ||
suffix: "", | ||
pattern: pattern || defaultPattern, | ||
modifier: tryConsumeModifier() || "" | ||
}); | ||
maybeAddPartFromPendingFixedValue(); | ||
let modifierToken = tryConsumeModifier(); | ||
addPart(prefix, nameToken, regexOrWildcardToken, "", modifierToken); | ||
continue; | ||
} | ||
const value = char || tryConsume("ESCAPED_CHAR"); | ||
const value = charToken ?? tryConsume("ESCAPED_CHAR"); | ||
if (value) { | ||
path += value; | ||
appendToPendingFixedValue(value); | ||
continue; | ||
} | ||
const open = tryConsume("OPEN"); | ||
if (open) { | ||
const openToken = tryConsume("OPEN"); | ||
if (openToken) { | ||
const prefix = consumeText(); | ||
const name2 = tryConsume("NAME") || ""; | ||
let pattern2 = tryConsume("PATTERN") || ""; | ||
if (!name2 && !pattern2 && tryConsume("ASTERISK")) { | ||
pattern2 = ".*"; | ||
const nameToken2 = tryConsume("NAME"); | ||
let regexOrWildcardToken2 = tryConsume("REGEX"); | ||
if (!nameToken2 && !regexOrWildcardToken2) { | ||
regexOrWildcardToken2 = tryConsume("ASTERISK"); | ||
} | ||
const suffix = consumeText(); | ||
mustConsume("CLOSE"); | ||
const modifier = tryConsumeModifier() || ""; | ||
if (!name2 && !pattern2 && !modifier) { | ||
path += prefix; | ||
continue; | ||
} | ||
if (!name2 && !pattern2 && !prefix) { | ||
continue; | ||
} | ||
if (path) { | ||
result.push(encodePart(path)); | ||
path = ""; | ||
} | ||
result.push({ | ||
name: name2 || (pattern2 ? key++ : ""), | ||
pattern: name2 && !pattern2 ? defaultPattern : pattern2, | ||
prefix: encodePart(prefix), | ||
suffix: encodePart(suffix), | ||
modifier | ||
}); | ||
const modifierToken = tryConsumeModifier(); | ||
addPart(prefix, nameToken2, regexOrWildcardToken2, suffix, modifierToken); | ||
continue; | ||
} | ||
if (path) { | ||
result.push(encodePart(path)); | ||
path = ""; | ||
} | ||
maybeAddPartFromPendingFixedValue(); | ||
mustConsume("END"); | ||
@@ -237,88 +285,93 @@ } | ||
} | ||
function regexpToRegexp(path, keys) { | ||
if (!keys) | ||
return path; | ||
const groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g; | ||
let index = 0; | ||
let execResult = groupsRegex.exec(path.source); | ||
while (execResult) { | ||
keys.push({ | ||
name: execResult[1] || index++, | ||
prefix: "", | ||
suffix: "", | ||
modifier: "", | ||
pattern: "" | ||
}); | ||
execResult = groupsRegex.exec(path.source); | ||
function stringToRegexp(path, names, options) { | ||
return partsToRegexp(parse(path, options), names, options); | ||
} | ||
function modifierToString(modifier) { | ||
switch (modifier) { | ||
case 0 /* kZeroOrMore */: | ||
return "*"; | ||
case 1 /* kOptional */: | ||
return "?"; | ||
case 2 /* kOneOrMore */: | ||
return "+"; | ||
case 3 /* kNone */: | ||
return ""; | ||
} | ||
return path; | ||
} | ||
function arrayToRegexp(paths, keys, options) { | ||
const parts = paths.map((path) => pathToRegexp(path, keys, options).source); | ||
return new RegExp(`(?:${parts.join("|")})`, flags(options)); | ||
} | ||
function stringToRegexp(path, keys, options) { | ||
return tokensToRegexp(parse(path, options), keys, options); | ||
} | ||
function tokensToRegexp(tokens, keys, options = {}) { | ||
const { | ||
strict = false, | ||
start = true, | ||
end = true, | ||
encode = (x) => x | ||
} = options; | ||
const endsWith = `[${escapeString(options.endsWith === void 0 ? "" : options.endsWith)}]|$`; | ||
const delimiter = `[${escapeString(options.delimiter === void 0 ? "/#?" : options.delimiter)}]`; | ||
let route = start ? "^" : ""; | ||
for (const token of tokens) { | ||
if (typeof token === "string") { | ||
route += escapeString(encode(token)); | ||
} else { | ||
const prefix = escapeString(encode(token.prefix)); | ||
const suffix = escapeString(encode(token.suffix)); | ||
if (token.pattern) { | ||
if (keys) | ||
keys.push(token); | ||
if (prefix || suffix) { | ||
if (token.modifier === "+" || token.modifier === "*") { | ||
const mod = token.modifier === "*" ? "?" : ""; | ||
route += `(?:${prefix}((?:${token.pattern})(?:${suffix}${prefix}(?:${token.pattern}))*)${suffix})${mod}`; | ||
} else { | ||
route += `(?:${prefix}(${token.pattern})${suffix})${token.modifier}`; | ||
} | ||
} else { | ||
if (token.modifier === "+" || token.modifier === "*") { | ||
route += `((?:${token.pattern})${token.modifier})`; | ||
} else { | ||
route += `(${token.pattern})${token.modifier}`; | ||
} | ||
} | ||
function partsToRegexp(parts, names, options = {}) { | ||
options.delimiter ?? (options.delimiter = "/#?"); | ||
options.prefixes ?? (options.prefixes = "./"); | ||
options.sensitive ?? (options.sensitive = false); | ||
options.strict ?? (options.strict = false); | ||
options.end ?? (options.end = true); | ||
options.start ?? (options.start = true); | ||
options.endsWith = ""; | ||
let result = options.start ? "^" : ""; | ||
for (const part of parts) { | ||
if (part.type === 3 /* kFixed */) { | ||
if (part.modifier === 3 /* kNone */) { | ||
result += escapeString(part.value); | ||
} else { | ||
route += `(?:${prefix}${suffix})${token.modifier}`; | ||
result += `(?:${escapeString(part.value)})${modifierToString(part.modifier)}`; | ||
} | ||
continue; | ||
} | ||
if (names) | ||
names.push(part.name); | ||
const segmentWildcardRegex = `[^${escapeString(options.delimiter)}]+?`; | ||
let regexValue = part.value; | ||
if (part.type === 1 /* kSegmentWildcard */) | ||
regexValue = segmentWildcardRegex; | ||
else if (part.type === 0 /* kFullWildcard */) | ||
regexValue = kFullWildcardRegex; | ||
if (!part.prefix.length && !part.suffix.length) { | ||
if (part.modifier === 3 /* kNone */ || part.modifier === 1 /* kOptional */) { | ||
result += `(${regexValue})${modifierToString(part.modifier)}`; | ||
} else { | ||
result += `((?:${regexValue})${modifierToString(part.modifier)})`; | ||
} | ||
continue; | ||
} | ||
if (part.modifier === 3 /* kNone */ || part.modifier === 1 /* kOptional */) { | ||
result += `(?:${escapeString(part.prefix)}(${regexValue})${escapeString(part.suffix)})`; | ||
result += modifierToString(part.modifier); | ||
continue; | ||
} | ||
result += `(?:${escapeString(part.prefix)}`; | ||
result += `((?:${regexValue})(?:`; | ||
result += escapeString(part.suffix); | ||
result += escapeString(part.prefix); | ||
result += `(?:${regexValue}))*)${escapeString(part.suffix)})`; | ||
if (part.modifier === 0 /* kZeroOrMore */) { | ||
result += "?"; | ||
} | ||
} | ||
if (end) { | ||
if (!strict) | ||
route += `${delimiter}?`; | ||
route += !options.endsWith ? "$" : `(?=${endsWith})`; | ||
} else { | ||
const endToken = tokens[tokens.length - 1]; | ||
const isEndDelimited = typeof endToken === "string" ? delimiter.indexOf(endToken[endToken.length - 1]) > -1 : endToken === void 0; | ||
if (!strict) { | ||
route += `(?:${delimiter}(?=${endsWith}))?`; | ||
const endsWith = `[${escapeString(options.endsWith)}]|$`; | ||
const delimiter = `[${escapeString(options.delimiter)}]`; | ||
if (options.end) { | ||
if (!options.strict) { | ||
result += `${delimiter}?`; | ||
} | ||
if (!isEndDelimited) { | ||
route += `(?=${delimiter}|${endsWith})`; | ||
if (!options.endsWith.length) { | ||
result += "$"; | ||
} else { | ||
result += `(?=${endsWith})`; | ||
} | ||
return new RegExp(result, flags(options)); | ||
} | ||
return new RegExp(route, flags(options)); | ||
if (!options.strict) { | ||
result += `(?:${delimiter}(?=${endsWith}))?`; | ||
} | ||
let isEndDelimited = false; | ||
if (parts.length) { | ||
const lastPart = parts[parts.length - 1]; | ||
if (lastPart.type === 3 /* kFixed */ && lastPart.modifier === 3 /* kNone */) { | ||
isEndDelimited = options.delimiter.indexOf(lastPart) > -1; | ||
} | ||
} | ||
if (!isEndDelimited) { | ||
result += `(?=${delimiter}|${endsWith})`; | ||
} | ||
return new RegExp(result, flags(options)); | ||
} | ||
function pathToRegexp(path, keys, options) { | ||
if (path instanceof RegExp) | ||
return regexpToRegexp(path, keys); | ||
if (Array.isArray(path)) | ||
return arrayToRegexp(path, keys, options); | ||
return stringToRegexp(path, keys, options); | ||
} | ||
@@ -588,18 +641,44 @@ // src/url-utils.ts | ||
constructor(input) { | ||
// The list of `LexToken`s produced by the path-to-regexp `lexer()` function | ||
// when passed `input` with lenient mode enabled. | ||
this.tokenList = []; | ||
// As we parse the input string we populate a `URLPatternInit` dictionary | ||
// with each component pattern. This is then the final result of the parse. | ||
this.internalResult = {}; | ||
// The index of the current `LexToken` being considered. | ||
this.tokenIndex = 0; | ||
// The value to add to `tokenIndex` on each turn through the parse loop. | ||
// While typically this is `1`, it is also set to `0` at times for things | ||
// like state transitions, etc. It is automatically reset back to `1` at | ||
// the top of the parse loop. | ||
this.tokenIncrement = 1; | ||
// The index of the first `LexToken` to include in the component string. | ||
this.componentStart = 0; | ||
// The current parse state. This should only be changed via `changeState()` | ||
// or `rewindAndSetState()`. | ||
this.state = 0 /* INIT */; | ||
// The current nest depth of `{ }` pattern groupings. | ||
this.groupDepth = 0; | ||
// The current nesting depth of `[ ]` in hostname patterns. | ||
this.hostnameIPv6BracketDepth = 0; | ||
// True if we should apply parse rules as if this is a "standard" URL. If | ||
// false then this is treated as a "not a base URL". | ||
this.shouldTreatAsStandardURL = false; | ||
this.input = input; | ||
} | ||
// Return the parse result. The result is only available after the | ||
// `parse()` method completes. | ||
get result() { | ||
return this.internalResult; | ||
} | ||
// Attempt to parse the input string used to construct the Parser object. | ||
// This method may only be called once. Any errors will be thrown as an | ||
// exception. Retrieve the parse result by accessing the `Parser.result` | ||
// property getter. | ||
parse() { | ||
this.tokenList = lexer(this.input, true); | ||
this.tokenList = lexer( | ||
this.input, | ||
/*lenient=*/ | ||
true | ||
); | ||
for (; this.tokenIndex < this.tokenList.length; this.tokenIndex += this.tokenIncrement) { | ||
@@ -611,8 +690,20 @@ this.tokenIncrement = 1; | ||
if (this.isHashPrefix()) { | ||
this.changeState(9 /* HASH */, 1); | ||
this.changeState( | ||
9 /* HASH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} else if (this.isSearchPrefix()) { | ||
this.changeState(8 /* SEARCH */, 1); | ||
this.changeState( | ||
8 /* SEARCH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
this.internalResult.hash = ""; | ||
} else { | ||
this.changeState(7 /* PATHNAME */, 0); | ||
this.changeState( | ||
7 /* PATHNAME */, | ||
/*skip=*/ | ||
0 | ||
); | ||
this.internalResult.search = ""; | ||
@@ -626,3 +717,7 @@ this.internalResult.hash = ""; | ||
} | ||
this.changeState(10 /* DONE */, 0); | ||
this.changeState( | ||
10 /* DONE */, | ||
/*skip=*/ | ||
0 | ||
); | ||
break; | ||
@@ -680,5 +775,13 @@ } | ||
if (this.isPasswordPrefix()) { | ||
this.changeState(4 /* PASSWORD */, 1); | ||
this.changeState( | ||
4 /* PASSWORD */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} else if (this.isIdentityTerminator()) { | ||
this.changeState(5 /* HOSTNAME */, 1); | ||
this.changeState( | ||
5 /* HOSTNAME */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} | ||
@@ -688,3 +791,7 @@ break; | ||
if (this.isIdentityTerminator()) { | ||
this.changeState(5 /* HOSTNAME */, 1); | ||
this.changeState( | ||
5 /* HOSTNAME */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} | ||
@@ -699,9 +806,25 @@ break; | ||
if (this.isPortPrefix() && !this.hostnameIPv6BracketDepth) { | ||
this.changeState(6 /* PORT */, 1); | ||
this.changeState( | ||
6 /* PORT */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} else if (this.isPathnameStart()) { | ||
this.changeState(7 /* PATHNAME */, 0); | ||
this.changeState( | ||
7 /* PATHNAME */, | ||
/*skip=*/ | ||
0 | ||
); | ||
} else if (this.isSearchPrefix()) { | ||
this.changeState(8 /* SEARCH */, 1); | ||
this.changeState( | ||
8 /* SEARCH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} else if (this.isHashPrefix()) { | ||
this.changeState(9 /* HASH */, 1); | ||
this.changeState( | ||
9 /* HASH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} | ||
@@ -711,7 +834,19 @@ break; | ||
if (this.isPathnameStart()) { | ||
this.changeState(7 /* PATHNAME */, 0); | ||
this.changeState( | ||
7 /* PATHNAME */, | ||
/*skip=*/ | ||
0 | ||
); | ||
} else if (this.isSearchPrefix()) { | ||
this.changeState(8 /* SEARCH */, 1); | ||
this.changeState( | ||
8 /* SEARCH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} else if (this.isHashPrefix()) { | ||
this.changeState(9 /* HASH */, 1); | ||
this.changeState( | ||
9 /* HASH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} | ||
@@ -721,5 +856,13 @@ break; | ||
if (this.isSearchPrefix()) { | ||
this.changeState(8 /* SEARCH */, 1); | ||
this.changeState( | ||
8 /* SEARCH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} else if (this.isHashPrefix()) { | ||
this.changeState(9 /* HASH */, 1); | ||
this.changeState( | ||
9 /* HASH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} | ||
@@ -729,3 +872,7 @@ break; | ||
if (this.isHashPrefix()) { | ||
this.changeState(9 /* HASH */, 1); | ||
this.changeState( | ||
9 /* HASH */, | ||
/*skip=*/ | ||
1 | ||
); | ||
} | ||
@@ -828,3 +975,3 @@ break; | ||
const previousToken = this.safeToken(this.tokenIndex - 1); | ||
return previousToken.type !== "NAME" && previousToken.type !== "PATTERN" && previousToken.type !== "CLOSE" && previousToken.type !== "ASTERISK"; | ||
return previousToken.type !== "NAME" && previousToken.type !== "REGEX" && previousToken.type !== "CLOSE" && previousToken.type !== "ASTERISK"; | ||
} | ||
@@ -855,3 +1002,8 @@ isHashPrefix() { | ||
options.encodePart = protocolEncodeCallback; | ||
const regexp = pathToRegexp(this.makeComponentString(), void 0, options); | ||
const regexp = stringToRegexp( | ||
this.makeComponentString(), | ||
/*keys=*/ | ||
void 0, | ||
options | ||
); | ||
this.shouldTreatAsStandardURL = isSpecialScheme(regexp); | ||
@@ -885,4 +1037,4 @@ } | ||
pathname: o.pathname, | ||
search: o.search != "" ? o.search.substring(1, o.search.length) : void 0, | ||
hash: o.hash != "" ? o.hash.substring(1, o.hash.length) : void 0 | ||
search: o.search !== "" ? o.search.substring(1, o.search.length) : void 0, | ||
hash: o.hash !== "" ? o.hash.substring(1, o.hash.length) : void 0 | ||
}; | ||
@@ -952,37 +1104,39 @@ } | ||
} | ||
function tokensToPattern(tokens, options) { | ||
const wildcardPattern = ".*"; | ||
const segmentWildcardPattern = `[^${escapeRegexpString(options.delimiter === void 0 ? "/#?" : options.delimiter)}]+?`; | ||
function partsToPattern(parts, options) { | ||
options.delimiter ?? (options.delimiter = "/#?"); | ||
options.prefixes ?? (options.prefixes = "./"); | ||
options.sensitive ?? (options.sensitive = false); | ||
options.strict ?? (options.strict = false); | ||
options.end ?? (options.end = true); | ||
options.start ?? (options.start = true); | ||
options.endsWith = ""; | ||
const kFullWildcardRegex2 = ".*"; | ||
const segmentWildcardRegex = `[^${escapeRegexpString(options.delimiter)}]+?`; | ||
const regexIdentifierPart2 = /[$_\u200C\u200D\p{ID_Continue}]/u; | ||
let result = ""; | ||
for (let i = 0; i < tokens.length; ++i) { | ||
const token = tokens[i]; | ||
const lastToken = i > 0 ? tokens[i - 1] : null; | ||
const nextToken = i < tokens.length - 1 ? tokens[i + 1] : null; | ||
if (typeof token === "string") { | ||
result += escapePatternString(token); | ||
continue; | ||
} | ||
if (token.pattern === "") { | ||
if (token.modifier === "") { | ||
result += escapePatternString(token.prefix); | ||
for (let i = 0; i < parts.length; ++i) { | ||
const part = parts[i]; | ||
if (part.type === 3 /* kFixed */) { | ||
if (part.modifier === 3 /* kNone */) { | ||
result += escapePatternString(part.value); | ||
continue; | ||
} | ||
result += `{${escapePatternString(token.prefix)}}${token.modifier}`; | ||
result += `{${escapePatternString(part.value)}}${modifierToString(part.modifier)}`; | ||
continue; | ||
} | ||
const customName = typeof token.name !== "number"; | ||
const optionsPrefixes = options.prefixes !== void 0 ? options.prefixes : "./"; | ||
let needsGrouping = token.suffix !== "" || token.prefix !== "" && (token.prefix.length !== 1 || !optionsPrefixes.includes(token.prefix)); | ||
if (!needsGrouping && customName && token.pattern === segmentWildcardPattern && token.modifier === "" && nextToken && !nextToken.prefix && !nextToken.suffix) { | ||
if (typeof nextToken === "string") { | ||
const code = nextToken.length > 0 ? nextToken[0] : ""; | ||
const customName = part.hasCustomName(); | ||
let needsGrouping = !!part.suffix.length || !!part.prefix.length && (part.prefix.length !== 1 || !options.prefixes.includes(part.prefix)); | ||
const lastPart = i > 0 ? parts[i - 1] : null; | ||
const nextPart = i < parts.length - 1 ? parts[i + 1] : null; | ||
if (!needsGrouping && customName && part.type === 1 /* kSegmentWildcard */ && part.modifier === 3 /* kNone */ && nextPart && !nextPart.prefix.length && !nextPart.suffix.length) { | ||
if (nextPart.type === 3 /* kFixed */) { | ||
const code = nextPart.value.length > 0 ? nextPart.value[0] : ""; | ||
needsGrouping = regexIdentifierPart2.test(code); | ||
} else { | ||
needsGrouping = typeof nextToken.name === "number"; | ||
needsGrouping = !nextPart.hasCustomName(); | ||
} | ||
} | ||
if (!needsGrouping && token.prefix === "" && lastToken && typeof lastToken === "string" && lastToken.length > 0) { | ||
const code = lastToken[lastToken.length - 1]; | ||
needsGrouping = optionsPrefixes.includes(code); | ||
if (!needsGrouping && !part.prefix.length && lastPart && lastPart.type === 3 /* kFixed */) { | ||
const code = lastPart.value[lastPart.value.length - 1]; | ||
needsGrouping = options.prefixes.includes(code); | ||
} | ||
@@ -992,29 +1146,31 @@ if (needsGrouping) { | ||
} | ||
result += escapePatternString(token.prefix); | ||
result += escapePatternString(part.prefix); | ||
if (customName) { | ||
result += `:${token.name}`; | ||
result += `:${part.name}`; | ||
} | ||
if (token.pattern === wildcardPattern) { | ||
if (!customName && (!lastToken || typeof lastToken === "string" || lastToken.modifier || needsGrouping || token.prefix !== "")) { | ||
if (part.type === 2 /* kRegex */) { | ||
result += `(${part.value})`; | ||
} else if (part.type === 1 /* kSegmentWildcard */) { | ||
if (!customName) { | ||
result += `(${segmentWildcardRegex})`; | ||
} | ||
} else if (part.type === 0 /* kFullWildcard */) { | ||
if (!customName && (!lastPart || lastPart.type === 3 /* kFixed */ || lastPart.modifier !== 3 /* kNone */ || needsGrouping || part.prefix !== "")) { | ||
result += "*"; | ||
} else { | ||
result += `(${wildcardPattern})`; | ||
result += `(${kFullWildcardRegex2})`; | ||
} | ||
} else if (token.pattern === segmentWildcardPattern) { | ||
if (!customName) { | ||
result += `(${segmentWildcardPattern})`; | ||
} | ||
} else { | ||
result += `(${token.pattern})`; | ||
} | ||
if (token.pattern === segmentWildcardPattern && customName && token.suffix !== "") { | ||
if (regexIdentifierPart2.test(token.suffix[0])) { | ||
if (part.type === 1 /* kSegmentWildcard */ && customName && !!part.suffix.length) { | ||
if (regexIdentifierPart2.test(part.suffix[0])) { | ||
result += "\\"; | ||
} | ||
} | ||
result += escapePatternString(token.suffix); | ||
result += escapePatternString(part.suffix); | ||
if (needsGrouping) { | ||
result += "}"; | ||
} | ||
result += token.modifier; | ||
if (part.modifier !== 3 /* kNone */) { | ||
result += modifierToString(part.modifier); | ||
} | ||
} | ||
@@ -1026,4 +1182,5 @@ return result; | ||
this.regexp = {}; | ||
this.keys = {}; | ||
this.names = {}; | ||
this.component_pattern = {}; | ||
this.parts = {}; | ||
try { | ||
@@ -1076,3 +1233,3 @@ let baseURL = void 0; | ||
const pattern = this.pattern[component]; | ||
this.keys[component] = []; | ||
this.names[component] = []; | ||
switch (component) { | ||
@@ -1122,6 +1279,11 @@ case "protocol": | ||
try { | ||
const tokens = parse(pattern, options2); | ||
this.regexp[component] = tokensToRegexp(tokens, this.keys[component], options2); | ||
this.component_pattern[component] = tokensToPattern(tokens, options2); | ||
} catch { | ||
this.parts[component] = parse(pattern, options2); | ||
this.regexp[component] = partsToRegexp( | ||
this.parts[component], | ||
/* out */ | ||
this.names[component], | ||
options2 | ||
); | ||
this.component_pattern[component] = partsToPattern(this.parts[component], options2); | ||
} catch (err) { | ||
throw new TypeError(`invalid ${component} pattern '${this.pattern[component]}'.`); | ||
@@ -1207,10 +1369,10 @@ } | ||
let groups = {}; | ||
for (let [i, key] of this.keys[component].entries()) { | ||
if (typeof key.name === "string" || typeof key.name === "number") { | ||
for (let [i, name] of this.names[component].entries()) { | ||
if (typeof name === "string" || typeof name === "number") { | ||
let value = match[i + 1]; | ||
groups[key.name] = value; | ||
groups[name] = value; | ||
} | ||
} | ||
result[component] = { | ||
input: values[component] || "", | ||
input: values[component] ?? "", | ||
groups | ||
@@ -1221,2 +1383,39 @@ }; | ||
} | ||
static compareComponent(component, left, right) { | ||
const comparePart = (left2, right2) => { | ||
for (let attr of ["type", "modifier", "prefix", "value", "suffix"]) { | ||
if (left2[attr] < right2[attr]) | ||
return -1; | ||
else if (left2[attr] === right2[attr]) | ||
continue; | ||
else | ||
return 1; | ||
} | ||
return 0; | ||
}; | ||
const emptyFixedPart = new Part(3 /* kFixed */, "", "", "", "", 3 /* kNone */); | ||
const wildcardOnlyPart = new Part(0 /* kFullWildcard */, "", "", "", "", 3 /* kNone */); | ||
const comparePartList = (left2, right2) => { | ||
let i = 0; | ||
for (; i < Math.min(left2.length, right2.length); ++i) { | ||
let result = comparePart(left2[i], right2[i]); | ||
if (result) | ||
return result; | ||
} | ||
if (left2.length === right2.length) { | ||
return 0; | ||
} | ||
return comparePart(left2[i] ?? emptyFixedPart, right2[i] ?? emptyFixedPart); | ||
}; | ||
if (!left.component_pattern[component] && !right.component_pattern[component]) { | ||
return 0; | ||
} | ||
if (left.component_pattern[component] && !right.component_pattern[component]) { | ||
return comparePartList(left.parts[component], [wildcardOnlyPart]); | ||
} | ||
if (!left.component_pattern[component] && right.component_pattern[component]) { | ||
return comparePartList([wildcardOnlyPart], right.parts[component]); | ||
} | ||
return comparePartList(left.parts[component], right.parts[component]); | ||
} | ||
get protocol() { | ||
@@ -1223,0 +1422,0 @@ return this.component_pattern.protocol; |
{ | ||
"name": "urlpattern-polyfill", | ||
"version": "7.0.0", | ||
"version": "8.0.1", | ||
"description": "Polyfill for the URLPattern API", | ||
@@ -41,8 +41,8 @@ "repository": { | ||
"devDependencies": { | ||
"@ava/typescript": "^3.0.1", | ||
"ava": "^5.1.0", | ||
"esbuild": "^0.14.31", | ||
"rimraf": "^3.0.2", | ||
"typescript": "^4.7.2", | ||
"wireit": "^0.7.3" | ||
"@ava/typescript": "^4.0.0", | ||
"ava": "^5.2.0", | ||
"esbuild": "^0.17.18", | ||
"rimraf": "^5.0.0", | ||
"typescript": "^5.0.4", | ||
"wireit": "^0.9.5" | ||
}, | ||
@@ -65,2 +65,3 @@ "ava": { | ||
"build": "wireit", | ||
"sync-wpt": "wireit", | ||
"copyTypeFiles": "wireit", | ||
@@ -111,4 +112,7 @@ "prepFakeNodeModules": "wireit", | ||
}, | ||
"sync-wpt": { | ||
"command": "cd test && wget http://wpt.live/urlpattern/resources/urlpatterntestdata.json && wget http://wpt.live/urlpattern/resources/urlpattern-compare-test-data.json" | ||
}, | ||
"test": { | ||
"command": "ava --fail-fast -s", | ||
"command": "ava --timeout=60s", | ||
"watch": "test/**/*", | ||
@@ -115,0 +119,0 @@ "files": [ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
102626
2919