diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
index 1ac41a5..8459f3a 100644
--- a/.github/workflows/cd.yml
+++ b/.github/workflows/cd.yml
@@ -6,7 +6,7 @@ on:
types:
- completed
branches:
- - master
+ - main
jobs:
publish:
@@ -27,15 +27,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: "20"
+ node-version: "24"
cache: "npm"
- registry-url: https://registry.npmjs.org
- cache-dependency-path: package-lock.json
- env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install dependencies
- run: npm install
+ run: npm ci
- name: Build the project
run: npm run build
@@ -43,5 +39,5 @@ jobs:
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+ NPM_CONFIG_PROVENANCE: true
run: npx semantic-release
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 40f02cf..82ca421 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,10 +3,10 @@ name: CI Pipeline
on:
push:
branches:
- - master
+ - main
pull_request:
branches:
- - master
+ - main
jobs:
build:
@@ -19,23 +19,11 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: "20"
+ node-version: "24"
cache: "npm"
- registry-url: https://registry.npmjs.org
- cache-dependency-path: package-lock.json
-
- - name: Retrieve dependencies
- id: "modules_cache"
- uses: actions/cache@v4
- with:
- path: node_modules
- key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- restore-keys: |
- node-modules-${{ runner.os }}-
- name: Install dependencies
- if: steps.modules_cache.outputs.cache-hit != 'true'
- run: npm install
+ run: npm ci
- name: Run typescript
run: npm run tsc
diff --git a/README.md b/README.md
index 2433cbd..a5449eb 100644
--- a/README.md
+++ b/README.md
@@ -516,6 +516,216 @@ diff.on("finish", () => console.log("Your data has been processed. The full diff
diff.on("error", (err) => console.log(err))
```
+
+
+### getTextDiff
+
+```js
+import { getTextDiff } from "@donedeal0/superdiff";
+```
+
+Compares two texts and returns a diff for each characters, words or sentence, depending on your preference.
+
+The output is optimized by default to produce a readable, visual diff (like GitHub or Git). A strict mode that tracks exact token moves and updates is also available.
+
+All language subtleties (Unicode, CJK scripts, locale-aware sentence segmentation, etc.) are handled.
+
+#### FORMAT
+
+**Input**
+
+```ts
+ previousText: string | null | undefined,
+ currentText: string | null | undefined,
+ options?: {
+ showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default.
+ separation?: "character" | "word" | "sentence", // "word" by default
+ mode?: "visual" | "strict", // "visual" by default
+ ignoreCase?: boolean, // false by default
+ ignorePunctuation?: boolean, // false by default
+ locale?: Intl.Locale | string // english by default
+ }
+```
+- `previousText`: the original text.
+- `currentText`: the new text.
+- `options`
+ - `showOnly` gives you the option to return only the values whose status you are interested in (e.g. `["added", "equal"]`).
+ - `moved` and `updated` are only available in `strict` mode.
+ - `separation` whether you want a `character`, `word` or `sentence` based diff.
+ - `mode`:
+ - `visual` (default): optimized for readability. Token moves are ignored so insertions don’t cascade and break equality (recommended for UI diffing).
+ - `strict`: tracks token moves exactly. Semantically precise, but noisier (a simple addition will move all the next tokens, breaking equality).
+ - `ignoreCase`: if set to `true` `hello` and `HELLO` will be considered equal.
+ - `ignorePunctuation`: if set to `true` `hello!` and `hello` will be considered equal.
+ - `locale`: the locale of your text.
+
+**Output**
+
+```ts
+type TextDiff = {
+ type: "text";
+ status: "added" | "deleted" | "equal" | "updated";
+ diff: {
+ value: string;
+ previousValue?: string
+ status: "added" | "deleted" | "equal" | "moved" | "updated";
+ currentIndex: number | null;
+ previousIndex: number | null;
+ }[];
+};
+```
+
+#### USAGE
+
+**VISUAL MODE**
+
+`visual` is optimized for readability. Token moves are ignored so insertions don’t cascade and break equality (recommended for UI diffing). Token updates are rendered as two `added` and `deleted` entries.
+
+This mode is based on a [longest common subsequence (LCS) computation](https://en.wikipedia.org/wiki/Longest_common_subsequence), similar to Git and GitHub diffs.
+
+**Input**
+
+```diff
+getTextDiff(
+- "The brown fox jumped high",
++ "The orange cat has jumped",
+{ mode: "visual", separation: "word" }
+);
+```
+
+**Output**
+
+```diff
+{
+ type: "text",
++ status: "updated",
+ diff: [
+ {
+ value: 'The',
+ status: 'equal',
+ currentIndex: 0,
+ previousIndex: 0
+ },
+- {
+- value: "brown",
+- status: "deleted",
+- currentIndex: null,
+- previousIndex: 1,
+- }
+- {
+- value: "fox",
+- status: "deleted",
+- currentIndex: null,
+- previousIndex: 2,
+- }
++ {
++ value: "orange",
++ status: "added",
++ currentIndex: 1,
++ previousIndex: null,
++ },
++ {
++ value: "cat",
++ status: "added",
++ currentIndex: 2,
++ previousIndex: null,
++ },
++ {
++ value: "has",
++ status: "added",
++ currentIndex: 3,
++ previousIndex: null,
++ },
+ {
+ value: "jumped",
+ status: "equal",
+ currentIndex: 4,
+ previousIndex: 3,
+ },
+- {
+- value: "high",
+- status: "deleted",
+- currentIndex: null,
+- previousIndex: 4,
+- }
+ ],
+ }
+```
+
+**STRICT MODE**
+
+`strict` tracks token moves exactly. Semantically precise, but noisier (a simple addition will move all the next tokens, breaking equality). It also considers direct token swaps as `updated`.
+
+**Input**
+
+```diff
+getTextDiff(
+- "The brown fox jumped high",
++ "The orange cat has jumped",
+{ mode: "strict", separation: "word" }
+);
+```
+
+**Output**
+
+```diff
+{
+ type: "text",
++ status: "updated",
+ diff: [
+ {
+ value: 'The',
+ status: 'equal',
+ currentIndex: 0,
+ previousIndex: 0
+ },
++ {
++ value: "orange",
++ previousValue: "brown",
++ status: "updated",
++ currentIndex: 1,
++ previousIndex: null,
++ },
++ {
++ value: "cat",
++ previousValue: "fox",
++ status: "updated",
++ currentIndex: 2,
++ previousIndex: null,
++ },
++ {
++ value: "has",
++ status: "added",
++ currentIndex: 3,
++ previousIndex: null,
++ },
++ {
++ value: "jumped",
++ status: "moved",
++ currentIndex: 4,
++ previousIndex: 3,
++ },
+- {
+- value: "high",
+- status: "deleted",
+- currentIndex: null,
+- previousIndex: 4,
+- }
+ ],
+ }
+```
+
+#### TOKEN STATUSES
+
+| Status | Represents | Index meaning |
+| ------- | ------------- | --------------------------------------- |
+| **equal** | same token | both indexes valid |
+| **added** | new token | `previousIndex = null` |
+| **deleted** | removed token | `currentIndex = null` |
+| **moved** | same token (only in `strict` mode) | both indexes valid |
+| **updated** | replacement (only in `strict` mode) | no shared identity, one index only |
+
+
### isEqual
diff --git a/benchmark/texts.ts b/benchmark/texts.ts
new file mode 100644
index 0000000..1301750
--- /dev/null
+++ b/benchmark/texts.ts
@@ -0,0 +1,41 @@
+import * as Diff from "diff";
+import { getTextDiff } from "../src";
+import { bench } from "./utils";
+
+export function generateText(wordCount: number, mutate = false): string {
+ const baseWords = [];
+ for (let i = 0; i < wordCount; i++) {
+ baseWords.push(`word${i}`);
+ }
+ if (!mutate) return baseWords.join(" ");
+ const mutated = [...baseWords];
+ mutated[100] = "changed_word";
+ mutated.splice(500, 0, "inserted_word");
+ mutated.splice(800, 1);
+
+ return mutated.join(" ");
+}
+
+export function runTextBench10K() {
+ const prev = generateText(10_000);
+ const curr = generateText(10_000, true);
+ console.log("\nText diff – 10k words");
+
+ const diff = bench("diff", 1, () => Diff.diffWords(prev, curr));
+ const superdiff = bench("Superdiff", 1, () => {
+ getTextDiff(prev, curr, { separation: "word", mode: "strict" });
+ });
+ return { superdiff, diff };
+}
+
+export function runTextBench100K() {
+ const prev = generateText(100_000);
+ const curr = generateText(100_000, true);
+ console.log("\nText diff – 100k words");
+
+ const diff = bench("diff", 1, () => Diff.diffWords(prev, curr));
+ const superdiff = bench("Superdiff", 1, () => {
+ getTextDiff(prev, curr, { separation: "word", mode: "visual" });
+ });
+ return { superdiff, diff };
+}
diff --git a/package-lock.json b/package-lock.json
index cd3a46e..20d944f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"blob-polyfill": "^9.0.20240710",
"deep-diff": "^1.0.2",
"deep-object-diff": "^1.1.9",
+ "diff": "^8.0.2",
"eslint": "^9.21.0",
"husky": "^9.1.7",
"jest": "^29.7.0",
@@ -146,7 +147,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -618,6 +618,7 @@
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
"dev": true,
"optional": true,
+ "peer": true,
"engines": {
"node": ">=0.1.90"
}
@@ -732,7 +733,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
},
@@ -756,7 +756,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -2951,6 +2950,7 @@
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
@@ -2990,7 +2990,6 @@
"integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@octokit/auth-token": "^6.0.0",
"@octokit/graphql": "^9.0.3",
@@ -3537,6 +3536,7 @@
"resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.0.tgz",
"integrity": "sha512-KtXWczvTAB1ZFZ6B4O+w8HkfYm/OgQb1dUGNFZtDgQ0csggrmkq8sTxhd+lwGF8kMb59/RnG9o4Tn7M/I8dQ9Q==",
"dev": true,
+ "peer": true,
"dependencies": {
"conventional-changelog-angular": "^8.0.0",
"conventional-changelog-writer": "^8.0.0",
@@ -4261,6 +4261,7 @@
"resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.1.tgz",
"integrity": "sha512-K0w+5220TM4HZTthE5dDpIuFrnkN1NfTGPidJFm04ULT1DEZ9WG89VNXN7F0c+6nMEpWgqmPvb7vY7JkB2jyyA==",
"dev": true,
+ "peer": true,
"dependencies": {
"conventional-changelog-angular": "^8.0.0",
"conventional-changelog-writer": "^8.0.0",
@@ -4285,6 +4286,7 @@
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz",
"integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=16"
},
@@ -4304,6 +4306,7 @@
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=10"
},
@@ -4338,7 +4341,6 @@
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.25"
@@ -4758,8 +4760,7 @@
"version": "18.11.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==",
- "dev": true,
- "peer": true
+ "dev": true
},
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
@@ -4771,7 +4772,8 @@
"version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@types/stack-utils": {
"version": "2.0.3",
@@ -4849,7 +4851,6 @@
"integrity": "sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.52.0",
"@typescript-eslint/types": "8.52.0",
@@ -5079,6 +5080,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
"integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/helper-numbers": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
@@ -5088,25 +5090,29 @@
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
"integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
"integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.11.6",
"@webassemblyjs/helper-api-error": "1.11.6",
@@ -5117,13 +5123,15 @@
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
"integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-buffer": "1.12.1",
@@ -5136,6 +5144,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
"integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
"dev": true,
+ "peer": true,
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
@@ -5145,6 +5154,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
"integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@xtuc/long": "4.2.2"
}
@@ -5153,13 +5163,15 @@
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
"integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-buffer": "1.12.1",
@@ -5176,6 +5188,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
"integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
@@ -5189,6 +5202,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
"integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-buffer": "1.12.1",
@@ -5201,6 +5215,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
"integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-api-error": "1.11.6",
@@ -5215,6 +5230,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
"integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.12.1",
"@xtuc/long": "4.2.2"
@@ -5224,13 +5240,15 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/abab": {
"version": "2.0.6",
@@ -5246,7 +5264,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5270,6 +5287,7 @@
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
"dev": true,
+ "peer": true,
"peerDependencies": {
"acorn": "^8"
}
@@ -5324,7 +5342,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -5341,6 +5358,7 @@
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true,
+ "peer": true,
"peerDependencies": {
"ajv": "^6.9.1"
}
@@ -5375,6 +5393,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
+ "peer": true,
"dependencies": {
"color-convert": "^1.9.0"
},
@@ -5419,7 +5438,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz",
"integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/arr-diff": {
"version": "4.0.0",
@@ -5435,7 +5455,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
"integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/asynckit": {
"version": "0.4.0",
@@ -5703,7 +5724,6 @@
"url": "https://github.com/sponsors/ai"
}
],
- "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001663",
"electron-to-chromium": "^1.5.28",
@@ -5816,6 +5836,7 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@@ -5855,6 +5876,7 @@
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=6.0"
}
@@ -5896,6 +5918,7 @@
"resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz",
"integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==",
"dev": true,
+ "peer": true,
"dependencies": {
"chalk": "^4.0.0",
"highlight.js": "^10.7.1",
@@ -5917,6 +5940,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
+ "peer": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -5932,6 +5956,7 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
+ "peer": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -5948,6 +5973,7 @@
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
@@ -5959,6 +5985,7 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -5970,13 +5997,15 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/cli-highlight/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -5986,6 +6015,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
+ "peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -5998,6 +6028,7 @@
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
+ "peer": true,
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
@@ -6016,6 +6047,7 @@
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=10"
}
@@ -6025,6 +6057,7 @@
"resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz",
"integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"string-width": "^4.2.0"
},
@@ -6072,6 +6105,7 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
+ "peer": true,
"dependencies": {
"color-name": "1.1.3"
}
@@ -6080,7 +6114,8 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
@@ -6109,6 +6144,7 @@
"resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz",
"integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==",
"dev": true,
+ "peer": true,
"dependencies": {
"array-ify": "^1.0.0",
"dot-prop": "^5.1.0"
@@ -6152,6 +6188,7 @@
"resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz",
"integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==",
"dev": true,
+ "peer": true,
"dependencies": {
"compare-func": "^2.0.0"
},
@@ -6164,6 +6201,7 @@
"resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.0.0.tgz",
"integrity": "sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/semver": "^7.5.5",
"conventional-commits-filter": "^5.0.0",
@@ -6183,6 +6221,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
},
@@ -6195,6 +6234,7 @@
"resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz",
"integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -6204,6 +6244,7 @@
"resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz",
"integrity": "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==",
"dev": true,
+ "peer": true,
"dependencies": {
"meow": "^13.0.0"
},
@@ -6219,6 +6260,7 @@
"resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz",
"integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -6237,13 +6279,15 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/cosmiconfig": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
"integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
"dev": true,
+ "peer": true,
"dependencies": {
"env-paths": "^2.2.1",
"import-fresh": "^3.3.0",
@@ -6585,10 +6629,11 @@
}
},
"node_modules/diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz",
+ "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==",
"dev": true,
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
@@ -6634,6 +6679,7 @@
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
"integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
"dev": true,
+ "peer": true,
"dependencies": {
"is-obj": "^2.0.0"
},
@@ -6661,6 +6707,7 @@
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
"dev": true,
+ "peer": true,
"dependencies": {
"readable-stream": "^2.0.2"
}
@@ -6700,13 +6747,15 @@
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz",
"integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
"dev": true,
+ "peer": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -6881,6 +6930,7 @@
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=6"
}
@@ -6890,6 +6940,7 @@
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
"integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -6930,7 +6981,8 @@
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
@@ -6968,7 +7020,6 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
- "peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -7018,6 +7069,7 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=0.8.0"
}
@@ -7050,7 +7102,6 @@
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -7342,6 +7393,7 @@
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=0.8.x"
}
@@ -7498,6 +7550,7 @@
"resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz",
"integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -7510,6 +7563,7 @@
"resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz",
"integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==",
"dev": true,
+ "peer": true,
"dependencies": {
"semver-regex": "^4.0.5",
"super-regex": "^1.0.0"
@@ -7602,6 +7656,7 @@
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
"integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==",
"dev": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.1",
"readable-stream": "^2.0.0"
@@ -7658,6 +7713,7 @@
"resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz",
"integrity": "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -7763,6 +7819,7 @@
"resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz",
"integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"argv-formatter": "~1.0.0",
"spawn-error-forwarder": "~1.0.0",
@@ -7809,7 +7866,8 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "2.0.2",
@@ -7874,6 +7932,7 @@
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"minimist": "^1.2.5",
"neo-async": "^2.6.2",
@@ -7895,6 +7954,7 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -7946,6 +8006,7 @@
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
"dev": true,
+ "peer": true,
"engines": {
"node": "*"
}
@@ -7955,6 +8016,7 @@
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz",
"integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==",
"dev": true,
+ "peer": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@@ -7967,6 +8029,7 @@
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
"integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
"dev": true,
+ "peer": true,
"dependencies": {
"lru-cache": "^10.0.1"
},
@@ -7978,7 +8041,8 @@
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/html-encoding-sniffer": {
"version": "4.0.0",
@@ -8118,6 +8182,7 @@
"resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-1.3.4.tgz",
"integrity": "sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg==",
"dev": true,
+ "peer": true,
"dependencies": {
"debug": "^4.3.4",
"import-meta-resolve": "^4.0.0"
@@ -8151,6 +8216,7 @@
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
"integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
"dev": true,
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
@@ -8215,6 +8281,7 @@
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz",
"integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==",
"dev": true,
+ "peer": true,
"dependencies": {
"from2": "^2.3.0",
"p-is-promise": "^3.0.0"
@@ -8302,6 +8369,7 @@
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -8352,7 +8420,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/isexe": {
"version": "2.0.0",
@@ -11631,7 +11700,8 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
@@ -11747,6 +11817,7 @@
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
"dev": true,
+ "peer": true,
"dependencies": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
@@ -11762,6 +11833,7 @@
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
"dev": true,
+ "peer": true,
"dependencies": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
@@ -11775,6 +11847,7 @@
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -11794,6 +11867,7 @@
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=6.11.5"
}
@@ -11942,6 +12016,7 @@
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.1.0.tgz",
"integrity": "sha512-+pvwa14KZL74MVXjYdPR3nSInhGhNvPce/3mqLVZT2oUvt654sL1XImFuLZ1pkA866IYZ3ikDTOFUIC7XzpZZg==",
"dev": true,
+ "peer": true,
"dependencies": {
"ansi-escapes": "^7.0.0",
"chalk": "^5.3.0",
@@ -11962,6 +12037,7 @@
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
"integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
"dev": true,
+ "peer": true,
"dependencies": {
"environment": "^1.0.0"
},
@@ -11977,6 +12053,7 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
"integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"dev": true,
+ "peer": true,
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
@@ -11999,6 +12076,7 @@
"resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
"integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -12140,7 +12218,8 @@
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/nerf-dart": {
"version": "1.0.0",
@@ -12153,6 +12232,7 @@
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz",
"integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@sindresorhus/is": "^4.6.0",
"char-regex": "^1.0.2",
@@ -12181,6 +12261,7 @@
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
"integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
"dev": true,
+ "peer": true,
"dependencies": {
"hosted-git-info": "^7.0.0",
"semver": "^7.3.5",
@@ -12195,6 +12276,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
},
@@ -14242,7 +14324,6 @@
"dev": true,
"inBundle": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -14438,6 +14519,7 @@
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz",
"integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -14465,6 +14547,7 @@
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz",
"integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -14596,13 +14679,15 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/parse5-htmlparser2-tree-adapter": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
"dev": true,
+ "peer": true,
"dependencies": {
"parse5": "^6.0.1"
}
@@ -14611,7 +14696,8 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/path-exists": {
"version": "4.0.0",
@@ -14709,6 +14795,7 @@
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -14728,6 +14815,7 @@
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
"integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==",
"dev": true,
+ "peer": true,
"dependencies": {
"find-up": "^2.0.0",
"load-json-file": "^4.0.0"
@@ -14741,6 +14829,7 @@
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"locate-path": "^2.0.0"
},
@@ -14753,6 +14842,7 @@
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
"dev": true,
+ "peer": true,
"dependencies": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
@@ -14766,6 +14856,7 @@
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"dev": true,
+ "peer": true,
"dependencies": {
"p-try": "^1.0.0"
},
@@ -14778,6 +14869,7 @@
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
"dev": true,
+ "peer": true,
"dependencies": {
"p-limit": "^1.1.0"
},
@@ -14790,6 +14882,7 @@
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -14799,6 +14892,7 @@
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -14962,7 +15056,8 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/prompts": {
"version": "2.4.2",
@@ -15035,6 +15130,7 @@
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"safe-buffer": "^5.1.0"
}
@@ -15075,6 +15171,7 @@
"resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
"integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"find-up-simple": "^1.0.0",
"read-pkg": "^9.0.0",
@@ -15092,6 +15189,7 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz",
"integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=16"
},
@@ -15104,6 +15202,7 @@
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz",
"integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/normalize-package-data": "^2.4.3",
"normalize-package-data": "^6.0.0",
@@ -15123,6 +15222,7 @@
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.1.0.tgz",
"integrity": "sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.22.13",
"index-to-position": "^0.1.2",
@@ -15140,6 +15240,7 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz",
"integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=16"
},
@@ -15152,6 +15253,7 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dev": true,
+ "peer": true,
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -15323,7 +15425,8 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/safer-buffer": {
"version": "2.1.2",
@@ -15349,6 +15452,7 @@
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
@@ -15411,7 +15515,8 @@
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz",
"integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/semantic-release/node_modules/@octokit/plugin-paginate-rest": {
"version": "13.2.1",
@@ -15419,6 +15524,7 @@
"integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@octokit/types": "^15.0.1"
},
@@ -15435,6 +15541,7 @@
"integrity": "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@octokit/openapi-types": "^26.0.0"
}
@@ -15444,6 +15551,7 @@
"resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz",
"integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -15454,6 +15562,7 @@
"integrity": "sha512-ctDzdSMrT3H+pwKBPdyCPty6Y47X8dSrjd3aPZ5KKIKKWTwZBE9De8GtsH3TyAlw3Uyo2stegMx6rJMXKpJwJA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@octokit/core": "^7.0.0",
"@octokit/plugin-paginate-rest": "^13.0.0",
@@ -15485,6 +15594,7 @@
"integrity": "sha512-+M9/Lb35IgnlUO6OSJ40Ie+hUsZLuph2fqXC/qrKn0fMvUU/jiCjpoL6zEm69vzcmaZJ8yNKtMBEKHWN49WBbQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@semantic-release/error": "^4.0.0",
"aggregate-error": "^5.0.0",
@@ -15512,6 +15622,7 @@
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
"integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -15524,6 +15635,7 @@
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz",
"integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==",
"dev": true,
+ "peer": true,
"dependencies": {
"clean-stack": "^5.2.0",
"indent-string": "^5.0.0"
@@ -15540,6 +15652,7 @@
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz",
"integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"escape-string-regexp": "5.0.0"
},
@@ -15555,6 +15668,7 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -15567,6 +15681,7 @@
"resolved": "https://registry.npmjs.org/execa/-/execa-9.4.0.tgz",
"integrity": "sha512-yKHlle2YGxZE842MERVIplWwNH5VYmqqcPFgtnlU//K8gxuFFXu0pwd/CrfXTumFpeEiufsP7+opT/bPJa1yVw==",
"dev": true,
+ "peer": true,
"dependencies": {
"@sindresorhus/merge-streams": "^4.0.0",
"cross-spawn": "^7.0.3",
@@ -15593,6 +15708,7 @@
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@sec-ant/readable-stream": "^0.4.1",
"is-stream": "^4.0.1"
@@ -15609,6 +15725,7 @@
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.0.0.tgz",
"integrity": "sha512-4nw3vOVR+vHUOT8+U4giwe2tcGv+R3pwwRidUe67DoMBTjhrfr6rZYJVVwdkBE+Um050SG+X9tf0Jo4fOpn01w==",
"dev": true,
+ "peer": true,
"dependencies": {
"lru-cache": "^10.0.1"
},
@@ -15621,6 +15738,7 @@
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
"integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18.18.0"
}
@@ -15630,6 +15748,7 @@
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
"integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -15642,6 +15761,7 @@
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -15653,7 +15773,8 @@
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/semantic-release/node_modules/npm": {
"version": "10.9.4",
@@ -15731,6 +15852,7 @@
],
"dev": true,
"license": "Artistic-2.0",
+ "peer": true,
"workspaces": [
"docs",
"smoke-tests",
@@ -15821,6 +15943,7 @@
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
"integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
"dev": true,
+ "peer": true,
"dependencies": {
"path-key": "^4.0.0",
"unicorn-magic": "^0.3.0"
@@ -18103,7 +18226,6 @@
"dev": true,
"inBundle": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -18360,6 +18482,7 @@
"resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz",
"integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -18372,6 +18495,7 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -18384,6 +18508,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
},
@@ -18396,6 +18521,7 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=14"
},
@@ -18408,6 +18534,7 @@
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
"integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -18420,6 +18547,7 @@
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -18442,6 +18570,7 @@
"resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz",
"integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==",
"dev": true,
+ "peer": true,
"dependencies": {
"semver": "^7.3.5"
},
@@ -18457,6 +18586,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
},
@@ -18469,6 +18599,7 @@
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz",
"integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -18481,6 +18612,7 @@
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
+ "peer": true,
"dependencies": {
"randombytes": "^2.1.0"
}
@@ -18517,6 +18649,7 @@
"resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz",
"integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==",
"dev": true,
+ "peer": true,
"dependencies": {
"chalk": "^2.3.2",
"figures": "^2.0.0",
@@ -18531,6 +18664,7 @@
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==",
"dev": true,
+ "peer": true,
"dependencies": {
"escape-string-regexp": "^1.0.5"
},
@@ -18550,6 +18684,7 @@
"resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz",
"integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==",
"dev": true,
+ "peer": true,
"dependencies": {
"unicode-emoji-modifier-base": "^1.0.0"
},
@@ -18591,7 +18726,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz",
"integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/spdx-correct": {
"version": "3.2.0",
@@ -18630,6 +18766,7 @@
"resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz",
"integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==",
"dev": true,
+ "peer": true,
"dependencies": {
"through2": "~2.0.0"
}
@@ -18669,6 +18806,7 @@
"resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
"integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==",
"dev": true,
+ "peer": true,
"dependencies": {
"duplexer2": "~0.1.0",
"readable-stream": "^2.0.2"
@@ -18679,6 +18817,7 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
+ "peer": true,
"dependencies": {
"safe-buffer": "~5.1.0"
}
@@ -18810,6 +18949,7 @@
"resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz",
"integrity": "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==",
"dev": true,
+ "peer": true,
"dependencies": {
"function-timeout": "^1.0.1",
"time-span": "^5.1.0"
@@ -18826,6 +18966,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
+ "peer": true,
"dependencies": {
"has-flag": "^3.0.0"
},
@@ -18838,6 +18979,7 @@
"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz",
"integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==",
"dev": true,
+ "peer": true,
"dependencies": {
"has-flag": "^4.0.0",
"supports-color": "^7.0.0"
@@ -18854,6 +18996,7 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -18863,6 +19006,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
+ "peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -18920,6 +19064,7 @@
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=6"
}
@@ -18980,6 +19125,7 @@
"resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz",
"integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -18998,6 +19144,7 @@
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
"dev": true,
+ "peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.20",
"jest-worker": "^27.4.5",
@@ -19032,6 +19179,7 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -19041,6 +19189,7 @@
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -19055,6 +19204,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
+ "peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -19069,13 +19219,15 @@
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/terser/node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
+ "peer": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
@@ -19144,6 +19296,7 @@
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
@@ -19154,6 +19307,7 @@
"resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz",
"integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==",
"dev": true,
+ "peer": true,
"dependencies": {
"convert-hrtime": "^5.0.0"
},
@@ -19212,7 +19366,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -19290,6 +19443,7 @@
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz",
"integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">= 0.4"
},
@@ -19331,7 +19485,6 @@
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -19370,6 +19523,16 @@
}
}
},
+ "node_modules/ts-node/node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/tsup": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz",
@@ -19439,7 +19602,6 @@
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
@@ -19454,6 +19616,456 @@
"fsevents": "~2.3.3"
}
},
+ "node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
+ "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/android-arm": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
+ "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/android-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
+ "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/android-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
+ "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
+ "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
+ "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
+ "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-arm": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
+ "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
+ "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
+ "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
+ "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
+ "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
+ "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
+ "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
+ "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
+ "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
+ "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
+ "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
+ "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
+ "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
+ "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/win32-x64": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
+ "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/esbuild": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
+ "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.2",
+ "@esbuild/android-arm": "0.27.2",
+ "@esbuild/android-arm64": "0.27.2",
+ "@esbuild/android-x64": "0.27.2",
+ "@esbuild/darwin-arm64": "0.27.2",
+ "@esbuild/darwin-x64": "0.27.2",
+ "@esbuild/freebsd-arm64": "0.27.2",
+ "@esbuild/freebsd-x64": "0.27.2",
+ "@esbuild/linux-arm": "0.27.2",
+ "@esbuild/linux-arm64": "0.27.2",
+ "@esbuild/linux-ia32": "0.27.2",
+ "@esbuild/linux-loong64": "0.27.2",
+ "@esbuild/linux-mips64el": "0.27.2",
+ "@esbuild/linux-ppc64": "0.27.2",
+ "@esbuild/linux-riscv64": "0.27.2",
+ "@esbuild/linux-s390x": "0.27.2",
+ "@esbuild/linux-x64": "0.27.2",
+ "@esbuild/netbsd-arm64": "0.27.2",
+ "@esbuild/netbsd-x64": "0.27.2",
+ "@esbuild/openbsd-arm64": "0.27.2",
+ "@esbuild/openbsd-x64": "0.27.2",
+ "@esbuild/openharmony-arm64": "0.27.2",
+ "@esbuild/sunos-x64": "0.27.2",
+ "@esbuild/win32-arm64": "0.27.2",
+ "@esbuild/win32-ia32": "0.27.2",
+ "@esbuild/win32-x64": "0.27.2"
+ }
+ },
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
@@ -19505,7 +20117,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -19551,6 +20162,7 @@
"integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
"dev": true,
"optional": true,
+ "peer": true,
"bin": {
"uglifyjs": "bin/uglifyjs"
},
@@ -19573,6 +20185,7 @@
"resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz",
"integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -19582,6 +20195,7 @@
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
"integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -19683,7 +20297,8 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
@@ -19743,6 +20358,7 @@
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
"dev": true,
+ "peer": true,
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -19781,6 +20397,7 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz",
"integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/estree": "^1.0.5",
"@webassemblyjs/ast": "^1.12.1",
@@ -19827,6 +20444,7 @@
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=10.13.0"
}
@@ -19836,6 +20454,7 @@
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
+ "peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
@@ -19849,6 +20468,7 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4.0"
}
@@ -19857,7 +20477,8 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/whatwg-encoding": {
"version": "2.0.0",
@@ -19925,7 +20546,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
@@ -20091,6 +20713,7 @@
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=0.4"
}
diff --git a/package.json b/package.json
index 12647da..679e5ad 100644
--- a/package.json
+++ b/package.json
@@ -102,6 +102,7 @@
"blob-polyfill": "^9.0.20240710",
"deep-diff": "^1.0.2",
"deep-object-diff": "^1.1.9",
+ "diff": "^8.0.2",
"eslint": "^9.21.0",
"husky": "^9.1.7",
"jest-environment-jsdom": "^29.7.0",
diff --git a/src/index.ts b/src/index.ts
index 5a2e03d..f361c2d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,7 @@
export { getObjectDiff } from "./lib/object-diff";
export { getListDiff } from "./lib/list-diff";
export { isEqual, isObject } from "./lib/utils";
+export { getTextDiff } from "./lib/text-diff";
export * from "./models/list";
export * from "./models/object";
export * from "./models/stream";
diff --git a/src/lib/text-diff/index.ts b/src/lib/text-diff/index.ts
new file mode 100644
index 0000000..671bdde
--- /dev/null
+++ b/src/lib/text-diff/index.ts
@@ -0,0 +1,51 @@
+import {
+ DEFAULT_TEXT_DIFF_OPTIONS,
+ TextDiff,
+ TextDiffOptions,
+ TextStatus,
+} from "@models/text";
+import { tokenizeText } from "./tokenize";
+import { getStrictTextDiff } from "./strict";
+import { getLCSTextDiff } from "./lcs";
+
+export function getTextDiff(
+ previousText: string | null | undefined,
+ currentText: string | null | undefined,
+ options: TextDiffOptions = DEFAULT_TEXT_DIFF_OPTIONS,
+): TextDiff {
+ const previousTokens = tokenizeText(previousText, options);
+ const currentTokens = tokenizeText(currentText, options);
+ if (!previousText && !currentText) {
+ return { type: "text", status: TextStatus.EQUAL, diff: [] };
+ }
+
+ if (!previousText) {
+ return {
+ type: "text",
+ status: TextStatus.ADDED,
+ diff: currentTokens.map((token, i) => ({
+ value: token.value,
+ status: TextStatus.ADDED,
+ currentIndex: i,
+ previousIndex: null,
+ })),
+ };
+ }
+ if (!currentText) {
+ return {
+ type: "text",
+ status: TextStatus.DELETED,
+ diff: previousTokens.map((token, i) => ({
+ value: token.value,
+ status: TextStatus.DELETED,
+ previousIndex: i,
+ currentIndex: null,
+ })),
+ };
+ }
+
+ if (options.mode === "strict") {
+ return getStrictTextDiff(previousTokens, currentTokens);
+ }
+ return getLCSTextDiff(previousTokens, currentTokens);
+}
diff --git a/src/lib/text-diff/lcs/index.ts b/src/lib/text-diff/lcs/index.ts
new file mode 100644
index 0000000..093817a
--- /dev/null
+++ b/src/lib/text-diff/lcs/index.ts
@@ -0,0 +1,52 @@
+import { TextDiff, TextStatus, TextToken, TextTokenDiff } from "@models/text";
+import { myersDiff } from "./myers";
+import { getDiffStatus } from "../utils/status";
+
+export function getLCSTextDiff(
+ previousTokens: TextToken[],
+ currentTokens: TextToken[],
+): TextDiff {
+ const edits = myersDiff(previousTokens, currentTokens);
+ const diff: TextTokenDiff[] = [];
+ const statusSet = new Set();
+
+ for (let i = 0; i < edits.length; i++) {
+ const edit = edits[i];
+
+ if (edit.status === TextStatus.EQUAL) {
+ diff.push({
+ value: currentTokens[edit.curr].value,
+ status: TextStatus.EQUAL,
+ currentIndex: edit.curr,
+ previousIndex: edit.prev,
+ });
+ statusSet.add(TextStatus.EQUAL);
+ }
+
+ if (edit.status === TextStatus.ADDED) {
+ diff.push({
+ value: currentTokens[edit.curr].value,
+ status: TextStatus.ADDED,
+ currentIndex: edit.curr,
+ previousIndex: null,
+ });
+ statusSet.add(TextStatus.ADDED);
+ }
+
+ if (edit.status === TextStatus.DELETED) {
+ diff.push({
+ value: previousTokens[edit.prev].value,
+ status: TextStatus.DELETED,
+ previousIndex: edit.prev,
+ currentIndex: null,
+ });
+ statusSet.add(TextStatus.DELETED);
+ }
+ }
+
+ return {
+ type: "text",
+ status: getDiffStatus(statusSet),
+ diff,
+ };
+}
diff --git a/src/lib/text-diff/lcs/myers.ts b/src/lib/text-diff/lcs/myers.ts
new file mode 100644
index 0000000..f2f596b
--- /dev/null
+++ b/src/lib/text-diff/lcs/myers.ts
@@ -0,0 +1,106 @@
+import { TextStatus, TextToken } from "@models/text";
+
+type MyersEdit =
+ | { status: TextStatus.EQUAL; prev: number; curr: number }
+ | { status: TextStatus.ADDED; curr: number }
+ | { status: TextStatus.DELETED; prev: number };
+
+function backtrack(
+ trace: Map[],
+ a: TextToken[],
+ b: TextToken[],
+): MyersEdit[] {
+ let x = a.length;
+ let y = b.length;
+ const edits: MyersEdit[] = [];
+
+ for (let d = trace.length - 1; d >= 0; d--) {
+ const v = trace[d];
+ const k = x - y;
+
+ let prevK: number;
+ if (k === -d || (k !== d && (v.get(k - 1) ?? 0) < (v.get(k + 1) ?? 0))) {
+ prevK = k + 1;
+ } else {
+ prevK = k - 1;
+ }
+
+ const prevX = v.get(prevK) ?? 0;
+ const prevY = prevX - prevK;
+
+ // Snake (equal)
+ while (x > prevX && y > prevY) {
+ edits.push({
+ status: TextStatus.EQUAL,
+ prev: x - 1,
+ curr: y - 1,
+ });
+ x--;
+ y--;
+ }
+
+ if (d === 0) break;
+
+ // Edit step
+ if (x === prevX) {
+ edits.push({
+ status: TextStatus.ADDED,
+ curr: y - 1,
+ });
+ y--;
+ } else {
+ edits.push({
+ status: TextStatus.DELETED,
+ prev: x - 1,
+ });
+ x--;
+ }
+ }
+
+ return edits.reverse();
+}
+
+export function myersDiff(a: TextToken[], b: TextToken[]): MyersEdit[] {
+ const N = a.length;
+ const M = b.length;
+ const max = N + M;
+
+ const trace: Map[] = [];
+ const v = new Map();
+ v.set(1, 0);
+
+ for (let d = 0; d <= max; d++) {
+ const vSnapshot = new Map(v);
+
+ for (let k = -d; k <= d; k += 2) {
+ let x: number;
+
+ if (k === -d || (k !== d && (v.get(k - 1) ?? 0) < (v.get(k + 1) ?? 0))) {
+ // Down (insert)
+ x = v.get(k + 1) ?? 0;
+ } else {
+ // Right (delete)
+ x = (v.get(k - 1) ?? 0) + 1;
+ }
+
+ let y = x - k;
+
+ // Snake (match)
+ while (x < N && y < M && a[x].normalizedValue === b[y].normalizedValue) {
+ x++;
+ y++;
+ }
+
+ v.set(k, x);
+
+ if (x >= N && y >= M) {
+ trace.push(vSnapshot);
+ return backtrack(trace, a, b);
+ }
+ }
+
+ trace.push(vSnapshot);
+ }
+
+ return [];
+}
diff --git a/src/lib/text-diff/strict/index.ts b/src/lib/text-diff/strict/index.ts
new file mode 100644
index 0000000..6fc535b
--- /dev/null
+++ b/src/lib/text-diff/strict/index.ts
@@ -0,0 +1,85 @@
+import { TextDiff, TextStatus, TextToken, TextTokenDiff } from "@models/text";
+import { getDiffStatus } from "../utils/status";
+
+export function getStrictTextDiff(
+ previousTokens: TextToken[],
+ currentTokens: TextToken[],
+): TextDiff {
+ const previousTokensMap = new Map();
+ const addedTokensMap = new Map();
+ const statusMap = new Set();
+ const diff: TextTokenDiff[] = [];
+
+ previousTokens.forEach((previousToken) => {
+ const match = previousTokensMap.get(previousToken.normalizedValue);
+ if (match) {
+ previousTokensMap.set(previousToken.normalizedValue, [
+ ...match,
+ previousToken,
+ ]);
+ } else {
+ previousTokensMap.set(previousToken.normalizedValue, [previousToken]);
+ }
+ });
+
+ currentTokens.forEach((currentToken) => {
+ const prevTokens = previousTokensMap.get(currentToken.normalizedValue);
+ const prevToken = prevTokens?.at(0);
+ if (prevTokens && prevToken) {
+ const nextStatus =
+ prevToken.currentIndex === currentToken.currentIndex
+ ? TextStatus.EQUAL
+ : TextStatus.MOVED;
+ statusMap.add(nextStatus);
+ diff.push({
+ value: currentToken.value,
+ status: nextStatus,
+ currentIndex: currentToken.currentIndex,
+ previousIndex: prevToken.currentIndex,
+ });
+ const nextPrevTokens = prevTokens.splice(1);
+ if (nextPrevTokens.length === 0) {
+ previousTokensMap.delete(prevToken.normalizedValue);
+ } else {
+ previousTokensMap.set(prevToken.normalizedValue, nextPrevTokens);
+ }
+ } else {
+ addedTokensMap.set(currentToken.currentIndex, currentToken);
+ statusMap.add(TextStatus.ADDED);
+ diff.push({
+ value: currentToken.value,
+ status: TextStatus.ADDED,
+ currentIndex: currentToken.currentIndex,
+ previousIndex: null,
+ });
+ }
+ });
+
+ previousTokensMap.forEach((previousTokens) => {
+ previousTokens.forEach((previousToken) => {
+ const match = addedTokensMap.get(previousToken.currentIndex);
+ if (match) {
+ statusMap.add(TextStatus.UPDATED);
+ diff[previousToken.currentIndex] = {
+ value: match.value,
+ previousValue: previousToken.value,
+ status: TextStatus.UPDATED,
+ previousIndex: null,
+ currentIndex: match.currentIndex,
+ };
+ } else {
+ statusMap.add(TextStatus.DELETED);
+ diff.push({
+ value: previousToken.value,
+ status: TextStatus.DELETED,
+ previousIndex: previousToken.currentIndex,
+ currentIndex: null,
+ });
+ }
+ });
+ });
+
+ const status = getDiffStatus(statusMap);
+
+ return { type: "text", status, diff };
+}
diff --git a/src/lib/text-diff/text-diff.test.ts b/src/lib/text-diff/text-diff.test.ts
new file mode 100644
index 0000000..90a70d2
--- /dev/null
+++ b/src/lib/text-diff/text-diff.test.ts
@@ -0,0 +1,502 @@
+import { getTextDiff } from ".";
+
+describe("getTextDiff - general", () => {
+ it("returns all equal tokens when texts are identical", () => {
+ expect(getTextDiff("A B C", "A B C")).toStrictEqual({
+ type: "text",
+ status: "equal",
+ diff: [
+ { value: "A", status: "equal", currentIndex: 0, previousIndex: 0 },
+ { value: "B", status: "equal", currentIndex: 1, previousIndex: 1 },
+ { value: "C", status: "equal", currentIndex: 2, previousIndex: 2 },
+ ],
+ });
+ });
+
+ it("marks all tokens as added when previous text is empty", () => {
+ expect(getTextDiff("", "A B")).toStrictEqual({
+ type: "text",
+ status: "added",
+ diff: [
+ { value: "A", status: "added", currentIndex: 0, previousIndex: null },
+ { value: "B", status: "added", currentIndex: 1, previousIndex: null },
+ ],
+ });
+ });
+
+ it("marks all tokens as deleted when current text is empty", () => {
+ expect(getTextDiff("A B", "")).toStrictEqual({
+ type: "text",
+ status: "deleted",
+ diff: [
+ { value: "A", status: "deleted", currentIndex: null, previousIndex: 0 },
+ { value: "B", status: "deleted", currentIndex: null, previousIndex: 1 },
+ ],
+ });
+ });
+});
+
+describe("getTextDiff – visual", () => {
+ it("merges delete + add at same position into updated", () => {
+ expect(getTextDiff("A B C", "A X C")).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "A", status: "equal", currentIndex: 0, previousIndex: 0 },
+ {
+ value: "B",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 1,
+ },
+ {
+ value: "X",
+ status: "added",
+ currentIndex: 1,
+ previousIndex: null,
+ },
+ { value: "C", status: "equal", currentIndex: 2, previousIndex: 2 },
+ ],
+ });
+ });
+
+ it("represents reordering as delete + add in visual mode", () => {
+ expect(getTextDiff("A B C A B", "A B A B C")).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "A", status: "equal", currentIndex: 0, previousIndex: 0 },
+ { value: "B", status: "equal", currentIndex: 1, previousIndex: 1 },
+ { value: "C", status: "deleted", currentIndex: null, previousIndex: 2 },
+ { value: "A", status: "equal", currentIndex: 2, previousIndex: 3 },
+ { value: "B", status: "equal", currentIndex: 3, previousIndex: 4 },
+ { value: "C", status: "added", currentIndex: 4, previousIndex: null },
+ ],
+ });
+ });
+
+ it("handles moves, updates, adds and deletes correctly - by word", () => {
+ expect(
+ getTextDiff(
+ "Solemnly he came and mounted the rounded gunrest.",
+ "He, solemnly came and he mounted square gunrest.",
+ { ignoreCase: true, separation: "word" },
+ ),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "He,", status: "added", currentIndex: 0, previousIndex: null },
+ {
+ value: "solemnly",
+ status: "equal",
+ currentIndex: 1,
+ previousIndex: 0,
+ },
+ {
+ value: "he",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 1,
+ },
+ { value: "came", status: "equal", currentIndex: 2, previousIndex: 2 },
+ { value: "and", status: "equal", currentIndex: 3, previousIndex: 3 },
+ { value: "he", status: "added", currentIndex: 4, previousIndex: null },
+ {
+ value: "mounted",
+ status: "equal",
+ currentIndex: 5,
+ previousIndex: 4,
+ },
+ {
+ value: "the",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 5,
+ },
+ {
+ value: "rounded",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 6,
+ },
+ {
+ value: "square",
+ status: "added",
+ currentIndex: 6,
+ previousIndex: null,
+ },
+ {
+ value: "gunrest.",
+ status: "equal",
+ currentIndex: 7,
+ previousIndex: 7,
+ },
+ ],
+ });
+ });
+
+ it("handles moves, updates, adds and deletes correctly - by character", () => {
+ expect(
+ getTextDiff("abc", "xcy", { separation: "character", mode: "visual" }),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ {
+ value: "a",
+ status: "deleted",
+ previousIndex: 0,
+ currentIndex: null,
+ },
+ {
+ value: "b",
+ status: "deleted",
+ previousIndex: 1,
+ currentIndex: null,
+ },
+ {
+ value: "x",
+ status: "added",
+ currentIndex: 0,
+ previousIndex: null,
+ },
+ { value: "c", status: "equal", currentIndex: 1, previousIndex: 2 },
+ {
+ value: "y",
+ status: "added",
+ currentIndex: 2,
+ previousIndex: null,
+ },
+ ],
+ });
+ });
+
+ it("handles moves, updates, adds and deletes correctly - by sentence", () => {
+ expect(
+ getTextDiff(
+ "Hello world. I like turtles. Goodbye moon.",
+ "Hello world. I love turtles. Welcome sun.",
+ { separation: "sentence", mode: "visual" },
+ ),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ {
+ value: "Hello world.",
+ status: "equal",
+ currentIndex: 0,
+ previousIndex: 0,
+ },
+ {
+ value: "I like turtles.",
+ status: "deleted",
+ previousIndex: 1,
+ currentIndex: null,
+ },
+ {
+ value: "Goodbye moon.",
+ status: "deleted",
+ previousIndex: 2,
+ currentIndex: null,
+ },
+ {
+ value: "I love turtles.",
+ status: "added",
+ currentIndex: 1,
+ previousIndex: null,
+ },
+ {
+ value: "Welcome sun.",
+ status: "added",
+ currentIndex: 2,
+ previousIndex: null,
+ },
+ ],
+ });
+ });
+
+ it("ignores case when ignoreCase is true", () => {
+ const diff = getTextDiff("Hello WORLD", "hello world", {
+ ignoreCase: true,
+ });
+
+ expect(diff.diff.every((d) => d.status === "equal")).toBe(true);
+ });
+
+ it("ignores punctuation when ignorePunctuation is true", () => {
+ const diff = getTextDiff("hello!", "hello", {
+ ignorePunctuation: true,
+ });
+
+ expect(diff.diff[0].status).toBe("equal");
+ });
+
+ it("handles character separation", () => {
+ expect(
+ getTextDiff("abc", "axc", { separation: "character" }),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "a", status: "equal", currentIndex: 0, previousIndex: 0 },
+ {
+ value: "b",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 1,
+ },
+ {
+ value: "x",
+ status: "added",
+ currentIndex: 1,
+ previousIndex: null,
+ },
+ { value: "c", status: "equal", currentIndex: 2, previousIndex: 2 },
+ ],
+ });
+ });
+
+ it("handles sentence separation", () => {
+ expect(
+ getTextDiff("Hello world. How are you?", "Hello world. I'm fine.", {
+ separation: "sentence",
+ }),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ {
+ value: "Hello world.",
+ status: "equal",
+ currentIndex: 0,
+ previousIndex: 0,
+ },
+ {
+ value: "How are you?",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 1,
+ },
+ {
+ value: "I'm fine.",
+ status: "added",
+ currentIndex: 1,
+ previousIndex: null,
+ },
+ ],
+ });
+ });
+});
+
+describe("getTextDiff – strict", () => {
+ it("merges delete + add at same position into updated", () => {
+ expect(getTextDiff("A B C", "A X C", { mode: "strict" })).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "A", status: "equal", currentIndex: 0, previousIndex: 0 },
+ {
+ value: "X",
+ previousValue: "B",
+ status: "updated",
+ currentIndex: 1,
+ previousIndex: null,
+ },
+ { value: "C", status: "equal", currentIndex: 2, previousIndex: 2 },
+ ],
+ });
+ });
+
+ it("ignores case when ignoreCase is true", () => {
+ expect(
+ getTextDiff("Hello World", "hello world", {
+ ignoreCase: true,
+ mode: "strict",
+ }),
+ ).toStrictEqual({
+ type: "text",
+ status: "equal",
+ diff: [
+ { value: "hello", status: "equal", currentIndex: 0, previousIndex: 0 },
+ { value: "world", status: "equal", currentIndex: 1, previousIndex: 1 },
+ ],
+ });
+ });
+
+ it("ignores punctuation when ignorePunctuation is true", () => {
+ expect(
+ getTextDiff("Hello, world!", "Hello world", {
+ ignorePunctuation: true,
+ mode: "strict",
+ }),
+ ).toStrictEqual({
+ type: "text",
+ status: "equal",
+ diff: [
+ { value: "Hello", status: "equal", currentIndex: 0, previousIndex: 0 },
+ { value: "world", status: "equal", currentIndex: 1, previousIndex: 1 },
+ ],
+ });
+ });
+
+ it("handles moves, updates, adds and deletes correctly - by word", () => {
+ expect(
+ getTextDiff(
+ "Solemnly he came and mounted the rounded gunrest.",
+ "He, solemnly came and he mounted square gunrest.",
+ { ignoreCase: true, separation: "word", mode: "strict" },
+ ),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "He,", status: "added", currentIndex: 0, previousIndex: null },
+ {
+ value: "solemnly",
+ status: "moved",
+ currentIndex: 1,
+ previousIndex: 0,
+ },
+ { value: "came", status: "equal", currentIndex: 2, previousIndex: 2 },
+ { value: "and", status: "equal", currentIndex: 3, previousIndex: 3 },
+ { value: "he", status: "moved", currentIndex: 4, previousIndex: 1 },
+ {
+ value: "mounted",
+ status: "moved",
+ currentIndex: 5,
+ previousIndex: 4,
+ },
+ {
+ value: "square",
+ previousValue: "rounded",
+ status: "updated",
+ currentIndex: 6,
+ previousIndex: null,
+ },
+ {
+ value: "gunrest.",
+ status: "equal",
+ currentIndex: 7,
+ previousIndex: 7,
+ },
+ {
+ value: "the",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 5,
+ },
+ ],
+ });
+ });
+
+ it("handles moves, updates, adds and deletes correctly - by character", () => {
+ expect(
+ getTextDiff("abcdz", "xbcy", {
+ separation: "character",
+ mode: "strict",
+ }),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ {
+ value: "x",
+ previousValue: "a",
+ status: "updated",
+ currentIndex: 0,
+ previousIndex: null,
+ },
+ {
+ value: "b",
+ status: "equal",
+ currentIndex: 1,
+ previousIndex: 1,
+ },
+ {
+ value: "c",
+ status: "equal",
+ currentIndex: 2,
+ previousIndex: 2,
+ },
+ {
+ value: "y",
+ previousValue: "d",
+ status: "updated",
+ currentIndex: 3,
+ previousIndex: null,
+ },
+ {
+ value: "z",
+ status: "deleted",
+ currentIndex: null,
+ previousIndex: 4,
+ },
+ ],
+ });
+ });
+
+ it("handles moves, updates, adds and deletes correctly - by sentence", () => {
+ console.log(
+ "tyty",
+ getTextDiff("The brown fox jumped high", "The orange cat has jumped", {
+ mode: "visual",
+ separation: "word",
+ }),
+ );
+ expect(
+ getTextDiff(
+ "A one. B two. C three. D four.",
+ "B two. A ONE. C three. E five.",
+ { separation: "sentence", mode: "strict", ignoreCase: true },
+ ),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ {
+ value: "B two.",
+ status: "moved",
+ currentIndex: 0,
+ previousIndex: 1,
+ },
+ {
+ value: "A ONE.",
+ status: "moved",
+ currentIndex: 1,
+ previousIndex: 0,
+ },
+ {
+ value: "C three.",
+ status: "equal",
+ currentIndex: 2,
+ previousIndex: 2,
+ },
+ {
+ value: "E five.",
+ previousValue: "D four.",
+ status: "updated",
+ previousIndex: null,
+ currentIndex: 3,
+ },
+ ],
+ });
+ });
+
+ it("detects moves with duplicates", () => {
+ expect(
+ getTextDiff("A B C A B", "A B A B C", { mode: "strict" }),
+ ).toStrictEqual({
+ type: "text",
+ status: "updated",
+ diff: [
+ { value: "A", status: "equal", currentIndex: 0, previousIndex: 0 },
+ { value: "B", status: "equal", currentIndex: 1, previousIndex: 1 },
+ { value: "A", status: "moved", currentIndex: 2, previousIndex: 3 },
+ { value: "B", status: "moved", currentIndex: 3, previousIndex: 4 },
+ { value: "C", status: "moved", currentIndex: 4, previousIndex: 2 },
+ ],
+ });
+ });
+});
diff --git a/src/lib/text-diff/tokenize/index.ts b/src/lib/text-diff/tokenize/index.ts
new file mode 100644
index 0000000..c22656d
--- /dev/null
+++ b/src/lib/text-diff/tokenize/index.ts
@@ -0,0 +1,106 @@
+import {
+ DEFAULT_TEXT_DIFF_OPTIONS,
+ TextDiffOptions,
+ TextToken,
+} from "@models/text";
+
+const normalizeToken = (token: string, options: TextDiffOptions): string => {
+ let nextToken = token;
+ if (options.ignoreCase) {
+ nextToken = nextToken.toLowerCase();
+ }
+ if (options.ignorePunctuation) {
+ nextToken = nextToken.replace(/[",;:!?“”‘’'«»()[\]{}…—–-]/g, "");
+ }
+ return nextToken;
+};
+
+export const tokenizeText = (
+ text: string | null | undefined,
+ options: TextDiffOptions = DEFAULT_TEXT_DIFF_OPTIONS,
+): TextToken[] => {
+ const result: TextToken[] = [];
+
+ const generateToken = (token: string, currentIndex: number) => {
+ if (token) {
+ result.push({
+ value: token,
+ normalizedValue: normalizeToken(token, options),
+ currentIndex,
+ });
+ }
+ };
+
+ // Intl.Segmenter splits words and punctuation separately.
+ // This function merges them into user-expected tokens like: "word!", "Jean-Claude", "day..."
+ const mergeWordsPunctuation = (tokens: Intl.SegmentData[]): string[] => {
+ const mergedWords: string[] = [];
+
+ const pushSplit = (segment: string) => {
+ const parts = segment
+ .split(
+ /(\p{Emoji_Presentation}|\p{Extended_Pictographic}|[+\\/*=<>%&|^~@#$€£¥])/gu,
+ )
+ .filter(Boolean);
+ mergedWords.push(...parts);
+ };
+
+ let lastEndIndex: number | null = null;
+
+ for (const { segment, isWordLike, index } of tokens) {
+ const endIndex = index + segment.length;
+ const validSegment = segment.trim();
+ if (!validSegment) {
+ lastEndIndex = endIndex;
+ continue;
+ }
+ if (isWordLike) {
+ const isAdjacent = lastEndIndex === index;
+ const endsWithDash = /[—–-]$/.test(mergedWords.at(-1) || "");
+
+ if (mergedWords.length > 0 && isAdjacent && endsWithDash) {
+ const prev = mergedWords.pop()!;
+ pushSplit(prev + validSegment);
+ } else {
+ pushSplit(validSegment);
+ }
+ } else if (mergedWords.length > 0) {
+ const prev = mergedWords.pop()!;
+ pushSplit(prev + validSegment);
+ } else {
+ pushSplit(validSegment);
+ }
+ lastEndIndex = endIndex;
+ }
+ return mergedWords;
+ };
+
+ if (!text?.trim()) return result;
+ switch (options.separation) {
+ case "character":
+ [...text].forEach((token, i) => generateToken(token.trim(), i));
+ break;
+ case "sentence": {
+ const segmenter = new Intl.Segmenter(options.locale, {
+ granularity: "sentence",
+ });
+ for (const [i, { segment }] of [...segmenter.segment(text)].entries()) {
+ generateToken(segment.trim(), i);
+ }
+ break;
+ }
+ case "word": {
+ const segmenter = new Intl.Segmenter(options.locale, {
+ granularity: "word",
+ });
+ const tokens = [...segmenter.segment(text)];
+ mergeWordsPunctuation(tokens).forEach((token, i) =>
+ generateToken(token, i),
+ );
+ break;
+ }
+ default:
+ text.split(/\s+/u).forEach(generateToken);
+ }
+ return result;
+};
diff --git a/src/lib/text-diff/tokenize/tokenize.test.ts b/src/lib/text-diff/tokenize/tokenize.test.ts
new file mode 100644
index 0000000..951077a
--- /dev/null
+++ b/src/lib/text-diff/tokenize/tokenize.test.ts
@@ -0,0 +1,223 @@
+import { tokenizeText } from ".";
+
+describe("tokenizeText", () => {
+ const base = "hello wrld! It's a great day... A wonderful day! Yeah.";
+
+ it("splits text into sentences", () => {
+ const tokens = tokenizeText(base, { separation: "sentence" });
+
+ expect(tokens).toEqual([
+ { value: "hello wrld!", normalizedValue: "hello wrld!", currentIndex: 0 },
+ {
+ value: "It's a great day...",
+ normalizedValue: "It's a great day...",
+ currentIndex: 1,
+ },
+ {
+ value: "A wonderful day!",
+ normalizedValue: "A wonderful day!",
+ currentIndex: 2,
+ },
+ { value: "Yeah.", normalizedValue: "Yeah.", currentIndex: 3 },
+ ]);
+ });
+
+ it("splits text into words and merges punctuation", () => {
+ const tokens = tokenizeText(base, { separation: "word" });
+
+ expect(tokens).toEqual([
+ { value: "hello", normalizedValue: "hello", currentIndex: 0 },
+ { value: "wrld!", normalizedValue: "wrld!", currentIndex: 1 },
+ { value: "It's", normalizedValue: "It's", currentIndex: 2 },
+ { value: "a", normalizedValue: "a", currentIndex: 3 },
+ { value: "great", normalizedValue: "great", currentIndex: 4 },
+ { value: "day...", normalizedValue: "day...", currentIndex: 5 },
+ { value: "A", normalizedValue: "A", currentIndex: 6 },
+ { value: "wonderful", normalizedValue: "wonderful", currentIndex: 7 },
+ { value: "day!", normalizedValue: "day!", currentIndex: 8 },
+ { value: "Yeah.", normalizedValue: "Yeah.", currentIndex: 9 },
+ ]);
+ });
+
+ it("splits text into characters", () => {
+ const tokens = tokenizeText("abc!", { separation: "character" });
+
+ expect(tokens).toEqual([
+ { value: "a", normalizedValue: "a", currentIndex: 0 },
+ { value: "b", normalizedValue: "b", currentIndex: 1 },
+ { value: "c", normalizedValue: "c", currentIndex: 2 },
+ { value: "!", normalizedValue: "!", currentIndex: 3 },
+ ]);
+ });
+
+ it("splits text by words when separation type is unknown", () => {
+ const tokens = tokenizeText("hello world");
+
+ expect(tokens).toEqual([
+ { value: "hello", normalizedValue: "hello", currentIndex: 0 },
+ { value: "world", normalizedValue: "world", currentIndex: 1 },
+ ]);
+ });
+
+ it("normalizes tokens by lowercasing when ignoreCase is true", () => {
+ const tokens = tokenizeText("Hello WORLD!", {
+ separation: "word",
+ ignoreCase: true,
+ });
+
+ expect(tokens).toEqual([
+ { value: "Hello", normalizedValue: "hello", currentIndex: 0 },
+ { value: "WORLD!", normalizedValue: "world!", currentIndex: 1 },
+ ]);
+ });
+
+ it("removes punctuation in normalizedValue when ignorePunctuation is true", () => {
+ const tokens = tokenizeText("hello world!", {
+ separation: "word",
+ ignorePunctuation: true,
+ });
+
+ expect(tokens).toEqual([
+ { value: "hello", normalizedValue: "hello", currentIndex: 0 },
+ { value: "world!", normalizedValue: "world", currentIndex: 1 },
+ ]);
+ });
+
+ it("applies both ignoreCase and ignorePunctuation", () => {
+ const tokens = tokenizeText("Hello WORLD!", {
+ separation: "word",
+ ignoreCase: true,
+ ignorePunctuation: true,
+ });
+
+ expect(tokens).toEqual([
+ { value: "Hello", normalizedValue: "hello", currentIndex: 0 },
+ { value: "WORLD!", normalizedValue: "world", currentIndex: 1 },
+ ]);
+ });
+
+ it("returns empty array for empty input", () => {
+ expect(tokenizeText("", { separation: "word" })).toEqual([]);
+ expect(tokenizeText(null, { separation: "word" })).toEqual([]);
+ expect(tokenizeText(undefined, { separation: "word" })).toEqual([]);
+ });
+
+ it("handles locale-specific segmentation (Japanese)", () => {
+ const tokens = tokenizeText("今日はいい天気ですね。", {
+ separation: "sentence",
+ locale: "ja",
+ });
+
+ expect(tokens).toEqual([
+ {
+ value: "今日はいい天気ですね。",
+ normalizedValue: "今日はいい天気ですね。",
+ currentIndex: 0,
+ },
+ ]);
+ });
+
+ it("handles CJK word segmentation", () => {
+ const tokens = tokenizeText("私は学生です。", {
+ separation: "word",
+ locale: "ja",
+ });
+
+ expect(tokens).toEqual([
+ { value: "私", normalizedValue: "私", currentIndex: 0 },
+ { value: "は", normalizedValue: "は", currentIndex: 1 },
+ { value: "学生", normalizedValue: "学生", currentIndex: 2 },
+ { value: "です。", normalizedValue: "です。", currentIndex: 3 },
+ ]);
+ });
+
+ it("trims extra spacing in sentences", () => {
+ const tokens = tokenizeText(" Hello world! This is fine. ", {
+ separation: "sentence",
+ });
+
+ expect(tokens).toEqual([
+ {
+ value: "Hello world!",
+ normalizedValue: "Hello world!",
+ currentIndex: 0,
+ },
+ {
+ value: "This is fine.",
+ normalizedValue: "This is fine.",
+ currentIndex: 1,
+ },
+ ]);
+ });
+
+ it("merges multiple punctuation marks", () => {
+ const tokens = tokenizeText("Wait!!! Really??", { separation: "word" });
+ expect(tokens).toEqual([
+ { value: "Wait!!!", normalizedValue: "Wait!!!", currentIndex: 0 },
+ { value: "Really??", normalizedValue: "Really??", currentIndex: 1 },
+ ]);
+ });
+
+ it("keeps emojis as standalone tokens", () => {
+ const tokens = tokenizeText("Hello 😊 world!", { separation: "word" });
+ expect(tokens).toEqual([
+ { value: "Hello", normalizedValue: "Hello", currentIndex: 0 },
+ { value: "😊", normalizedValue: "😊", currentIndex: 1 },
+ { value: "world!", normalizedValue: "world!", currentIndex: 2 },
+ ]);
+ });
+
+ it("handles numbers and punctuation", () => {
+ const tokens = tokenizeText("Version 2.0 is out!", { separation: "word" });
+
+ expect(tokens).toEqual([
+ { value: "Version", normalizedValue: "Version", currentIndex: 0 },
+ { value: "2.0", normalizedValue: "2.0", currentIndex: 1 },
+ { value: "is", normalizedValue: "is", currentIndex: 2 },
+ { value: "out!", normalizedValue: "out!", currentIndex: 3 },
+ ]);
+ });
+
+ it("handles mixed scripts", () => {
+ const tokens = tokenizeText("Hello 世界!", { separation: "word" });
+
+ expect(tokens).toEqual([
+ { value: "Hello", normalizedValue: "Hello", currentIndex: 0 },
+ { value: "世界!", normalizedValue: "世界!", currentIndex: 1 },
+ ]);
+ });
+
+ it("does not merge symbols that are not punctuation", () => {
+ const tokens = tokenizeText("hello + world", { separation: "word" });
+
+ expect(tokens).toEqual([
+ { value: "hello", normalizedValue: "hello", currentIndex: 0 },
+ { value: "+", normalizedValue: "+", currentIndex: 1 },
+ { value: "world", normalizedValue: "world", currentIndex: 2 },
+ ]);
+ });
+
+ it("handles unicode punctuation like em-dash and ellipsis", () => {
+ const tokens = tokenizeText("Is Jean-Claude cool?", { separation: "word" });
+ expect(tokens).toEqual([
+ { value: "Is", normalizedValue: "Is", currentIndex: 0 },
+ { value: "Jean-Claude", normalizedValue: "Jean-Claude", currentIndex: 1 },
+ { value: "cool?", normalizedValue: "cool?", currentIndex: 2 },
+ ]);
+ });
+
+ it("ignorePunctuation removes unicode punctuation", () => {
+ const tokens = tokenizeText("Wait—really…?", {
+ separation: "word",
+ ignorePunctuation: true,
+ });
+
+ expect(tokens).toEqual([
+ {
+ value: "Wait—really…?",
+ normalizedValue: "Waitreally",
+ currentIndex: 0,
+ },
+ ]);
+ });
+});
diff --git a/src/lib/text-diff/utils/status.ts b/src/lib/text-diff/utils/status.ts
new file mode 100644
index 0000000..4d2a333
--- /dev/null
+++ b/src/lib/text-diff/utils/status.ts
@@ -0,0 +1,21 @@
+import { TextDiff, TextStatus } from "@models/text";
+
+export function getDiffStatus(statusMap: Set): TextDiff["status"] {
+ if (statusMap.has(TextStatus.UPDATED)) return TextStatus.UPDATED;
+
+ const isUniqueStatus = (status: TextStatus) => {
+ let isUnique = true;
+ for (const value of statusMap) {
+ if (value !== status) {
+ isUnique = false;
+ break;
+ }
+ }
+ return isUnique;
+ };
+
+ if (isUniqueStatus(TextStatus.ADDED)) return TextStatus.ADDED;
+ if (isUniqueStatus(TextStatus.DELETED)) return TextStatus.DELETED;
+ if (isUniqueStatus(TextStatus.EQUAL)) return TextStatus.EQUAL;
+ return TextStatus.UPDATED;
+}
diff --git a/src/models/text/index.ts b/src/models/text/index.ts
new file mode 100644
index 0000000..5536755
--- /dev/null
+++ b/src/models/text/index.ts
@@ -0,0 +1,56 @@
+export const DEFAULT_TEXT_DIFF_OPTIONS: TextDiffOptions = {
+ showOnly: [],
+ mode: "visual",
+ separation: "word",
+ ignoreCase: false,
+ ignorePunctuation: false,
+ locale: undefined,
+};
+
+export type TextToken = {
+ value: string;
+ normalizedValue: string;
+ currentIndex: number;
+};
+
+export type TextTokenDiff = {
+ value: string;
+ previousValue?: string;
+ status: TextStatus;
+ currentIndex: number | null;
+ previousIndex: number | null;
+};
+
+export enum TextStatus {
+ ADDED = "added",
+ EQUAL = "equal",
+ DELETED = "deleted",
+ UPDATED = "updated",
+ MOVED = "moved",
+}
+
+export type TextDiffOptions = {
+ showOnly?: `${TextStatus}`[];
+ separation?: "character" | "word" | "sentence";
+ mode?: "visual" | "strict";
+ ignoreCase?: boolean;
+ ignorePunctuation?: boolean;
+
+ locale?: Intl.Locale | string;
+};
+
+export type TextDiff = {
+ type: "text";
+ status:
+ | TextStatus.ADDED
+ | TextStatus.DELETED
+ | TextStatus.EQUAL
+ | TextStatus.UPDATED;
+ diff: {
+ value: string;
+ previousValue?: string;
+ status: TextStatus;
+ currentIndex: number | null;
+ previousIndex: number | null;
+ }[];
+};