Backend half

This commit is contained in:
2025-07-11 19:56:28 +02:00
parent fa868e7c1d
commit 8600fa7c1d
19426 changed files with 3750448 additions and 8108 deletions
+19 -200
View File
@@ -1,216 +1,35 @@
# Path-to-RegExp
> Turn a path string such as `/user/:name` into a regular expression.
Turn an Express-style path string such as `/user/:name` into a regular expression.
[![NPM version][npm-image]][npm-url]
[![NPM downloads][downloads-image]][downloads-url]
[![Build status][build-image]][build-url]
[![Build coverage][coverage-image]][coverage-url]
[![License][license-image]][license-url]
## Installation
```
npm install path-to-regexp --save
```
**Note:** This is a legacy branch. You should upgrade to `1.x`.
## Usage
```js
const {
match,
pathToRegexp,
compile,
parse,
stringify,
} = require("path-to-regexp");
```javascript
var pathToRegexp = require('path-to-regexp');
```
### Parameters
### pathToRegexp(path, keys, options)
Parameters match arbitrary strings in a path by matching up to the end of the segment, or up to any proceeding tokens. They are defined by prefixing a colon to the parameter name (`:foo`). Parameter names can use any valid JavaScript identifier, or be double quoted to use other characters (`:"param-name"`).
- **path** A string in the express format, an array of such strings, or a regular expression
- **keys** An array to be populated with the keys present in the url. Once the function completes, this will be an array of strings.
- **options**
- **options.sensitive** Defaults to false, set this to true to make routes case sensitive
- **options.strict** Defaults to false, set this to true to make the trailing slash matter.
- **options.end** Defaults to true, set this to false to only match the prefix of the URL.
```js
const fn = match("/:foo/:bar");
fn("/test/route");
//=> { path: '/test/route', params: { foo: 'test', bar: 'route' } }
```javascript
var keys = [];
var exp = pathToRegexp('/foo/:bar', keys);
//keys = ['bar']
//exp = /^\/foo\/(?:([^\/]+?))\/?$/i
```
### Wildcard
## Live Demo
Wildcard parameters match one or more characters across multiple segments. They are defined the same way as regular parameters, but are prefixed with an asterisk (`*foo`).
```js
const fn = match("/*splat");
fn("/bar/baz");
//=> { path: '/bar/baz', params: { splat: [ 'bar', 'baz' ] } }
```
### Optional
Braces can be used to define parts of the path that are optional.
```js
const fn = match("/users{/:id}/delete");
fn("/users/delete");
//=> { path: '/users/delete', params: {} }
fn("/users/123/delete");
//=> { path: '/users/123/delete', params: { id: '123' } }
```
## Match
The `match` function returns a function for matching strings against a path:
- **path** String or array of strings.
- **options** _(optional)_ (Extends [pathToRegexp](#pathToRegexp) options)
- **decode** Function for decoding strings to params, or `false` to disable all processing. (default: `decodeURIComponent`)
```js
const fn = match("/foo/:bar");
```
**Please note:** `path-to-regexp` is intended for ordered data (e.g. paths, hosts). It can not handle arbitrarily ordered data (e.g. query strings, URL fragments, JSON, etc).
## PathToRegexp
The `pathToRegexp` function returns a regular expression for matching strings against paths. It
- **path** String or array of strings.
- **options** _(optional)_ (See [parse](#parse) for more options)
- **sensitive** Regexp will be case sensitive. (default: `false`)
- **end** Validate the match reaches the end of the string. (default: `true`)
- **delimiter** The default delimiter for segments, e.g. `[^/]` for `:named` parameters. (default: `'/'`)
- **trailing** Allows optional trailing delimiter to match. (default: `true`)
```js
const { regexp, keys } = pathToRegexp("/foo/:bar");
```
## Compile ("Reverse" Path-To-RegExp)
The `compile` function will return a function for transforming parameters into a valid path:
- **path** A string.
- **options** (See [parse](#parse) for more options)
- **delimiter** The default delimiter for segments, e.g. `[^/]` for `:named` parameters. (default: `'/'`)
- **encode** Function for encoding input strings for output into the path, or `false` to disable entirely. (default: `encodeURIComponent`)
```js
const toPath = compile("/user/:id");
toPath({ id: "name" }); //=> "/user/name"
toPath({ id: "café" }); //=> "/user/caf%C3%A9"
const toPathRepeated = compile("/*segment");
toPathRepeated({ segment: ["foo"] }); //=> "/foo"
toPathRepeated({ segment: ["a", "b", "c"] }); //=> "/a/b/c"
// When disabling `encode`, you need to make sure inputs are encoded correctly. No arrays are accepted.
const toPathRaw = compile("/user/:id", { encode: false });
toPathRaw({ id: "%3A%2F" }); //=> "/user/%3A%2F"
```
## Stringify
Transform `TokenData` (a sequence of tokens) back into a Path-to-RegExp string.
- **data** A `TokenData` instance
```js
const data = new TokenData([
{ type: "text", value: "/" },
{ type: "param", name: "foo" },
]);
const path = stringify(data); //=> "/:foo"
```
## Developers
- If you are rewriting paths with match and compile, consider using `encode: false` and `decode: false` to keep raw paths passed around.
- To ensure matches work on paths containing characters usually encoded, such as emoji, consider using [encodeurl](https://github.com/pillarjs/encodeurl) for `encodePath`.
### Parse
The `parse` function accepts a string and returns `TokenData`, the set of tokens and other metadata parsed from the input string. `TokenData` is can used with `match` and `compile`.
- **path** A string.
- **options** _(optional)_
- **encodePath** A function for encoding input strings. (default: `x => x`, recommended: [`encodeurl`](https://github.com/pillarjs/encodeurl))
### Tokens
`TokenData` is a sequence of tokens, currently of types `text`, `parameter`, `wildcard`, or `group`.
### Custom path
In some applications, you may not be able to use the `path-to-regexp` syntax, but still want to use this library for `match` and `compile`. For example:
```js
import { TokenData, match } from "path-to-regexp";
const tokens = [
{ type: "text", value: "/" },
{ type: "parameter", name: "foo" },
];
const path = new TokenData(tokens);
const fn = match(path);
fn("/test"); //=> { path: '/test', index: 0, params: { foo: 'test' } }
```
## Errors
An effort has been made to ensure ambiguous paths from previous releases throw an error. This means you might be seeing an error when things worked before.
### Unexpected `?` or `+`
In past releases, `?`, `*`, and `+` were used to denote optional or repeating parameters. As an alternative, try these:
- For optional (`?`), use an empty segment in a group such as `/:file{.:ext}`.
- For repeating (`+`), only wildcard matching is supported, such as `/*path`.
- For optional repeating (`*`), use a group and a wildcard parameter such as `/files{/*path}`.
### Unexpected `(`, `)`, `[`, `]`, etc.
Previous versions of Path-to-RegExp used these for RegExp features. This version no longer supports them so they've been reserved to avoid ambiguity. To use these characters literally, escape them with a backslash, e.g. `"\\("`.
### Missing parameter name
Parameter names must be provided after `:` or `*`, and they must be a valid JavaScript identifier. If you want an parameter name that isn't a JavaScript identifier, such as starting with a number, you can wrap the name in quotes like `:"my-name"`.
### Unterminated quote
Parameter names can be wrapped in double quote characters, and this error means you forgot to close the quote character.
### Express <= 4.x
Path-To-RegExp breaks compatibility with Express <= `4.x` in the following ways:
- The wildcard `*` must have a name, matching the behavior of parameters `:`.
- The optional character `?` is no longer supported, use braces instead: `/:file{.:ext}`.
- Regexp characters are not supported.
- Some characters have been reserved to avoid confusion during upgrade (`()[]?+!`).
- Parameter names now support valid JavaScript identifiers, or quoted like `:"this"`.
You can see a live demo of this library in use at [express-route-tester](http://forbeslindesay.github.com/express-route-tester/).
## License
MIT
[npm-image]: https://img.shields.io/npm/v/path-to-regexp
[npm-url]: https://npmjs.org/package/path-to-regexp
[downloads-image]: https://img.shields.io/npm/dm/path-to-regexp
[downloads-url]: https://npmjs.org/package/path-to-regexp
[build-image]: https://img.shields.io/github/actions/workflow/status/pillarjs/path-to-regexp/ci.yml?branch=master
[build-url]: https://github.com/pillarjs/path-to-regexp/actions/workflows/ci.yml?query=branch%3Amaster
[coverage-image]: https://img.shields.io/codecov/c/gh/pillarjs/path-to-regexp
[coverage-url]: https://codecov.io/gh/pillarjs/path-to-regexp
[license-image]: http://img.shields.io/npm/l/path-to-regexp.svg?style=flat
[license-url]: LICENSE.md
MIT
-136
View File
@@ -1,136 +0,0 @@
/**
* Encode a string into another string.
*/
export type Encode = (value: string) => string;
/**
* Decode a string into another string.
*/
export type Decode = (value: string) => string;
export interface ParseOptions {
/**
* A function for encoding input strings.
*/
encodePath?: Encode;
}
export interface PathToRegexpOptions {
/**
* Matches the path completely without trailing characters. (default: `true`)
*/
end?: boolean;
/**
* Allows optional trailing delimiter to match. (default: `true`)
*/
trailing?: boolean;
/**
* Match will be case sensitive. (default: `false`)
*/
sensitive?: boolean;
/**
* The default delimiter for segments. (default: `'/'`)
*/
delimiter?: string;
}
export interface MatchOptions extends PathToRegexpOptions {
/**
* Function for decoding strings for params, or `false` to disable entirely. (default: `decodeURIComponent`)
*/
decode?: Decode | false;
}
export interface CompileOptions {
/**
* Function for encoding input strings for output into the path, or `false` to disable entirely. (default: `encodeURIComponent`)
*/
encode?: Encode | false;
/**
* The default delimiter for segments. (default: `'/'`)
*/
delimiter?: string;
}
/**
* Plain text.
*/
export interface Text {
type: "text";
value: string;
}
/**
* A parameter designed to match arbitrary text within a segment.
*/
export interface Parameter {
type: "param";
name: string;
}
/**
* A wildcard parameter designed to match multiple segments.
*/
export interface Wildcard {
type: "wildcard";
name: string;
}
/**
* A set of possible tokens to expand when matching.
*/
export interface Group {
type: "group";
tokens: Token[];
}
/**
* A token that corresponds with a regexp capture.
*/
export type Key = Parameter | Wildcard;
/**
* A sequence of `path-to-regexp` keys that match capturing groups.
*/
export type Keys = Array<Key>;
/**
* A sequence of path match characters.
*/
export type Token = Text | Parameter | Wildcard | Group;
/**
* Tokenized path instance.
*/
export declare class TokenData {
readonly tokens: Token[];
constructor(tokens: Token[]);
}
/**
* Parse a string for the raw tokens.
*/
export declare function parse(str: string, options?: ParseOptions): TokenData;
/**
* Compile a string to a template function for the path.
*/
export declare function compile<P extends ParamData = ParamData>(path: Path, options?: CompileOptions & ParseOptions): (data?: P) => string;
export type ParamData = Partial<Record<string, string | string[]>>;
export type PathFunction<P extends ParamData> = (data?: P) => string;
/**
* A match result contains data about the path match.
*/
export interface MatchResult<P extends ParamData> {
path: string;
params: P;
}
/**
* A match is either `false` (no match) or a match result.
*/
export type Match<P extends ParamData> = false | MatchResult<P>;
/**
* The match function takes a string and returns whether it matched the path.
*/
export type MatchFunction<P extends ParamData> = (path: string) => Match<P>;
/**
* Supported path types.
*/
export type Path = string | TokenData;
/**
* Transform a path into a match function.
*/
export declare function match<P extends ParamData>(path: Path | Path[], options?: MatchOptions & ParseOptions): MatchFunction<P>;
export declare function pathToRegexp(path: Path | Path[], options?: PathToRegexpOptions & ParseOptions): {
regexp: RegExp;
keys: Keys;
};
/**
* Stringify token data into a path string.
*/
export declare function stringify(data: TokenData): string;
-403
View File
@@ -1,403 +0,0 @@
"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
File diff suppressed because one or more lines are too long
+156
View File
@@ -0,0 +1,156 @@
/**
* Expose `pathToRegexp`.
*/
module.exports = pathToRegexp;
/**
* Match matching groups in a regular expression.
*/
var MATCHING_GROUP_REGEXP = /\\.|\((?:\?<(.*?)>)?(?!\?)/g;
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Object} options
* @return {RegExp}
* @api private
*/
function pathToRegexp(path, keys, options) {
options = options || {};
keys = keys || [];
var strict = options.strict;
var end = options.end !== false;
var flags = options.sensitive ? '' : 'i';
var lookahead = options.lookahead !== false;
var extraOffset = 0;
var keysOffset = keys.length;
var i = 0;
var name = 0;
var pos = 0;
var backtrack = '';
var m;
if (path instanceof RegExp) {
while (m = MATCHING_GROUP_REGEXP.exec(path.source)) {
if (m[0][0] === '\\') continue;
keys.push({
name: m[1] || name++,
optional: false,
offset: m.index
});
}
return path;
}
if (Array.isArray(path)) {
// Map array parts into regexps and return their source. We also pass
// the same keys and options instance into every generation to get
// consistent matching groups before we join the sources together.
path = path.map(function (value) {
return pathToRegexp(value, keys, options).source;
});
return new RegExp(path.join('|'), flags);
}
if (typeof path !== 'string') {
throw new TypeError('path must be a string, array of strings, or regular expression');
}
path = path.replace(
/\\.|(\/)?(\.)?:(\w+)(\(.*?\))?(\*)?(\?)?|[.*]|\/\(/g,
function (match, slash, format, key, capture, star, optional, offset) {
if (match[0] === '\\') {
backtrack += match;
pos += 2;
return match;
}
if (match === '.') {
backtrack += '\\.';
extraOffset += 1;
pos += 1;
return '\\.';
}
if (slash || format) {
backtrack = '';
} else {
backtrack += path.slice(pos, offset);
}
pos = offset + match.length;
if (match === '*') {
extraOffset += 3;
return '(.*)';
}
if (match === '/(') {
backtrack += '/';
extraOffset += 2;
return '/(?:';
}
slash = slash || '';
format = format ? '\\.' : '';
optional = optional || '';
capture = capture ?
capture.replace(/\\.|\*/, function (m) { return m === '*' ? '(.*)' : m; }) :
(backtrack ? '((?:(?!/|' + backtrack + ').)+?)' : '([^/' + format + ']+?)');
keys.push({
name: key,
optional: !!optional,
offset: offset + extraOffset
});
var result = '(?:'
+ format + slash + capture
+ (star ? '((?:[/' + format + '].+?)?)' : '')
+ ')'
+ optional;
extraOffset += result.length - match.length;
return result;
});
// This is a workaround for handling unnamed matching groups.
while (m = MATCHING_GROUP_REGEXP.exec(path)) {
if (m[0][0] === '\\') continue;
if (keysOffset + i === keys.length || keys[keysOffset + i].offset > m.index) {
keys.splice(keysOffset + i, 0, {
name: name++, // Unnamed matching groups must be consistently linear.
optional: false,
offset: m.index
});
}
i++;
}
path += strict ? '' : path[path.length - 1] === '/' ? '?' : '/?';
// If the path is non-ending, match until the end or a slash.
if (end) {
path += '$';
} else if (path[path.length - 1] !== '/') {
path += lookahead ? '(?=/|$)' : '(?:/|$)';
}
return new RegExp('^' + path, flags);
};
+17 -49
View File
@@ -1,62 +1,30 @@
{
"name": "path-to-regexp",
"version": "8.2.0",
"description": "Express style path to RegExp utility",
"version": "0.1.12",
"files": [
"index.js",
"LICENSE"
],
"scripts": {
"test": "istanbul cover _mocha -- -R spec"
},
"keywords": [
"express",
"regexp",
"route",
"routing"
"regexp"
],
"component": {
"scripts": {
"path-to-regexp": "index.js"
}
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/pillarjs/path-to-regexp.git"
},
"license": "MIT",
"exports": "./dist/index.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"dist/"
],
"scripts": {
"bench": "vitest bench",
"build": "ts-scripts build",
"format": "ts-scripts format",
"lint": "ts-scripts lint",
"prepare": "ts-scripts install && npm run build",
"size": "size-limit",
"specs": "ts-scripts specs",
"test": "ts-scripts test && npm run size"
},
"devDependencies": {
"@borderless/ts-scripts": "^0.15.0",
"@size-limit/preset-small-lib": "^11.1.2",
"@types/node": "^22.7.2",
"@types/semver": "^7.3.1",
"@vitest/coverage-v8": "^2.1.1",
"recheck": "^4.4.5",
"size-limit": "^11.1.2",
"typescript": "^5.5.3"
},
"engines": {
"node": ">=16"
},
"publishConfig": {
"access": "public"
},
"size-limit": [
{
"path": "dist/index.js",
"limit": "2.2 kB"
}
],
"ts-scripts": {
"dist": [
"dist"
],
"project": [
"tsconfig.build.json"
]
"mocha": "^1.17.1",
"istanbul": "^0.2.6"
}
}