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:
469
node_modules/neotraverse/README.md
generated
vendored
Normal file
469
node_modules/neotraverse/README.md
generated
vendored
Normal file
@@ -0,0 +1,469 @@
|
||||
# neotraverse
|
||||
|
||||
Traverse and transform objects by visiting every node on a recursive walk. This is a fork and TypeScript rewrite of [traverse](https://github.com/ljharb/js-traverse) with 0 dependencies and major improvements:
|
||||
|
||||
- 🤌 1.38KB min+brotli
|
||||
- 🚥 Zero dependencies
|
||||
- 🎹 TypeScript. Throw away the `@types/traverse` package
|
||||
- ❎ No polyfills
|
||||
- 🛸 ESM-first
|
||||
- 📜 Legacy mode supporting ES5
|
||||
|
||||
# Principles
|
||||
|
||||
Rules this package aims to follow for an indefinite period of time:
|
||||
|
||||
- No dependencies.
|
||||
- No polyfills.
|
||||
- ESM-first.
|
||||
- Pushing to be modern
|
||||
- Always provide a legacy mode
|
||||
- Always follow `traverse` API. There already are many packages that do this. `neotraverse` intends to be a drop-in replacement for `traverse` and provide the same API with 0 dependencies and enhanced Developer Experience.
|
||||
- All deviating changes happen in `neotraverse/modern` build.
|
||||
|
||||
# Modern build
|
||||
|
||||
`neotraverse/modern` provides a new class `new Traverse()`, and all methods and state is provided as first argument `ctx` (`this.update -> ctx.update`, `this.isLeaf -> ctx.isLeaf`, etc.)
|
||||
|
||||
Before:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```js
|
||||
import { Traverse } from 'neotraverse/modern';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
new Traverse(obj).forEach((ctx, x) => {
|
||||
if (x < 0) ctx.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
# Which build to use?
|
||||
|
||||
`neotraverse` provides 3 builds:
|
||||
|
||||
- default: Backwards compatible with `traverse` and provides the same API, but ESM only and compiled to ES2022 with Node 18+
|
||||
- modern: Modern build with ESM only and compiled to ES2022 with Node 18+. Provides a new class `new Traverse()`, and all methods and state is provided as first argument `ctx` (`this.update -> ctx.update`, `this.isLeaf -> ctx.isLeaf`, etc.)
|
||||
- legacy: Legacy build with ES5 and CJS, compatible with `traverse` and provides the same API.
|
||||
|
||||
Here's a matrix of the different builds:
|
||||
|
||||
| Build | ESM | CJS | Browser | Node | Polyfills | Size |
|
||||
| ------- | --------- | --- | ------- | ---- | --------- | ----------------- |
|
||||
| default | ✅ ES2022 | | ✅ | ✅ | ❌ | 1.54KB min+brotli |
|
||||
| modern | ✅ ES2022 | | ✅ | ✅ | ❌ | 1.38KB min+brotli |
|
||||
| legacy | ✅ ES5 | ✅ | ✅ | ✅ | ❌ | 2.73KB min+brotli |
|
||||
|
||||
If you are:
|
||||
|
||||
## starting from scratch
|
||||
|
||||
```ts
|
||||
import { Traverse } from 'neotraverse/modern';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
new Traverse(obj).forEach((ctx, x) => {
|
||||
if (x < 0) ctx.update(x + 128); // `this` is same as `ctx` when using regular function
|
||||
});
|
||||
```
|
||||
|
||||
## migrating from `traverse`
|
||||
|
||||
### and you don't care about old browsers or Node versions:
|
||||
|
||||
Use default build for no breaking changes, and a modern build for better developer experience.
|
||||
|
||||
```ts
|
||||
import traverse from 'neotraverse';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
### and you care about old browsers or Node versions:
|
||||
|
||||
Use legacy build for compatibility with old browsers and Node versions.
|
||||
|
||||
```js
|
||||
const traverse = require('neotraverse/legacy');
|
||||
```
|
||||
|
||||
ESM:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse/legacy';
|
||||
```
|
||||
|
||||
# examples
|
||||
|
||||
## transform negative numbers in-place
|
||||
|
||||
negative.js
|
||||
|
||||
```js
|
||||
import { Traverse } from 'neotraverse/modern';
|
||||
const obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }];
|
||||
|
||||
new Traverse(obj).forEach(function (ctx, x) {
|
||||
if (x < 0) ctx.update(x + 128);
|
||||
});
|
||||
|
||||
console.dir(obj);
|
||||
```
|
||||
|
||||
or in legacy mode:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse';
|
||||
// OR import traverse from 'neotraverse/legacy';
|
||||
|
||||
const obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }];
|
||||
|
||||
traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
|
||||
// This is identical to the above
|
||||
traverse.forEach(obj, function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
|
||||
console.dir(obj);
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ]
|
||||
|
||||
## collect leaf nodes
|
||||
|
||||
leaves.js
|
||||
|
||||
```js
|
||||
import { Traverse } from 'neotraverse/modern';
|
||||
|
||||
const obj = {
|
||||
a: [1, 2, 3],
|
||||
b: 4,
|
||||
c: [5, 6],
|
||||
d: { e: [7, 8], f: 9 }
|
||||
};
|
||||
|
||||
const leaves = new Traverse(obj).reduce((ctx, acc, x) => {
|
||||
if (ctx.isLeaf) acc.push(x);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
console.dir(leaves);
|
||||
```
|
||||
|
||||
or in legacy mode:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse';
|
||||
// OR import traverse from 'neotraverse/legacy';
|
||||
|
||||
const obj = {
|
||||
a: [1, 2, 3],
|
||||
b: 4,
|
||||
c: [5, 6],
|
||||
d: { e: [7, 8], f: 9 }
|
||||
};
|
||||
|
||||
const leaves = traverse(obj).reduce(function (acc, x) {
|
||||
if (this.isLeaf) acc.push(x);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Equivalent to the above
|
||||
const leavesLegacy = traverse.reduce(
|
||||
obj,
|
||||
function (acc, x) {
|
||||
if (this.isLeaf) acc.push(x);
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
console.dir(leaves);
|
||||
console.dir(leavesLegacy);
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
|
||||
## scrub circular references
|
||||
|
||||
scrub.js:
|
||||
|
||||
```js
|
||||
import { Traverse } from 'neotraverse/modern';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
obj.c.push(obj);
|
||||
|
||||
const scrubbed = new Traverse(obj).map(function (ctx, x) {
|
||||
if (ctx.circular) ctx.remove();
|
||||
});
|
||||
|
||||
console.dir(scrubbed);
|
||||
```
|
||||
|
||||
or in legacy mode:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse';
|
||||
// OR import traverse from 'neotraverse/legacy';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
obj.c.push(obj);
|
||||
|
||||
const scrubbed = traverse(obj).map(function (x) {
|
||||
if (this.circular) this.remove();
|
||||
});
|
||||
|
||||
// Equivalent to the above
|
||||
const scrubbedLegacy = traverse.map(obj, function (x) {
|
||||
if (this.circular) this.remove();
|
||||
});
|
||||
|
||||
console.dir(scrubbed);
|
||||
console.dir(scrubbedLegacy);
|
||||
```
|
||||
|
||||
output:
|
||||
|
||||
{ a: 1, b: 2, c: [ 3, 4 ] }
|
||||
|
||||
## commonjs
|
||||
|
||||
neotraverse/legacy is compatible with commonjs and provides the same API as `traverse`, acting as a drop-in replacement:
|
||||
|
||||
```js
|
||||
const traverse = require('neotraverse/legacy');
|
||||
```
|
||||
|
||||
## esm
|
||||
|
||||
```js
|
||||
import { Traverse } from 'neotraverse/modern';
|
||||
```
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse';
|
||||
```
|
||||
|
||||
# Differences from `traverse`
|
||||
|
||||
- ESM-first
|
||||
- ES2022, Node 18+
|
||||
- Types included by default. No need to install `@types/traverse`
|
||||
- Works as-is in all major browsers and Deno
|
||||
- No polyfills
|
||||
- `new Traverse()` class instead of regular old `traverse()`
|
||||
- Legacy mode supporting `ES5` and `CJS`
|
||||
|
||||
There is a legacy mode that provides the same API as `traverse`, acting as a drop-in replacement:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
If you want to support really old browsers or NodeJS, supporting ES5, there's `neotraverse/legacy` which is compatible with ES5 and provides the same API as `traverse`, acting as a drop-in replacement for older browsers:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse/legacy';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
# Migrating from `traverse`
|
||||
|
||||
### Step 1: Install `neotraverse`
|
||||
|
||||
```sh
|
||||
npm install neotraverse
|
||||
npm uninstall traverse @types/traverse # Remove the old dependencies
|
||||
```
|
||||
|
||||
### Step 2: Replace `traverse` with `neotraverse`
|
||||
|
||||
```diff
|
||||
-import traverse from 'traverse';
|
||||
+import traverse from 'neotraverse';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
-traverse(obj).forEach(function (x) {
|
||||
+traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
Optionally, there's also a legacy mode that provides the same API as `traverse`, acting as a drop-in replacement:
|
||||
|
||||
```js
|
||||
import traverse from 'neotraverse/legacy';
|
||||
|
||||
const obj = { a: 1, b: 2, c: [3, 4] };
|
||||
|
||||
traverse(obj).forEach(function (x) {
|
||||
if (x < 0) this.update(x + 128);
|
||||
});
|
||||
```
|
||||
|
||||
### Step 3(Optional): Bundle time aliasing
|
||||
|
||||
If you use Vite, you can aliss `traverse` to `neotravers/legacy` in your `vite.config.js`:
|
||||
|
||||
```js
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
traverse: 'neotraverse' // or 'neotraverse/legacy'
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
# methods
|
||||
|
||||
Each method that takes an `fn` uses the context documented below in the context section.
|
||||
|
||||
## .map(fn)
|
||||
|
||||
Execute `fn` for each node in the object and return a new object with the results of the walk. To update nodes in the result use `ctx.update(value)`(modern) or `this.update(value)`(legacy).
|
||||
|
||||
## .forEach(fn)
|
||||
|
||||
Execute `fn` for each node in the object but unlike `.map()`, when `ctx.update()`(modern) or `this.update()`(legacy) is called it updates the object in-place.
|
||||
|
||||
## .reduce(fn, acc)
|
||||
|
||||
For each node in the object, perform a [left-fold](<http://en.wikipedia.org/wiki/Fold_(higher-order_function)>) with the return value of `fn(acc, node)`.
|
||||
|
||||
If `acc` isn't specified, `acc` is set to the root object for the first step and the root element is skipped.
|
||||
|
||||
## .paths()
|
||||
|
||||
Return an `Array` of every possible non-cyclic path in the object. Paths are `Array`s of string keys.
|
||||
|
||||
## .nodes()
|
||||
|
||||
Return an `Array` of every node in the object.
|
||||
|
||||
## .clone()
|
||||
|
||||
Create a deep clone of the object.
|
||||
|
||||
## .get(path)
|
||||
|
||||
Get the element at the array `path`.
|
||||
|
||||
## .set(path, value)
|
||||
|
||||
Set the element at the array `path` to `value`.
|
||||
|
||||
## .has(path)
|
||||
|
||||
Return whether the element at the array `path` exists.
|
||||
|
||||
# context
|
||||
|
||||
Each method that takes a callback has a context (its `ctx` object, or `this` object in legacy mode) with these attributes:
|
||||
|
||||
## this.node
|
||||
|
||||
The present node on the recursive walk
|
||||
|
||||
## this.path
|
||||
|
||||
An array of string keys from the root to the present node
|
||||
|
||||
## this.parent
|
||||
|
||||
The context of the node's parent. This is `undefined` for the root node.
|
||||
|
||||
## this.key
|
||||
|
||||
The name of the key of the present node in its parent. This is `undefined` for the root node.
|
||||
|
||||
## this.isRoot, this.notRoot
|
||||
|
||||
Whether the present node is the root node
|
||||
|
||||
## this.isLeaf, this.notLeaf
|
||||
|
||||
Whether or not the present node is a leaf node (has no children)
|
||||
|
||||
## this.level
|
||||
|
||||
Depth of the node within the traversal
|
||||
|
||||
## this.circular
|
||||
|
||||
If the node equals one of its parents, the `circular` attribute is set to the context of that parent and the traversal progresses no deeper.
|
||||
|
||||
## this.update(value, stopHere=false)
|
||||
|
||||
Set a new value for the present node.
|
||||
|
||||
All the elements in `value` will be recursively traversed unless `stopHere` is true.
|
||||
|
||||
## this.remove(stopHere=false)
|
||||
|
||||
Remove the current element from the output. If the node is in an Array it will be spliced off. Otherwise it will be deleted from its parent.
|
||||
|
||||
## this.delete(stopHere=false)
|
||||
|
||||
Delete the current element from its parent in the output. Calls `delete` even on Arrays.
|
||||
|
||||
## this.before(fn)
|
||||
|
||||
Call this function before any of the children are traversed.
|
||||
|
||||
You can assign into `ctx.keys`(modern) or `this.keys`(legacy) here to traverse in a custom order.
|
||||
|
||||
## this.after(fn)
|
||||
|
||||
Call this function after any of the children are traversed.
|
||||
|
||||
## this.pre(fn)
|
||||
|
||||
Call this function before each of the children are traversed.
|
||||
|
||||
## this.post(fn)
|
||||
|
||||
Call this function after each of the children are traversed.
|
||||
|
||||
# license
|
||||
|
||||
MIT
|
Reference in New Issue
Block a user