Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.
This commit is contained in:
21
node_modules/regex-utilities/LICENSE
generated
vendored
Normal file
21
node_modules/regex-utilities/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Steven Levithan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
78
node_modules/regex-utilities/README.md
generated
vendored
Normal file
78
node_modules/regex-utilities/README.md
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# regex-utilities
|
||||
|
||||
[](https://github.com/slevithan/regex-utilities/actions)
|
||||
[](https://www.npmjs.com/package/regex-utilities)
|
||||
[](https://bundlejs.com/?q=regex-utilities&treeshake=[*])
|
||||
|
||||
Tiny utilities that the [regex](https://github.com/slevithan/regex) library makes available for reuse in its plugins. Useful for parsing and processing regular expression syntax in a lightweight way, when you don't need a full regex AST.
|
||||
|
||||
## Constants
|
||||
|
||||
### `Context`
|
||||
|
||||
Frozen object with the following properties for tracking regex syntax context:
|
||||
|
||||
- `DEFAULT` - Base context.
|
||||
- `CHAR_CLASS` - Character class context.
|
||||
|
||||
## Functions
|
||||
|
||||
For all of the following functions, argument `expression` is the target string, and `needle` is the regex pattern to search for.
|
||||
|
||||
- Argument `expression` (the string being searched through) is assumed to be a flag-`v`-mode regex pattern string. In other words, nested character classes within it are supported when determining the context for a match.
|
||||
- Argument `needle` (the regex pattern being searched for) is provided as a string, and is applied with flags `su`.
|
||||
- If argument `context` is not provided, matches are allowed in all contexts. In other words, inside and outside of character classes.
|
||||
|
||||
### `replaceUnescaped`
|
||||
|
||||
*Arguments: `expression, needle, replacement, [context]`*
|
||||
|
||||
Replaces all unescaped instances of a regex pattern in the given context, using a replacement string or function.
|
||||
|
||||
<details>
|
||||
<summary>Examples with a replacement string</summary>
|
||||
|
||||
```js
|
||||
const str = '.\\.\\\\.[[\\.].].';
|
||||
replaceUnescaped(str, '\\.', '@');
|
||||
// → '@\\.\\\\@[[\\.]@]@'
|
||||
replaceUnescaped(str, '\\.', '@', Context.DEFAULT);
|
||||
// → '@\\.\\\\@[[\\.].]@'
|
||||
replaceUnescaped(str, '\\.', '@', Context.CHAR_CLASS);
|
||||
// → '.\\.\\\\.[[\\.]@].'
|
||||
```
|
||||
</details>
|
||||
|
||||
Details for the `replacement` argument:
|
||||
|
||||
- If a string is provided, it's used literally without special handling for backreferences, etc.
|
||||
- If a function is provided, it receives two arguments:
|
||||
1. The match object (which includes `groups`, `index`, etc.).
|
||||
2. An object with extended details (`context` and `negated`) about where the match was found.
|
||||
|
||||
### `execUnescaped`
|
||||
|
||||
*Arguments: `expression, needle, [pos = 0], [context]`*
|
||||
|
||||
Returns a match object for the first unescaped instance of a regex pattern in the given context, or `null`.
|
||||
|
||||
### `hasUnescaped`
|
||||
|
||||
*Arguments: `expression, needle, [context]`*
|
||||
|
||||
Checks whether an unescaped instance of a regex pattern appears in the given context.
|
||||
|
||||
### `forEachUnescaped`
|
||||
|
||||
*Arguments: `expression, needle, callback, [context]`*
|
||||
|
||||
Runs a function for each unescaped match of a regex pattern in the given context. The function receives two arguments:
|
||||
|
||||
1. The match object (which includes `groups`, `index`, etc.).
|
||||
2. An object with extended details (`context` and `negated`) about where the match was found.
|
||||
|
||||
### `getGroupContents`
|
||||
|
||||
*Arguments: `expression, contentsStartPos`*
|
||||
|
||||
Extracts the full contents of a group (subpattern) from the given expression, accounting for escaped characters, nested groups, and character classes. The group is identified by the position where its contents start (the string index just after the group's opening delimiter). Returns the rest of the string if the group is unclosed.
|
35
node_modules/regex-utilities/package.json
generated
vendored
Normal file
35
node_modules/regex-utilities/package.json
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "regex-utilities",
|
||||
"version": "2.3.0",
|
||||
"description": "Tiny helpers for processing regex syntax",
|
||||
"author": "Steven Levithan",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/index.d.ts",
|
||||
"import": "./src/index.js"
|
||||
}
|
||||
},
|
||||
"types": "./types/index.d.ts",
|
||||
"scripts": {
|
||||
"types": "tsc src/index.js --rootDir src --declaration --allowJs --emitDeclarationOnly --outdir types",
|
||||
"prebuild": "rm -rf types/*",
|
||||
"build": "npm run types",
|
||||
"pretest": "npm run build",
|
||||
"test": "jasmine",
|
||||
"prepare": "npm test"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"types"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/slevithan/regex-utilities.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jasmine": "^5.2.0",
|
||||
"typescript": "5.5.4"
|
||||
}
|
||||
}
|
170
node_modules/regex-utilities/src/index.js
generated
vendored
Normal file
170
node_modules/regex-utilities/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
// Constant properties for tracking regex syntax context
|
||||
export const Context = Object.freeze({
|
||||
DEFAULT: 'DEFAULT',
|
||||
CHAR_CLASS: 'CHAR_CLASS',
|
||||
});
|
||||
|
||||
/**
|
||||
Replaces all unescaped instances of a regex pattern in the given context, using a replacement
|
||||
string or callback.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {string | (match: RegExpExecArray, details: {
|
||||
context: 'DEFAULT' | 'CHAR_CLASS';
|
||||
negated: boolean;
|
||||
}) => string} replacement
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
@returns {string} Updated expression
|
||||
@example
|
||||
const str = '.\\.\\\\.[[\\.].].';
|
||||
replaceUnescaped(str, '\\.', '@');
|
||||
// → '@\\.\\\\@[[\\.]@]@'
|
||||
replaceUnescaped(str, '\\.', '@', Context.DEFAULT);
|
||||
// → '@\\.\\\\@[[\\.].]@'
|
||||
replaceUnescaped(str, '\\.', '@', Context.CHAR_CLASS);
|
||||
// → '.\\.\\\\.[[\\.]@].'
|
||||
*/
|
||||
export function replaceUnescaped(expression, needle, replacement, context) {
|
||||
const re = new RegExp(String.raw`${needle}|(?<$skip>\[\^?|\\?.)`, 'gsu');
|
||||
const negated = [false];
|
||||
let numCharClassesOpen = 0;
|
||||
let result = '';
|
||||
for (const match of expression.matchAll(re)) {
|
||||
const {0: m, groups: {$skip}} = match;
|
||||
if (!$skip && (!context || (context === Context.DEFAULT) === !numCharClassesOpen)) {
|
||||
if (replacement instanceof Function) {
|
||||
result += replacement(match, {
|
||||
context: numCharClassesOpen ? Context.CHAR_CLASS : Context.DEFAULT,
|
||||
negated: negated[negated.length - 1],
|
||||
});
|
||||
} else {
|
||||
result += replacement;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (m[0] === '[') {
|
||||
numCharClassesOpen++;
|
||||
negated.push(m[1] === '^');
|
||||
} else if (m === ']' && numCharClassesOpen) {
|
||||
numCharClassesOpen--;
|
||||
negated.pop();
|
||||
}
|
||||
result += m;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
Runs a callback for each unescaped instance of a regex pattern in the given context.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {(match: RegExpExecArray, details: {
|
||||
context: 'DEFAULT' | 'CHAR_CLASS';
|
||||
negated: boolean;
|
||||
}) => void} callback
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
*/
|
||||
export function forEachUnescaped(expression, needle, callback, context) {
|
||||
// Do this the easy way
|
||||
replaceUnescaped(expression, needle, callback, context);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a match object for the first unescaped instance of a regex pattern in the given context, or
|
||||
`null`.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {number} [pos] Offset to start the search
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
@returns {RegExpExecArray | null}
|
||||
*/
|
||||
export function execUnescaped(expression, needle, pos = 0, context) {
|
||||
// Quick partial test; avoid the loop if not needed
|
||||
if (!(new RegExp(needle, 'su').test(expression))) {
|
||||
return null;
|
||||
}
|
||||
const re = new RegExp(`${needle}|(?<$skip>\\\\?.)`, 'gsu');
|
||||
re.lastIndex = pos;
|
||||
let numCharClassesOpen = 0;
|
||||
let match;
|
||||
while (match = re.exec(expression)) {
|
||||
const {0: m, groups: {$skip}} = match;
|
||||
if (!$skip && (!context || (context === Context.DEFAULT) === !numCharClassesOpen)) {
|
||||
return match;
|
||||
}
|
||||
if (m === '[') {
|
||||
numCharClassesOpen++;
|
||||
} else if (m === ']' && numCharClassesOpen) {
|
||||
numCharClassesOpen--;
|
||||
}
|
||||
// Avoid an infinite loop on zero-length matches
|
||||
if (re.lastIndex == match.index) {
|
||||
re.lastIndex++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks whether an unescaped instance of a regex pattern appears in the given context.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
@returns {boolean} Whether the pattern was found
|
||||
*/
|
||||
export function hasUnescaped(expression, needle, context) {
|
||||
// Do this the easy way
|
||||
return !!execUnescaped(expression, needle, 0, context);
|
||||
}
|
||||
|
||||
/**
|
||||
Extracts the full contents of a group (subpattern) from the given expression, accounting for
|
||||
escaped characters, nested groups, and character classes. The group is identified by the position
|
||||
where its contents start (the string index just after the group's opening delimiter). Returns the
|
||||
rest of the string if the group is unclosed.
|
||||
|
||||
Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {number} contentsStartPos
|
||||
@returns {string}
|
||||
*/
|
||||
export function getGroupContents(expression, contentsStartPos) {
|
||||
const token = /\\?./gsu;
|
||||
token.lastIndex = contentsStartPos;
|
||||
let contentsEndPos = expression.length;
|
||||
let numCharClassesOpen = 0;
|
||||
// Starting search within an open group, after the group's opening
|
||||
let numGroupsOpen = 1;
|
||||
let match;
|
||||
while (match = token.exec(expression)) {
|
||||
const [m] = match;
|
||||
if (m === '[') {
|
||||
numCharClassesOpen++;
|
||||
} else if (!numCharClassesOpen) {
|
||||
if (m === '(') {
|
||||
numGroupsOpen++;
|
||||
} else if (m === ')') {
|
||||
numGroupsOpen--;
|
||||
if (!numGroupsOpen) {
|
||||
contentsEndPos = match.index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (m === ']') {
|
||||
numCharClassesOpen--;
|
||||
}
|
||||
}
|
||||
return expression.slice(contentsStartPos, contentsEndPos);
|
||||
}
|
84
node_modules/regex-utilities/types/index.d.ts
generated
vendored
Normal file
84
node_modules/regex-utilities/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
Replaces all unescaped instances of a regex pattern in the given context, using a replacement
|
||||
string or callback.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {string | (match: RegExpExecArray, details: {
|
||||
context: 'DEFAULT' | 'CHAR_CLASS';
|
||||
negated: boolean;
|
||||
}) => string} replacement
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
@returns {string} Updated expression
|
||||
@example
|
||||
const str = '.\\.\\\\.[[\\.].].';
|
||||
replaceUnescaped(str, '\\.', '@');
|
||||
// → '@\\.\\\\@[[\\.]@]@'
|
||||
replaceUnescaped(str, '\\.', '@', Context.DEFAULT);
|
||||
// → '@\\.\\\\@[[\\.].]@'
|
||||
replaceUnescaped(str, '\\.', '@', Context.CHAR_CLASS);
|
||||
// → '.\\.\\\\.[[\\.]@].'
|
||||
*/
|
||||
export function replaceUnescaped(expression: string, needle: string, replacement: string | ((match: RegExpExecArray, details: {
|
||||
context: "DEFAULT" | "CHAR_CLASS";
|
||||
negated: boolean;
|
||||
}) => string), context?: "DEFAULT" | "CHAR_CLASS"): string;
|
||||
/**
|
||||
Runs a callback for each unescaped instance of a regex pattern in the given context.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {(match: RegExpExecArray, details: {
|
||||
context: 'DEFAULT' | 'CHAR_CLASS';
|
||||
negated: boolean;
|
||||
}) => void} callback
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
*/
|
||||
export function forEachUnescaped(expression: string, needle: string, callback: (match: RegExpExecArray, details: {
|
||||
context: "DEFAULT" | "CHAR_CLASS";
|
||||
negated: boolean;
|
||||
}) => void, context?: "DEFAULT" | "CHAR_CLASS"): void;
|
||||
/**
|
||||
Returns a match object for the first unescaped instance of a regex pattern in the given context, or
|
||||
`null`.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {number} [pos] Offset to start the search
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
@returns {RegExpExecArray | null}
|
||||
*/
|
||||
export function execUnescaped(expression: string, needle: string, pos?: number, context?: "DEFAULT" | "CHAR_CLASS"): RegExpExecArray | null;
|
||||
/**
|
||||
Checks whether an unescaped instance of a regex pattern appears in the given context.
|
||||
|
||||
Doesn't skip over complete multicharacter tokens (only `\` plus its folowing char) so must be used
|
||||
with knowledge of what's safe to do given regex syntax. Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {string} needle Search as a regex pattern, with flags `su` applied
|
||||
@param {'DEFAULT' | 'CHAR_CLASS'} [context] All contexts if not specified
|
||||
@returns {boolean} Whether the pattern was found
|
||||
*/
|
||||
export function hasUnescaped(expression: string, needle: string, context?: "DEFAULT" | "CHAR_CLASS"): boolean;
|
||||
/**
|
||||
Extracts the full contents of a group (subpattern) from the given expression, accounting for
|
||||
escaped characters, nested groups, and character classes. The group is identified by the position
|
||||
where its contents start (the string index just after the group's opening delimiter). Returns the
|
||||
rest of the string if the group is unclosed.
|
||||
|
||||
Assumes UnicodeSets-mode syntax.
|
||||
@param {string} expression Search target
|
||||
@param {number} contentsStartPos
|
||||
@returns {string}
|
||||
*/
|
||||
export function getGroupContents(expression: string, contentsStartPos: number): string;
|
||||
export const Context: Readonly<{
|
||||
DEFAULT: "DEFAULT";
|
||||
CHAR_CLASS: "CHAR_CLASS";
|
||||
}>;
|
Reference in New Issue
Block a user