403 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			403 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, "__esModule", { value: true });
							 | 
						||
| 
								 | 
							
								exports.TokenData = void 0;
							 | 
						||
| 
								 | 
							
								exports.parse = parse;
							 | 
						||
| 
								 | 
							
								exports.compile = compile;
							 | 
						||
| 
								 | 
							
								exports.match = match;
							 | 
						||
| 
								 | 
							
								exports.pathToRegexp = pathToRegexp;
							 | 
						||
| 
								 | 
							
								exports.stringify = stringify;
							 | 
						||
| 
								 | 
							
								const DEFAULT_DELIMITER = "/";
							 | 
						||
| 
								 | 
							
								const NOOP_VALUE = (value) => value;
							 | 
						||
| 
								 | 
							
								const ID_START = /^[$_\p{ID_Start}]$/u;
							 | 
						||
| 
								 | 
							
								const ID_CONTINUE = /^[$\u200c\u200d\p{ID_Continue}]$/u;
							 | 
						||
| 
								 | 
							
								const DEBUG_URL = "https://git.new/pathToRegexpError";
							 | 
						||
| 
								 | 
							
								const SIMPLE_TOKENS = {
							 | 
						||
| 
								 | 
							
								    // Groups.
							 | 
						||
| 
								 | 
							
								    "{": "{",
							 | 
						||
| 
								 | 
							
								    "}": "}",
							 | 
						||
| 
								 | 
							
								    // Reserved.
							 | 
						||
| 
								 | 
							
								    "(": "(",
							 | 
						||
| 
								 | 
							
								    ")": ")",
							 | 
						||
| 
								 | 
							
								    "[": "[",
							 | 
						||
| 
								 | 
							
								    "]": "]",
							 | 
						||
| 
								 | 
							
								    "+": "+",
							 | 
						||
| 
								 | 
							
								    "?": "?",
							 | 
						||
| 
								 | 
							
								    "!": "!",
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Escape text for stringify to path.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function escapeText(str) {
							 | 
						||
| 
								 | 
							
								    return str.replace(/[{}()\[\]+?!:*]/g, "\\$&");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Escape a regular expression string.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function escape(str) {
							 | 
						||
| 
								 | 
							
								    return str.replace(/[.+*?^${}()[\]|/\\]/g, "\\$&");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Tokenize input string.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function* lexer(str) {
							 | 
						||
| 
								 | 
							
								    const chars = [...str];
							 | 
						||
| 
								 | 
							
								    let i = 0;
							 | 
						||
| 
								 | 
							
								    function name() {
							 | 
						||
| 
								 | 
							
								        let value = "";
							 | 
						||
| 
								 | 
							
								        if (ID_START.test(chars[++i])) {
							 | 
						||
| 
								 | 
							
								            value += chars[i];
							 | 
						||
| 
								 | 
							
								            while (ID_CONTINUE.test(chars[++i])) {
							 | 
						||
| 
								 | 
							
								                value += chars[i];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (chars[i] === '"') {
							 | 
						||
| 
								 | 
							
								            let pos = i;
							 | 
						||
| 
								 | 
							
								            while (i < chars.length) {
							 | 
						||
| 
								 | 
							
								                if (chars[++i] === '"') {
							 | 
						||
| 
								 | 
							
								                    i++;
							 | 
						||
| 
								 | 
							
								                    pos = 0;
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (chars[i] === "\\") {
							 | 
						||
| 
								 | 
							
								                    value += chars[++i];
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else {
							 | 
						||
| 
								 | 
							
								                    value += chars[i];
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (pos) {
							 | 
						||
| 
								 | 
							
								                throw new TypeError(`Unterminated quote at ${pos}: ${DEBUG_URL}`);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (!value) {
							 | 
						||
| 
								 | 
							
								            throw new TypeError(`Missing parameter name at ${i}: ${DEBUG_URL}`);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return value;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    while (i < chars.length) {
							 | 
						||
| 
								 | 
							
								        const value = chars[i];
							 | 
						||
| 
								 | 
							
								        const type = SIMPLE_TOKENS[value];
							 | 
						||
| 
								 | 
							
								        if (type) {
							 | 
						||
| 
								 | 
							
								            yield { type, index: i++, value };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (value === "\\") {
							 | 
						||
| 
								 | 
							
								            yield { type: "ESCAPED", index: i++, value: chars[i++] };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (value === ":") {
							 | 
						||
| 
								 | 
							
								            const value = name();
							 | 
						||
| 
								 | 
							
								            yield { type: "PARAM", index: i, value };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (value === "*") {
							 | 
						||
| 
								 | 
							
								            const value = name();
							 | 
						||
| 
								 | 
							
								            yield { type: "WILDCARD", index: i, value };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            yield { type: "CHAR", index: i, value: chars[i++] };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return { type: "END", index: i, value: "" };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								class Iter {
							 | 
						||
| 
								 | 
							
								    constructor(tokens) {
							 | 
						||
| 
								 | 
							
								        this.tokens = tokens;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    peek() {
							 | 
						||
| 
								 | 
							
								        if (!this._peek) {
							 | 
						||
| 
								 | 
							
								            const next = this.tokens.next();
							 | 
						||
| 
								 | 
							
								            this._peek = next.value;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return this._peek;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    tryConsume(type) {
							 | 
						||
| 
								 | 
							
								        const token = this.peek();
							 | 
						||
| 
								 | 
							
								        if (token.type !== type)
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        this._peek = undefined; // Reset after consumed.
							 | 
						||
| 
								 | 
							
								        return token.value;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    consume(type) {
							 | 
						||
| 
								 | 
							
								        const value = this.tryConsume(type);
							 | 
						||
| 
								 | 
							
								        if (value !== undefined)
							 | 
						||
| 
								 | 
							
								            return value;
							 | 
						||
| 
								 | 
							
								        const { type: nextType, index } = this.peek();
							 | 
						||
| 
								 | 
							
								        throw new TypeError(`Unexpected ${nextType} at ${index}, expected ${type}: ${DEBUG_URL}`);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    text() {
							 | 
						||
| 
								 | 
							
								        let result = "";
							 | 
						||
| 
								 | 
							
								        let value;
							 | 
						||
| 
								 | 
							
								        while ((value = this.tryConsume("CHAR") || this.tryConsume("ESCAPED"))) {
							 | 
						||
| 
								 | 
							
								            result += value;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Tokenized path instance.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								class TokenData {
							 | 
						||
| 
								 | 
							
								    constructor(tokens) {
							 | 
						||
| 
								 | 
							
								        this.tokens = tokens;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								exports.TokenData = TokenData;
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Parse a string for the raw tokens.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function parse(str, options = {}) {
							 | 
						||
| 
								 | 
							
								    const { encodePath = NOOP_VALUE } = options;
							 | 
						||
| 
								 | 
							
								    const it = new Iter(lexer(str));
							 | 
						||
| 
								 | 
							
								    function consume(endType) {
							 | 
						||
| 
								 | 
							
								        const tokens = [];
							 | 
						||
| 
								 | 
							
								        while (true) {
							 | 
						||
| 
								 | 
							
								            const path = it.text();
							 | 
						||
| 
								 | 
							
								            if (path)
							 | 
						||
| 
								 | 
							
								                tokens.push({ type: "text", value: encodePath(path) });
							 | 
						||
| 
								 | 
							
								            const param = it.tryConsume("PARAM");
							 | 
						||
| 
								 | 
							
								            if (param) {
							 | 
						||
| 
								 | 
							
								                tokens.push({
							 | 
						||
| 
								 | 
							
								                    type: "param",
							 | 
						||
| 
								 | 
							
								                    name: param,
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            const wildcard = it.tryConsume("WILDCARD");
							 | 
						||
| 
								 | 
							
								            if (wildcard) {
							 | 
						||
| 
								 | 
							
								                tokens.push({
							 | 
						||
| 
								 | 
							
								                    type: "wildcard",
							 | 
						||
| 
								 | 
							
								                    name: wildcard,
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            const open = it.tryConsume("{");
							 | 
						||
| 
								 | 
							
								            if (open) {
							 | 
						||
| 
								 | 
							
								                tokens.push({
							 | 
						||
| 
								 | 
							
								                    type: "group",
							 | 
						||
| 
								 | 
							
								                    tokens: consume("}"),
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            it.consume(endType);
							 | 
						||
| 
								 | 
							
								            return tokens;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const tokens = consume("END");
							 | 
						||
| 
								 | 
							
								    return new TokenData(tokens);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Compile a string to a template function for the path.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function compile(path, options = {}) {
							 | 
						||
| 
								 | 
							
								    const { encode = encodeURIComponent, delimiter = DEFAULT_DELIMITER } = options;
							 | 
						||
| 
								 | 
							
								    const data = path instanceof TokenData ? path : parse(path, options);
							 | 
						||
| 
								 | 
							
								    const fn = tokensToFunction(data.tokens, delimiter, encode);
							 | 
						||
| 
								 | 
							
								    return function path(data = {}) {
							 | 
						||
| 
								 | 
							
								        const [path, ...missing] = fn(data);
							 | 
						||
| 
								 | 
							
								        if (missing.length) {
							 | 
						||
| 
								 | 
							
								            throw new TypeError(`Missing parameters: ${missing.join(", ")}`);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return path;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function tokensToFunction(tokens, delimiter, encode) {
							 | 
						||
| 
								 | 
							
								    const encoders = tokens.map((token) => tokenToFunction(token, delimiter, encode));
							 | 
						||
| 
								 | 
							
								    return (data) => {
							 | 
						||
| 
								 | 
							
								        const result = [""];
							 | 
						||
| 
								 | 
							
								        for (const encoder of encoders) {
							 | 
						||
| 
								 | 
							
								            const [value, ...extras] = encoder(data);
							 | 
						||
| 
								 | 
							
								            result[0] += value;
							 | 
						||
| 
								 | 
							
								            result.push(...extras);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return result;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Convert a single token into a path building function.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function tokenToFunction(token, delimiter, encode) {
							 | 
						||
| 
								 | 
							
								    if (token.type === "text")
							 | 
						||
| 
								 | 
							
								        return () => [token.value];
							 | 
						||
| 
								 | 
							
								    if (token.type === "group") {
							 | 
						||
| 
								 | 
							
								        const fn = tokensToFunction(token.tokens, delimiter, encode);
							 | 
						||
| 
								 | 
							
								        return (data) => {
							 | 
						||
| 
								 | 
							
								            const [value, ...missing] = fn(data);
							 | 
						||
| 
								 | 
							
								            if (!missing.length)
							 | 
						||
| 
								 | 
							
								                return [value];
							 | 
						||
| 
								 | 
							
								            return [""];
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const encodeValue = encode || NOOP_VALUE;
							 | 
						||
| 
								 | 
							
								    if (token.type === "wildcard" && encode !== false) {
							 | 
						||
| 
								 | 
							
								        return (data) => {
							 | 
						||
| 
								 | 
							
								            const value = data[token.name];
							 | 
						||
| 
								 | 
							
								            if (value == null)
							 | 
						||
| 
								 | 
							
								                return ["", token.name];
							 | 
						||
| 
								 | 
							
								            if (!Array.isArray(value) || value.length === 0) {
							 | 
						||
| 
								 | 
							
								                throw new TypeError(`Expected "${token.name}" to be a non-empty array`);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return [
							 | 
						||
| 
								 | 
							
								                value
							 | 
						||
| 
								 | 
							
								                    .map((value, index) => {
							 | 
						||
| 
								 | 
							
								                    if (typeof value !== "string") {
							 | 
						||
| 
								 | 
							
								                        throw new TypeError(`Expected "${token.name}/${index}" to be a string`);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    return encodeValue(value);
							 | 
						||
| 
								 | 
							
								                })
							 | 
						||
| 
								 | 
							
								                    .join(delimiter),
							 | 
						||
| 
								 | 
							
								            ];
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return (data) => {
							 | 
						||
| 
								 | 
							
								        const value = data[token.name];
							 | 
						||
| 
								 | 
							
								        if (value == null)
							 | 
						||
| 
								 | 
							
								            return ["", token.name];
							 | 
						||
| 
								 | 
							
								        if (typeof value !== "string") {
							 | 
						||
| 
								 | 
							
								            throw new TypeError(`Expected "${token.name}" to be a string`);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return [encodeValue(value)];
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Transform a path into a match function.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function match(path, options = {}) {
							 | 
						||
| 
								 | 
							
								    const { decode = decodeURIComponent, delimiter = DEFAULT_DELIMITER } = options;
							 | 
						||
| 
								 | 
							
								    const { regexp, keys } = pathToRegexp(path, options);
							 | 
						||
| 
								 | 
							
								    const decoders = keys.map((key) => {
							 | 
						||
| 
								 | 
							
								        if (decode === false)
							 | 
						||
| 
								 | 
							
								            return NOOP_VALUE;
							 | 
						||
| 
								 | 
							
								        if (key.type === "param")
							 | 
						||
| 
								 | 
							
								            return decode;
							 | 
						||
| 
								 | 
							
								        return (value) => value.split(delimiter).map(decode);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    return function match(input) {
							 | 
						||
| 
								 | 
							
								        const m = regexp.exec(input);
							 | 
						||
| 
								 | 
							
								        if (!m)
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        const path = m[0];
							 | 
						||
| 
								 | 
							
								        const params = Object.create(null);
							 | 
						||
| 
								 | 
							
								        for (let i = 1; i < m.length; i++) {
							 | 
						||
| 
								 | 
							
								            if (m[i] === undefined)
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            const key = keys[i - 1];
							 | 
						||
| 
								 | 
							
								            const decoder = decoders[i - 1];
							 | 
						||
| 
								 | 
							
								            params[key.name] = decoder(m[i]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return { path, params };
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function pathToRegexp(path, options = {}) {
							 | 
						||
| 
								 | 
							
								    const { delimiter = DEFAULT_DELIMITER, end = true, sensitive = false, trailing = true, } = options;
							 | 
						||
| 
								 | 
							
								    const keys = [];
							 | 
						||
| 
								 | 
							
								    const sources = [];
							 | 
						||
| 
								 | 
							
								    const flags = sensitive ? "" : "i";
							 | 
						||
| 
								 | 
							
								    const paths = Array.isArray(path) ? path : [path];
							 | 
						||
| 
								 | 
							
								    const items = paths.map((path) => path instanceof TokenData ? path : parse(path, options));
							 | 
						||
| 
								 | 
							
								    for (const { tokens } of items) {
							 | 
						||
| 
								 | 
							
								        for (const seq of flatten(tokens, 0, [])) {
							 | 
						||
| 
								 | 
							
								            const regexp = sequenceToRegExp(seq, delimiter, keys);
							 | 
						||
| 
								 | 
							
								            sources.push(regexp);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    let pattern = `^(?:${sources.join("|")})`;
							 | 
						||
| 
								 | 
							
								    if (trailing)
							 | 
						||
| 
								 | 
							
								        pattern += `(?:${escape(delimiter)}$)?`;
							 | 
						||
| 
								 | 
							
								    pattern += end ? "$" : `(?=${escape(delimiter)}|$)`;
							 | 
						||
| 
								 | 
							
								    const regexp = new RegExp(pattern, flags);
							 | 
						||
| 
								 | 
							
								    return { regexp, keys };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Generate a flat list of sequence tokens from the given tokens.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function* flatten(tokens, index, init) {
							 | 
						||
| 
								 | 
							
								    if (index === tokens.length) {
							 | 
						||
| 
								 | 
							
								        return yield init;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const token = tokens[index];
							 | 
						||
| 
								 | 
							
								    if (token.type === "group") {
							 | 
						||
| 
								 | 
							
								        const fork = init.slice();
							 | 
						||
| 
								 | 
							
								        for (const seq of flatten(token.tokens, 0, fork)) {
							 | 
						||
| 
								 | 
							
								            yield* flatten(tokens, index + 1, seq);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        init.push(token);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    yield* flatten(tokens, index + 1, init);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Transform a flat sequence of tokens into a regular expression.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function sequenceToRegExp(tokens, delimiter, keys) {
							 | 
						||
| 
								 | 
							
								    let result = "";
							 | 
						||
| 
								 | 
							
								    let backtrack = "";
							 | 
						||
| 
								 | 
							
								    let isSafeSegmentParam = true;
							 | 
						||
| 
								 | 
							
								    for (let i = 0; i < tokens.length; i++) {
							 | 
						||
| 
								 | 
							
								        const token = tokens[i];
							 | 
						||
| 
								 | 
							
								        if (token.type === "text") {
							 | 
						||
| 
								 | 
							
								            result += escape(token.value);
							 | 
						||
| 
								 | 
							
								            backtrack += token.value;
							 | 
						||
| 
								 | 
							
								            isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(delimiter));
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (token.type === "param" || token.type === "wildcard") {
							 | 
						||
| 
								 | 
							
								            if (!isSafeSegmentParam && !backtrack) {
							 | 
						||
| 
								 | 
							
								                throw new TypeError(`Missing text after "${token.name}": ${DEBUG_URL}`);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (token.type === "param") {
							 | 
						||
| 
								 | 
							
								                result += `(${negate(delimiter, isSafeSegmentParam ? "" : backtrack)}+)`;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                result += `([\\s\\S]+)`;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            keys.push(token);
							 | 
						||
| 
								 | 
							
								            backtrack = "";
							 | 
						||
| 
								 | 
							
								            isSafeSegmentParam = false;
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return result;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function negate(delimiter, backtrack) {
							 | 
						||
| 
								 | 
							
								    if (backtrack.length < 2) {
							 | 
						||
| 
								 | 
							
								        if (delimiter.length < 2)
							 | 
						||
| 
								 | 
							
								            return `[^${escape(delimiter + backtrack)}]`;
							 | 
						||
| 
								 | 
							
								        return `(?:(?!${escape(delimiter)})[^${escape(backtrack)}])`;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (delimiter.length < 2) {
							 | 
						||
| 
								 | 
							
								        return `(?:(?!${escape(backtrack)})[^${escape(delimiter)}])`;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return `(?:(?!${escape(backtrack)}|${escape(delimiter)})[\\s\\S])`;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Stringify token data into a path string.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function stringify(data) {
							 | 
						||
| 
								 | 
							
								    return data.tokens
							 | 
						||
| 
								 | 
							
								        .map(function stringifyToken(token, index, tokens) {
							 | 
						||
| 
								 | 
							
								        if (token.type === "text")
							 | 
						||
| 
								 | 
							
								            return escapeText(token.value);
							 | 
						||
| 
								 | 
							
								        if (token.type === "group") {
							 | 
						||
| 
								 | 
							
								            return `{${token.tokens.map(stringifyToken).join("")}}`;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const isSafe = isNameSafe(token.name) && isNextNameSafe(tokens[index + 1]);
							 | 
						||
| 
								 | 
							
								        const key = isSafe ? token.name : JSON.stringify(token.name);
							 | 
						||
| 
								 | 
							
								        if (token.type === "param")
							 | 
						||
| 
								 | 
							
								            return `:${key}`;
							 | 
						||
| 
								 | 
							
								        if (token.type === "wildcard")
							 | 
						||
| 
								 | 
							
								            return `*${key}`;
							 | 
						||
| 
								 | 
							
								        throw new TypeError(`Unexpected token: ${token}`);
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								        .join("");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function isNameSafe(name) {
							 | 
						||
| 
								 | 
							
								    const [first, ...rest] = name;
							 | 
						||
| 
								 | 
							
								    if (!ID_START.test(first))
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    return rest.every((char) => ID_CONTINUE.test(char));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function isNextNameSafe(token) {
							 | 
						||
| 
								 | 
							
								    if ((token === null || token === void 0 ? void 0 : token.type) !== "text")
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    return !ID_CONTINUE.test(token.value[0]);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								//# sourceMappingURL=index.js.map
							 |