├── .gitignore
├── .editorconfig
├── .vscode
└── settings.json
├── .prettierrc.json
├── pnpm-workspace.yaml
├── vitest.config.ts
├── .github
└── workflows
│ └── main.yml
├── package.json
├── LICENSE
├── CHANGELOG.md
├── tsconfig.json
├── README.md
├── tests
└── index.test.ts
├── src
└── index.ts
└── pnpm-lock.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /node_modules
3 | /coverage
4 | /dist
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{md,markdown}]
2 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "markdown.extension.toc.levels": "1..3"
3 | }
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": false,
5 | "singleQuote": true
6 | }
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | overrides:
2 | tough-cookie@<4.1.3: '>=4.1.3'
3 | esbuild@<=0.24.2: '>=0.25.0'
4 | form-data@<2.5.4: '>=2.5.4'
5 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitest/config'
2 |
3 | export default defineConfig({
4 | test: {
5 | coverage: {
6 | reporter: ['lcov'],
7 | },
8 | },
9 | })
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - develop
5 | - master
6 |
7 | name: Test Coveralls
8 |
9 | jobs:
10 |
11 | build:
12 | name: Build
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: pnpm/action-setup@v2
16 | with:
17 | version: 8.6.1
18 |
19 | - uses: actions/checkout@v1
20 |
21 | - name: Use Node.js 18.x
22 | uses: actions/setup-node@v1
23 | with:
24 | node-version: 18.x
25 |
26 | - name: pnpm install, make test-coverage
27 | run: |
28 | pnpm install
29 | pnpm run test
30 |
31 | - name: Coveralls
32 | uses: coverallsapp/github-action@master
33 | with:
34 | github-token: ${{ secrets.GITHUB_TOKEN }}
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "markov-strings",
3 | "version": "3.0.2",
4 | "description": "A Markov string generator",
5 | "main": "dist/index.js",
6 | "files": [
7 | "dist"
8 | ],
9 | "scripts": {
10 | "dev": "tsc --watch",
11 | "build": "tsc",
12 | "test": "vitest run --coverage"
13 | },
14 | "engines": {
15 | "node": ">=8.0.0"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/scambier/markov-strings"
20 | },
21 | "keywords": [
22 | "markov",
23 | "string",
24 | "chain",
25 | "procedural",
26 | "generation",
27 | "text"
28 | ],
29 | "author": "scambier",
30 | "license": "MIT",
31 | "devDependencies": {
32 | "@types/lodash": "^4.17.21",
33 | "@types/lodash-es": "^4.17.12",
34 | "@types/node": "^22.19.2",
35 | "@vitest/coverage-v8": "2.1.8",
36 | "coveralls-next": "^6.0.1",
37 | "prettier": "^3.7.4",
38 | "typescript": "^5.9.3",
39 | "vitest": "^2.1.9"
40 | },
41 | "dependencies": {
42 | "lodash-es": "^4.17.21"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Simon Cambier
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 3.0.0 - BREAKING CHANGES
4 |
5 | - Refactoring to facilitate iterative construction of the corpus (multiple `.addData()` instead of a one-time `buildCorpus()`), and export/import of corpus internal data.
6 |
7 | ## 2.1.0
8 |
9 | - Add an optionnal `prng` parameter at generation to use a specific Pseudo Random Number Generator
10 |
11 | ## 2.0.4
12 |
13 | - Dependencies update
14 |
15 | ## 2.0.0
16 |
17 | - **Refactoring with breaking changes**
18 | - The constructor and generator take two different options objects
19 | - Most of generator options are gone, except `filter` and `maxTries`
20 | - Tests have been rewritten with jest, in TypeScript
21 |
22 | ## 1.5.0
23 |
24 | - Code rewritten in TypeScript. You can now `import MarkovGenerator from 'markov-strings'`
25 |
26 | ## 1.4.0
27 |
28 | - New `filter()` method, thanks @flpvsk
29 |
30 | ## 1.3.4 - 1.3.5
31 |
32 | - Dependencies update
33 |
34 | ## 1.3.3
35 |
36 | - Updated README. Version bump for npm
37 |
38 | ## 1.3.2
39 |
40 | - Fixed an infinite loop bug
41 | - Performance improvement
42 |
43 | ## 1.3.1
44 |
45 | - Updated README example
46 | - Removed a useless line
47 |
48 | ## 1.3.0
49 |
50 | - New feature: the generator now accepts arrays of objects, and tells the user which objects were used to build a sentence
51 | - Fixed all unit tests
52 | - Added a changelog
53 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "include": [
4 | "src/**/*"
5 | ],
6 | "compilerOptions": {
7 | /* Basic Options */
8 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
9 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
10 | // "lib": [], /* Specify library files to be included in the compilation. */
11 | // "allowJs": true, /* Allow javascript files to be compiled. */
12 | // "checkJs": true, /* Report errors in .js files. */
13 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
14 | "declaration": true, /* Generates corresponding '.d.ts' file. */
15 | "declarationDir": "./dist",
16 | // "sourceMap": true, /* Generates corresponding '.map' file. */
17 | // "outFile": "./", /* Concatenate and emit output to single file. */
18 | "outDir": "./dist", /* Redirect output structure to the directory. */
19 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
20 | // "removeComments": true, /* Do not emit comments to output. */
21 | // "noEmit": true, /* Do not emit outputs. */
22 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
23 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
24 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
25 |
26 | /* Strict Type-Checking Options */
27 | "strict": true, /* Enable all strict type-checking options. */
28 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
29 | // "strictNullChecks": true, /* Enable strict null checks. */
30 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 |
52 | /* Source Map Options */
53 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
54 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
55 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
56 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
57 |
58 | /* Experimental Options */
59 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
60 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
61 | }
62 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/scambier/markov-strings)
2 | [](https://coveralls.io/github/scambier/markov-strings?branch=master)
3 | [](https://badge.fury.io/js/markov-strings)
4 |
5 |
6 | ---
7 | ! This is the readme for markov-strings **3.x.x.** - The docs for the older **2.x.x** are [here](https://github.com/scambier/markov-strings/tree/v2) !
8 |
9 | ---
10 |
11 | # Markov-strings
12 |
13 | A simplistic Markov chain text generator.
14 | Give it an array of strings, and it will output a randomly generated string.
15 |
16 | A rust port of this library is available [here](https://github.com/scambier/markov-strings-rust).
17 |
18 | This module was created for the Mastodon bot [@BelgicaNews](https://botsin.space/@BelgicaNews).
19 |
20 | - [Markov-strings](#markov-strings)
21 | - [Prerequisites](#prerequisites)
22 | - [Installing](#installing)
23 | - [Usage](#usage)
24 | - [API](#api)
25 | - [`new Markov([options])`](#new-markovoptions)
26 | - [`.addData(data)`](#adddatadata)
27 | - [`.generate([options])`](#generateoptions)
28 | - [`.export()` and `.import(data)`](#export-and-importdata)
29 | - [Unit tests](#unit-tests)
30 | - [Changelog](#changelog)
31 | - [Running the tests](#running-the-tests)
32 |
33 | ## Prerequisites
34 |
35 | Built and tested with NodeJS 18
36 |
37 | ## Installing
38 |
39 | `npm install --save markov-strings`
40 |
41 | ## Usage
42 |
43 | ```js
44 | import Markov from 'markov-strings'
45 | // Not recommended: you can use `require()` if needed, instead of `import`
46 | // const Markov = require('markov-strings').default
47 |
48 | // Build the Markov generator
49 | const markov = new Markov({ stateSize: 2 })
50 |
51 | // Add data for the generator
52 | const data = [/* insert a few hundreds/thousands sentences here */]
53 | markov.addData(data)
54 |
55 | const options = {
56 | maxTries: 20, // Give up if I don't have a sentence after 20 tries (default is 10)
57 |
58 | // If you want to get seeded results, you can provide an external PRNG.
59 | prng: Math.random, // Default value if left empty
60 |
61 | // You'll often need to manually filter raw results to get something that fits your needs.
62 | filter: (result) => {
63 | return result.string.split(' ').length >= 5 && // At least 5 words
64 | result.string.endsWith('.') // End sentences with a dot.
65 | }
66 | }
67 |
68 | // Generate a sentence
69 | const result = markov.generate(options)
70 | console.log(result)
71 | /*
72 | {
73 | string: 'lorem ipsum dolor sit amet etc.',
74 | score: 42,
75 | tries: 5,
76 | refs: [ an array of objects ]
77 | }
78 | */
79 | ```
80 |
81 | Markov-strings is built in TypeScript, and exports several types to help you. Take a look at [the source](https://github.com/scambier/markov-strings/blob/master/src/index.ts) to see how it works.
82 |
83 | ## API
84 |
85 | ### `new Markov([options])`
86 |
87 | Create a generator instance.
88 |
89 | #### options
90 |
91 | ```js
92 | {
93 | stateSize: number
94 | }
95 | ```
96 |
97 | The `stateSize` is the number of words for each "link" of the generated sentence. `1` will output gibberish sentences without much sense. `2` is a sensible default for most cases. `3` and more can create good sentences if you have a corpus that allows it.
98 |
99 | ### `.addData(data)`
100 |
101 | To function correctly, the Markov generator needs its internal data to be correctly structured. `.addData(data)` allows you add raw data, that is automatically formatted to fit the internal structure.
102 |
103 | You can call `.addData(data)` as often as you need, **with new data each time (!)**. Multiple calls of `.addData()` with the same data is not recommended, because it will skew the random generation of results.
104 |
105 | #### data
106 |
107 | ```js
108 | string[] | Array<{ string: string }>
109 | ```
110 |
111 | `data` is an array of strings (sentences), or an array of objects. If you wish to use objects, each one must have a `string` attribute. The bigger the array, the better and more varied the results.
112 |
113 | Examples:
114 |
115 | ```js
116 | [ 'lorem ipsum', 'dolor sit amet' ]
117 | ```
118 |
119 | or
120 |
121 | ```js
122 | [
123 | { string: 'lorem ipsum', attr: 'value' },
124 | { string: 'dolor sit amet', attr: 'other value' }
125 | ]
126 | ```
127 |
128 | The additionnal data passed with objects will be returned in the `refs` array of the generated sentence.
129 |
130 | ### `.generate([options])`
131 |
132 | Returns an object of type `MarkovResult`:
133 |
134 | ```ts
135 | {
136 | string: string, // The resulting sentence
137 | score: number, // A relative "score" based on the number of possible permutations. Higher is "better", but the actual value depends on your corpus
138 | refs: Array<{ string: string }>, // The array of references used to build the sentence
139 | tries: number // The number of tries it took to output this result
140 | }
141 | ```
142 |
143 | The `refs` array will contain all objects that have been used to build the sentence. May be useful to fetch meta data or make stats.
144 |
145 | #### options
146 |
147 | ```ts
148 | {
149 | maxTries: number // The max number of tentatives before giving up (default is 10)
150 | prng: Math.random, // An external Pseudo Random Number Generator if you want to get seeded results
151 | filter: (result: MarkovResult) => boolean // A callback to filter results (see example above)
152 | }
153 | ```
154 |
155 | ### `.export()` and `.import(data)`
156 |
157 | You can export and import the markov built corpus. The exported data is a serializable object, and must be deserialized before being re-imported.
158 |
159 | [Example use-case](https://github.com/scambier/markov-strings/issues/9)
160 |
161 | ## Running the tests
162 |
163 | `npm test`
164 |
--------------------------------------------------------------------------------
/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { map, some } from 'lodash-es'
2 | import Markov, { MarkovResult } from '../src'
3 | import { describe, expect, it, beforeEach, vi } from 'vitest'
4 |
5 | const data = [
6 | 'Lorem ipsum dolor sit amet',
7 | 'Lorem ipsum duplicate start words',
8 | 'Consectetur adipiscing elit',
9 | 'Quisque tempor, erat vel lacinia imperdiet',
10 | 'Justo nisi fringilla dui',
11 | 'Egestas bibendum eros nisi ut lacus',
12 | "fringilla dui avait annoncé une rupture avec le erat vel: il n'en est rien…",
13 | 'Fusce tincidunt tempor, erat vel lacinia vel ex pharetra pretium lacinia imperdiet'
14 | ]
15 |
16 | describe('Markov class', () => {
17 | describe('Constructor', () => {
18 |
19 | it('should have a default stateSize', () => {
20 | const markov = new Markov()
21 | expect(markov.options.stateSize).toBe(2)
22 | })
23 |
24 | it('should save a different stateSize', () => {
25 | const markov = new Markov({ stateSize: 3 })
26 | expect(markov.options.stateSize).toBe(3)
27 | })
28 | })
29 |
30 | describe('Adding data', () => {
31 | it('should build synchronously', () => {
32 | const markov = new Markov()
33 | expect(markov.corpus).toEqual({})
34 | markov.addData(data)
35 | expect(markov.corpus).not.toEqual({})
36 | })
37 |
38 |
39 | it('should throw an error if the data structure is invalid', () => {
40 | const markov = new Markov()
41 | expect(() => {
42 | // @ts-ignore
43 | markov.addData([{}])
44 | }).toThrowError()
45 | })
46 |
47 | it('should accept objects', () => {
48 | const markov = new Markov()
49 | markov.addData(data.map(o => ({ string: o })))
50 | expect(markov.corpus).not.toEqual({})
51 | })
52 |
53 | })
54 |
55 | describe('After adding data', () => {
56 | let markov: Markov
57 | beforeEach(() => {
58 | markov = new Markov()
59 | markov.addData(data)
60 | })
61 |
62 | describe('The startWords array', () => {
63 | it('should contain the right values', () => {
64 | const start = markov.startWords
65 | expect(some(start, { words: 'Lorem ipsum' })).toBeTruthy()
66 | expect(some(start, { words: 'Consectetur adipiscing' })).toBeTruthy()
67 | expect(some(start, { words: 'Quisque tempor,' })).toBeTruthy()
68 | expect(some(start, { words: 'Justo nisi' })).toBeTruthy()
69 | expect(some(start, { words: 'Egestas bibendum' })).toBeTruthy()
70 | expect(some(start, { words: 'fringilla dui' })).toBeTruthy()
71 | expect(some(start, { words: 'Fusce tincidunt' })).toBeTruthy()
72 | })
73 |
74 | it('should have the right length', () => {
75 | expect(markov.startWords).toHaveLength(7)
76 | })
77 | })
78 |
79 | describe('The endWords array', () => {
80 | it('should have the right length', () => {
81 | expect(markov.endWords).toHaveLength(7)
82 | })
83 |
84 | it('should contain the right values', () => {
85 | const end = markov.endWords
86 | expect(some(end, { words: 'sit amet' })).toBeTruthy()
87 | expect(some(end, { words: 'start words' })).toBeTruthy()
88 | expect(some(end, { words: 'adipiscing elit' })).toBeTruthy()
89 | expect(some(end, { words: 'fringilla dui' })).toBeTruthy()
90 | expect(some(end, { words: 'ut lacus' })).toBeTruthy()
91 | expect(some(end, { words: 'est rien…' })).toBeTruthy()
92 | })
93 | })
94 |
95 | describe('The corpus itself', () => {
96 | it('should have the right values for the right keys', () => {
97 | const corpus = markov.corpus
98 | expect(some(corpus['Lorem ipsum'], { words: 'dolor sit' })).toBeTruthy()
99 | expect(
100 | some(corpus['Lorem ipsum'], { words: 'duplicate start' })
101 | ).toBeTruthy()
102 | expect(
103 | some(corpus['tempor, erat'], { words: 'vel lacinia' })
104 | ).toBeTruthy()
105 | })
106 | })
107 |
108 | describe('Export data', () => {
109 | it('should clone the original corpus values', () => {
110 | const exported = markov.export()
111 |
112 | expect(exported.corpus).toEqual(markov.corpus)
113 | expect(exported.corpus).not.toBe(markov.corpus)
114 |
115 | expect(exported.startWords).not.toBe(markov.startWords)
116 | expect(exported.startWords).toEqual(markov.startWords)
117 |
118 | expect(exported.endWords).not.toBe(markov.endWords)
119 | expect(exported.endWords).toEqual(markov.endWords)
120 |
121 | expect(exported.options).toEqual(markov.options)
122 | expect(exported.options).not.toBe(markov.options)
123 | })
124 | })
125 |
126 | describe('Import data', () => {
127 | it('should overwrite original values', () => {
128 | const exported = markov.export()
129 | const newMarkov = new Markov()
130 |
131 | // Make sure that the corpus is empty
132 | expect(newMarkov.corpus).toEqual({})
133 |
134 | newMarkov.import(exported)
135 |
136 | expect(newMarkov.corpus).toEqual(exported.corpus)
137 | expect(newMarkov.corpus).not.toBe(exported.corpus)
138 |
139 | expect(newMarkov.startWords).toEqual(exported.startWords)
140 | expect(newMarkov.startWords).not.toBe(exported.startWords)
141 |
142 | expect(newMarkov.endWords).toEqual(exported.endWords)
143 | expect(newMarkov.endWords).not.toBe(exported.endWords)
144 |
145 | expect(newMarkov.options).toEqual(exported.options)
146 | expect(newMarkov.options).not.toBe(exported.options)
147 | })
148 | })
149 | })
150 |
151 | describe('The sentence generator', () => {
152 | let markov: Markov
153 | beforeEach(() => {
154 | markov = new Markov()
155 | markov.addData(data)
156 | })
157 |
158 | it('should throw an error if the corpus is not built', () => {
159 | markov = new Markov()
160 | expect(() => {
161 | markov.generate()
162 | }).toThrowError('Corpus is empty. There is either no data, or the data is not sufficient to create markov chains.')
163 | })
164 |
165 | it('should return a result if under the tries limit', () => {
166 | expect.assertions(10)
167 |
168 | for (let i = 0; i < 10; i++) {
169 | const sentence = markov.generate({ maxTries: 20 })
170 | expect(sentence.tries).toBeLessThanOrEqual(20)
171 | }
172 | })
173 |
174 | it('should call the `filter` callback', () => {
175 | const filter = vi.fn(x => true)
176 | markov.generate({ filter })
177 | expect(filter).toHaveBeenCalled()
178 | })
179 |
180 | it('should throw an error after 10 tries, by default', () => {
181 | expect(() => {
182 | markov.generate({
183 | filter(result: MarkovResult): boolean {
184 | return false
185 | }
186 | })
187 | }).toThrowError('10')
188 | })
189 |
190 | it('should end with a value from endWords', async () => {
191 | expect.assertions(10)
192 |
193 | for (let i = 0; i < 10; i++) {
194 | const result = markov.generate()
195 | const arr = result.string.split(' ')
196 | const end = arr.slice(arr.length - 2, arr.length)
197 | expect(map(markov.endWords, 'words')).toContain(end.join(' '))
198 | }
199 | })
200 |
201 | it(`should pass the result object to 'filter(result)'`, async () => {
202 | expect.assertions(6)
203 |
204 | const options = {
205 | minWords: 5,
206 | maxTries: 10,
207 | filter: (result: MarkovResult): boolean => {
208 | expect(Object.keys(result)).toHaveLength(4)
209 | expect(result).toHaveProperty('string')
210 | expect(result).toHaveProperty('score')
211 | expect(result).toHaveProperty('refs')
212 | expect(Array.isArray(result.refs)).toBeTruthy()
213 | expect(result).toHaveProperty('tries')
214 | return true
215 | }
216 | }
217 | markov.generate(options)
218 | })
219 |
220 | })
221 | })
222 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | cloneDeep,
3 | flatten,
4 | includes,
5 | isEmpty,
6 | isString,
7 | slice,
8 | some,
9 | uniqBy,
10 | assignIn
11 | } from 'lodash-es'
12 |
13 | export type MarkovInputData = { string: string }[]
14 |
15 | export type MarkovGenerateOptions = {
16 | maxTries?: number
17 | prng?: () => number
18 | filter?: (result: MarkovResult) => boolean
19 | }
20 |
21 | /**
22 | * Data to build the Markov instance
23 | */
24 | export type MarkovConstructorOptions = {
25 | stateSize?: number
26 | }
27 |
28 | /**
29 | * While `stateSize` is optional as a constructor parameter,
30 | * it must exist as a member
31 | */
32 | export type MarkovDataMembers = {
33 | stateSize: number
34 | }
35 |
36 | export type MarkovResult = {
37 | string: string
38 | score: number
39 | refs: MarkovInputData
40 | tries: number
41 | }
42 |
43 | export type MarkovFragment = {
44 | words: string
45 | refs: MarkovInputData
46 | }
47 |
48 | export type Corpus = { [key: string]: MarkovFragment[] }
49 |
50 | export type MarkovImportExport = {
51 | corpus: Corpus
52 | startWords: MarkovFragment[]
53 | endWords: MarkovFragment[]
54 | options: MarkovDataMembers
55 | }
56 |
57 | function sampleWithPRNG(
58 | array: T[],
59 | prng: () => number = Math.random
60 | ): T | undefined {
61 | const length = array == null ? 0 : array.length
62 | return length ? array[Math.floor(prng() * length)] : undefined
63 | }
64 |
65 | export default class Markov {
66 | public data: MarkovInputData
67 | public options: MarkovDataMembers
68 |
69 | public startWords: MarkovFragment[] = []
70 | public endWords: MarkovFragment[] = []
71 | public corpus: Corpus = {}
72 |
73 | private defaultOptions: MarkovDataMembers = {
74 | stateSize: 2,
75 | }
76 |
77 | /**
78 | * Creates an instance of Markov generator.
79 | *
80 | * @param {MarkovConstructorOptions} [options={}]
81 | * @memberof Markov
82 | */
83 | constructor(options: MarkovConstructorOptions = {}) {
84 | this.data = []
85 |
86 | // Save options
87 | this.options = this.defaultOptions
88 | assignIn(this.options, options)
89 | }
90 |
91 | /**
92 | * Imports a corpus. This overwrites existing data.
93 | *
94 | * @param data
95 | */
96 | public import(data: MarkovImportExport): void {
97 | this.options = cloneDeep(data.options)
98 | this.corpus = cloneDeep(data.corpus)
99 | this.startWords = cloneDeep(data.startWords)
100 | this.endWords = cloneDeep(data.endWords)
101 | }
102 |
103 | /**
104 | * Exports structed data used to generate sentence.
105 | */
106 | public export(): MarkovImportExport {
107 | return cloneDeep({
108 | options: this.options,
109 | corpus: this.corpus,
110 | startWords: this.startWords,
111 | endWords: this.endWords,
112 | })
113 | }
114 |
115 | public addData(rawData: MarkovInputData | string[]) {
116 | // Format data if necessary
117 | let input: MarkovInputData = []
118 | if (isString(rawData[0])) {
119 | input = (rawData as string[]).map((s) => ({ string: s }))
120 | } else if (rawData[0].hasOwnProperty('string')) {
121 | input = rawData as MarkovInputData
122 | } else {
123 | throw new Error('Objects in your corpus must have a "string" property')
124 | }
125 |
126 | this.buildCorpus(input)
127 |
128 | this.data = this.data.concat(input)
129 | }
130 |
131 | /**
132 | * Builds the corpus. You must call this before generating sentences.
133 | *
134 | * @memberof Markov
135 | */
136 | private buildCorpus(data: MarkovInputData): void {
137 | const options = this.options
138 |
139 | // Loop through all sentences
140 | data.forEach((item) => {
141 | const line = item.string
142 | const words = line.split(' ')
143 | const stateSize = options.stateSize // Default value of 2 is set in the constructor
144 |
145 | //#region Start words
146 | // "Start words" is the list of words that can start a generated chain.
147 |
148 | const start = slice(words, 0, stateSize).join(' ')
149 | const oldStartObj = this.startWords.find((o) => o.words === start)
150 |
151 | // If we already have identical startWords
152 | if (oldStartObj) {
153 | // If the current item is not present in the references, add it
154 | if (!includes(oldStartObj.refs, item)) {
155 | oldStartObj.refs.push(item)
156 | }
157 | } else {
158 | // Add the startWords (and reference) to the list
159 | this.startWords.push({ words: start, refs: [item] })
160 | }
161 |
162 | //#endregion Start words
163 |
164 | //#region End words
165 | // "End words" is the list of words that can end a generated chain.
166 |
167 | const end = slice(words, words.length - stateSize, words.length).join(' ')
168 | const oldEndObj = this.endWords.find((o) => o.words === end)
169 | if (oldEndObj) {
170 | if (!includes(oldEndObj.refs, item)) {
171 | oldEndObj.refs.push(item)
172 | }
173 | } else {
174 | this.endWords.push({ words: end, refs: [item] })
175 | }
176 |
177 | //#endregion End words
178 |
179 | //#region Corpus generation
180 |
181 | // We loop through all words in the sentence to build "blocks" of `stateSize`
182 | // e.g. for a stateSize of 2, "lorem ipsum dolor sit amet" will have the following blocks:
183 | // "lorem ipsum", "ipsum dolor", "dolor sit", and "sit amet"
184 | for (let i = 0; i < words.length - 1; i++) {
185 | const curr = slice(words, i, i + stateSize).join(' ')
186 | const next = slice(words, i + stateSize, i + stateSize * 2).join(' ')
187 | if (!next || next.split(' ').length !== options.stateSize) {
188 | continue
189 | }
190 |
191 | // Check if the corpus already has a corresponding "curr" block
192 | if (this.corpus.hasOwnProperty(curr)) {
193 | const oldObj = this.corpus[curr].find((o) => o.words === next)
194 | if (oldObj) {
195 | // If the corpus already has the chain "curr -> next",
196 | // just add the current reference for this block
197 | oldObj.refs.push(item)
198 | } else {
199 | // Add the new "next" block in the list of possible paths for "curr"
200 | this.corpus[curr].push({ words: next, refs: [item] })
201 | }
202 | } else {
203 | // Add the "curr" block and link it with the "next" one
204 | this.corpus[curr] = [{ words: next, refs: [item] }]
205 | }
206 | }
207 |
208 | //#endregion Corpus generation
209 | })
210 | }
211 |
212 | /**
213 | * Generates a result, that contains a string and its references
214 | *
215 | * @param {MarkovGenerateOptions} [options={}]
216 | * @returns {MarkovResult}
217 | * @memberof Markov
218 | */
219 | public generate(options: MarkovGenerateOptions = {}): MarkovResult {
220 | if (isEmpty(this.corpus)) {
221 | throw new Error(
222 | 'Corpus is empty. There is either no data, or the data is not sufficient to create markov chains.'
223 | )
224 | }
225 |
226 | const corpus = cloneDeep(this.corpus)
227 | const maxTries = options.maxTries ? options.maxTries : 10
228 | const prng = options.prng ? options.prng : Math.random
229 |
230 | let tries: number
231 |
232 | // We loop through fragments to create a complete sentence
233 | for (tries = 1; tries <= maxTries; tries++) {
234 | let ended = false
235 |
236 | // Create an array of MarkovCorpusItems
237 | // The first item is a random startWords element
238 | const arr = [sampleWithPRNG(this.startWords, prng)!]
239 |
240 | let score = 0
241 |
242 | // loop to build a complete sentence
243 | for (let innerTries = 0; innerTries < maxTries; innerTries++) {
244 | const block = arr[arr.length - 1] // last value in array
245 | const state = sampleWithPRNG(corpus[block.words], prng) // Find a following item in the corpus
246 |
247 | // If a state cannot be found, the sentence can't be completed
248 | if (!state) {
249 | break
250 | }
251 |
252 | // add new state to list
253 | arr.push(state)
254 |
255 | // increment score
256 | score += corpus[block.words].length - 1 // increment score
257 |
258 | // is sentence finished?
259 | if (some(this.endWords, { words: state.words })) {
260 | ended = true
261 | break
262 | }
263 | }
264 |
265 | const sentence = arr
266 | .map((o) => o.words)
267 | .join(' ')
268 | .trim()
269 |
270 | const result = {
271 | string: sentence,
272 | score,
273 | refs: uniqBy(flatten(arr.map((o) => o.refs)), 'string'),
274 | tries,
275 | }
276 |
277 | // sentence is not ended or incorrect
278 | if (
279 | !ended ||
280 | (typeof options.filter === 'function' && !options.filter(result))
281 | ) {
282 | continue
283 | }
284 |
285 | return result
286 | }
287 | throw new Error(
288 | `Failed to build a sentence after ${tries - 1
289 | } tries. Possible solutions: try a less restrictive filter(), give more raw data to the corpus builder, or increase the number of maximum tries.`
290 | )
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | overrides:
8 | tough-cookie@<4.1.3: '>=4.1.3'
9 | esbuild@<=0.24.2: '>=0.25.0'
10 | form-data@<2.5.4: '>=2.5.4'
11 |
12 | importers:
13 |
14 | .:
15 | dependencies:
16 | lodash-es:
17 | specifier: ^4.17.21
18 | version: 4.17.21
19 | devDependencies:
20 | '@types/lodash':
21 | specifier: ^4.17.21
22 | version: 4.17.21
23 | '@types/lodash-es':
24 | specifier: ^4.17.12
25 | version: 4.17.12
26 | '@types/node':
27 | specifier: ^22.19.2
28 | version: 22.19.2
29 | '@vitest/coverage-v8':
30 | specifier: 2.1.8
31 | version: 2.1.8(vitest@2.1.9(@types/node@22.19.2))
32 | coveralls-next:
33 | specifier: ^6.0.1
34 | version: 6.0.1
35 | prettier:
36 | specifier: ^3.7.4
37 | version: 3.7.4
38 | typescript:
39 | specifier: ^5.9.3
40 | version: 5.9.3
41 | vitest:
42 | specifier: ^2.1.9
43 | version: 2.1.9(@types/node@22.19.2)
44 |
45 | packages:
46 |
47 | '@ampproject/remapping@2.3.0':
48 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
49 | engines: {node: '>=6.0.0'}
50 |
51 | '@babel/helper-string-parser@7.27.1':
52 | resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
53 | engines: {node: '>=6.9.0'}
54 |
55 | '@babel/helper-validator-identifier@7.28.5':
56 | resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
57 | engines: {node: '>=6.9.0'}
58 |
59 | '@babel/parser@7.28.5':
60 | resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
61 | engines: {node: '>=6.0.0'}
62 | hasBin: true
63 |
64 | '@babel/types@7.28.5':
65 | resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
66 | engines: {node: '>=6.9.0'}
67 |
68 | '@bcoe/v8-coverage@0.2.3':
69 | resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
70 |
71 | '@esbuild/aix-ppc64@0.25.12':
72 | resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
73 | engines: {node: '>=18'}
74 | cpu: [ppc64]
75 | os: [aix]
76 |
77 | '@esbuild/android-arm64@0.25.12':
78 | resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
79 | engines: {node: '>=18'}
80 | cpu: [arm64]
81 | os: [android]
82 |
83 | '@esbuild/android-arm@0.25.12':
84 | resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
85 | engines: {node: '>=18'}
86 | cpu: [arm]
87 | os: [android]
88 |
89 | '@esbuild/android-x64@0.25.12':
90 | resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
91 | engines: {node: '>=18'}
92 | cpu: [x64]
93 | os: [android]
94 |
95 | '@esbuild/darwin-arm64@0.25.12':
96 | resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
97 | engines: {node: '>=18'}
98 | cpu: [arm64]
99 | os: [darwin]
100 |
101 | '@esbuild/darwin-x64@0.25.12':
102 | resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
103 | engines: {node: '>=18'}
104 | cpu: [x64]
105 | os: [darwin]
106 |
107 | '@esbuild/freebsd-arm64@0.25.12':
108 | resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
109 | engines: {node: '>=18'}
110 | cpu: [arm64]
111 | os: [freebsd]
112 |
113 | '@esbuild/freebsd-x64@0.25.12':
114 | resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
115 | engines: {node: '>=18'}
116 | cpu: [x64]
117 | os: [freebsd]
118 |
119 | '@esbuild/linux-arm64@0.25.12':
120 | resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
121 | engines: {node: '>=18'}
122 | cpu: [arm64]
123 | os: [linux]
124 |
125 | '@esbuild/linux-arm@0.25.12':
126 | resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
127 | engines: {node: '>=18'}
128 | cpu: [arm]
129 | os: [linux]
130 |
131 | '@esbuild/linux-ia32@0.25.12':
132 | resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
133 | engines: {node: '>=18'}
134 | cpu: [ia32]
135 | os: [linux]
136 |
137 | '@esbuild/linux-loong64@0.25.12':
138 | resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
139 | engines: {node: '>=18'}
140 | cpu: [loong64]
141 | os: [linux]
142 |
143 | '@esbuild/linux-mips64el@0.25.12':
144 | resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
145 | engines: {node: '>=18'}
146 | cpu: [mips64el]
147 | os: [linux]
148 |
149 | '@esbuild/linux-ppc64@0.25.12':
150 | resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
151 | engines: {node: '>=18'}
152 | cpu: [ppc64]
153 | os: [linux]
154 |
155 | '@esbuild/linux-riscv64@0.25.12':
156 | resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
157 | engines: {node: '>=18'}
158 | cpu: [riscv64]
159 | os: [linux]
160 |
161 | '@esbuild/linux-s390x@0.25.12':
162 | resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
163 | engines: {node: '>=18'}
164 | cpu: [s390x]
165 | os: [linux]
166 |
167 | '@esbuild/linux-x64@0.25.12':
168 | resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
169 | engines: {node: '>=18'}
170 | cpu: [x64]
171 | os: [linux]
172 |
173 | '@esbuild/netbsd-arm64@0.25.12':
174 | resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
175 | engines: {node: '>=18'}
176 | cpu: [arm64]
177 | os: [netbsd]
178 |
179 | '@esbuild/netbsd-x64@0.25.12':
180 | resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
181 | engines: {node: '>=18'}
182 | cpu: [x64]
183 | os: [netbsd]
184 |
185 | '@esbuild/openbsd-arm64@0.25.12':
186 | resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
187 | engines: {node: '>=18'}
188 | cpu: [arm64]
189 | os: [openbsd]
190 |
191 | '@esbuild/openbsd-x64@0.25.12':
192 | resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
193 | engines: {node: '>=18'}
194 | cpu: [x64]
195 | os: [openbsd]
196 |
197 | '@esbuild/openharmony-arm64@0.25.12':
198 | resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
199 | engines: {node: '>=18'}
200 | cpu: [arm64]
201 | os: [openharmony]
202 |
203 | '@esbuild/sunos-x64@0.25.12':
204 | resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
205 | engines: {node: '>=18'}
206 | cpu: [x64]
207 | os: [sunos]
208 |
209 | '@esbuild/win32-arm64@0.25.12':
210 | resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
211 | engines: {node: '>=18'}
212 | cpu: [arm64]
213 | os: [win32]
214 |
215 | '@esbuild/win32-ia32@0.25.12':
216 | resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
217 | engines: {node: '>=18'}
218 | cpu: [ia32]
219 | os: [win32]
220 |
221 | '@esbuild/win32-x64@0.25.12':
222 | resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
223 | engines: {node: '>=18'}
224 | cpu: [x64]
225 | os: [win32]
226 |
227 | '@isaacs/cliui@8.0.2':
228 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
229 | engines: {node: '>=12'}
230 |
231 | '@istanbuljs/schema@0.1.3':
232 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
233 | engines: {node: '>=8'}
234 |
235 | '@jridgewell/gen-mapping@0.3.13':
236 | resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
237 |
238 | '@jridgewell/resolve-uri@3.1.2':
239 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
240 | engines: {node: '>=6.0.0'}
241 |
242 | '@jridgewell/sourcemap-codec@1.5.5':
243 | resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
244 |
245 | '@jridgewell/trace-mapping@0.3.31':
246 | resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
247 |
248 | '@pkgjs/parseargs@0.11.0':
249 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
250 | engines: {node: '>=14'}
251 |
252 | '@rollup/rollup-android-arm-eabi@4.53.3':
253 | resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==}
254 | cpu: [arm]
255 | os: [android]
256 |
257 | '@rollup/rollup-android-arm64@4.53.3':
258 | resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==}
259 | cpu: [arm64]
260 | os: [android]
261 |
262 | '@rollup/rollup-darwin-arm64@4.53.3':
263 | resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==}
264 | cpu: [arm64]
265 | os: [darwin]
266 |
267 | '@rollup/rollup-darwin-x64@4.53.3':
268 | resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==}
269 | cpu: [x64]
270 | os: [darwin]
271 |
272 | '@rollup/rollup-freebsd-arm64@4.53.3':
273 | resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==}
274 | cpu: [arm64]
275 | os: [freebsd]
276 |
277 | '@rollup/rollup-freebsd-x64@4.53.3':
278 | resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==}
279 | cpu: [x64]
280 | os: [freebsd]
281 |
282 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3':
283 | resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
284 | cpu: [arm]
285 | os: [linux]
286 |
287 | '@rollup/rollup-linux-arm-musleabihf@4.53.3':
288 | resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
289 | cpu: [arm]
290 | os: [linux]
291 |
292 | '@rollup/rollup-linux-arm64-gnu@4.53.3':
293 | resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
294 | cpu: [arm64]
295 | os: [linux]
296 |
297 | '@rollup/rollup-linux-arm64-musl@4.53.3':
298 | resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
299 | cpu: [arm64]
300 | os: [linux]
301 |
302 | '@rollup/rollup-linux-loong64-gnu@4.53.3':
303 | resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
304 | cpu: [loong64]
305 | os: [linux]
306 |
307 | '@rollup/rollup-linux-ppc64-gnu@4.53.3':
308 | resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
309 | cpu: [ppc64]
310 | os: [linux]
311 |
312 | '@rollup/rollup-linux-riscv64-gnu@4.53.3':
313 | resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
314 | cpu: [riscv64]
315 | os: [linux]
316 |
317 | '@rollup/rollup-linux-riscv64-musl@4.53.3':
318 | resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
319 | cpu: [riscv64]
320 | os: [linux]
321 |
322 | '@rollup/rollup-linux-s390x-gnu@4.53.3':
323 | resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
324 | cpu: [s390x]
325 | os: [linux]
326 |
327 | '@rollup/rollup-linux-x64-gnu@4.53.3':
328 | resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
329 | cpu: [x64]
330 | os: [linux]
331 |
332 | '@rollup/rollup-linux-x64-musl@4.53.3':
333 | resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
334 | cpu: [x64]
335 | os: [linux]
336 |
337 | '@rollup/rollup-openharmony-arm64@4.53.3':
338 | resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
339 | cpu: [arm64]
340 | os: [openharmony]
341 |
342 | '@rollup/rollup-win32-arm64-msvc@4.53.3':
343 | resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==}
344 | cpu: [arm64]
345 | os: [win32]
346 |
347 | '@rollup/rollup-win32-ia32-msvc@4.53.3':
348 | resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==}
349 | cpu: [ia32]
350 | os: [win32]
351 |
352 | '@rollup/rollup-win32-x64-gnu@4.53.3':
353 | resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==}
354 | cpu: [x64]
355 | os: [win32]
356 |
357 | '@rollup/rollup-win32-x64-msvc@4.53.3':
358 | resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==}
359 | cpu: [x64]
360 | os: [win32]
361 |
362 | '@types/estree@1.0.8':
363 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
364 |
365 | '@types/lodash-es@4.17.12':
366 | resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
367 |
368 | '@types/lodash@4.17.21':
369 | resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==}
370 |
371 | '@types/node@22.19.2':
372 | resolution: {integrity: sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==}
373 |
374 | '@vitest/coverage-v8@2.1.8':
375 | resolution: {integrity: sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==}
376 | peerDependencies:
377 | '@vitest/browser': 2.1.8
378 | vitest: 2.1.8
379 | peerDependenciesMeta:
380 | '@vitest/browser':
381 | optional: true
382 |
383 | '@vitest/expect@2.1.9':
384 | resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
385 |
386 | '@vitest/mocker@2.1.9':
387 | resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==}
388 | peerDependencies:
389 | msw: ^2.4.9
390 | vite: ^5.0.0
391 | peerDependenciesMeta:
392 | msw:
393 | optional: true
394 | vite:
395 | optional: true
396 |
397 | '@vitest/pretty-format@2.1.9':
398 | resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
399 |
400 | '@vitest/runner@2.1.9':
401 | resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==}
402 |
403 | '@vitest/snapshot@2.1.9':
404 | resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==}
405 |
406 | '@vitest/spy@2.1.9':
407 | resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==}
408 |
409 | '@vitest/utils@2.1.9':
410 | resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
411 |
412 | ansi-regex@5.0.1:
413 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
414 | engines: {node: '>=8'}
415 |
416 | ansi-regex@6.2.2:
417 | resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
418 | engines: {node: '>=12'}
419 |
420 | ansi-styles@4.3.0:
421 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
422 | engines: {node: '>=8'}
423 |
424 | ansi-styles@6.2.3:
425 | resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
426 | engines: {node: '>=12'}
427 |
428 | argparse@2.0.1:
429 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
430 |
431 | assertion-error@2.0.1:
432 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
433 | engines: {node: '>=12'}
434 |
435 | balanced-match@1.0.2:
436 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
437 |
438 | brace-expansion@2.0.2:
439 | resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
440 |
441 | cac@6.7.14:
442 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
443 | engines: {node: '>=8'}
444 |
445 | chai@5.3.3:
446 | resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
447 | engines: {node: '>=18'}
448 |
449 | check-error@2.1.1:
450 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
451 | engines: {node: '>= 16'}
452 |
453 | color-convert@2.0.1:
454 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
455 | engines: {node: '>=7.0.0'}
456 |
457 | color-name@1.1.4:
458 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
459 |
460 | coveralls-next@6.0.1:
461 | resolution: {integrity: sha512-G0xhUJE9M3OCKf8Xn/cGWrIh4xJI1w7MgJx30HpUfJf6yxyFS1SVGgXtFKmPGb5qEEh4H6oTUk0JQRVjq0ZgDQ==}
462 | engines: {node: '>=20'}
463 | hasBin: true
464 |
465 | cross-spawn@7.0.6:
466 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
467 | engines: {node: '>= 8'}
468 |
469 | debug@4.4.3:
470 | resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
471 | engines: {node: '>=6.0'}
472 | peerDependencies:
473 | supports-color: '*'
474 | peerDependenciesMeta:
475 | supports-color:
476 | optional: true
477 |
478 | deep-eql@5.0.2:
479 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
480 | engines: {node: '>=6'}
481 |
482 | eastasianwidth@0.2.0:
483 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
484 |
485 | emoji-regex@8.0.0:
486 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
487 |
488 | emoji-regex@9.2.2:
489 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
490 |
491 | es-module-lexer@1.7.0:
492 | resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
493 |
494 | esbuild@0.25.12:
495 | resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
496 | engines: {node: '>=18'}
497 | hasBin: true
498 |
499 | estree-walker@3.0.3:
500 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
501 |
502 | expect-type@1.3.0:
503 | resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
504 | engines: {node: '>=12.0.0'}
505 |
506 | foreground-child@3.3.1:
507 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
508 | engines: {node: '>=14'}
509 |
510 | fsevents@2.3.3:
511 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
512 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
513 | os: [darwin]
514 |
515 | glob@10.5.0:
516 | resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
517 | hasBin: true
518 |
519 | has-flag@4.0.0:
520 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
521 | engines: {node: '>=8'}
522 |
523 | html-escaper@2.0.2:
524 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
525 |
526 | is-fullwidth-code-point@3.0.0:
527 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
528 | engines: {node: '>=8'}
529 |
530 | isexe@2.0.0:
531 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
532 |
533 | istanbul-lib-coverage@3.2.2:
534 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
535 | engines: {node: '>=8'}
536 |
537 | istanbul-lib-report@3.0.1:
538 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
539 | engines: {node: '>=10'}
540 |
541 | istanbul-lib-source-maps@5.0.6:
542 | resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
543 | engines: {node: '>=10'}
544 |
545 | istanbul-reports@3.2.0:
546 | resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
547 | engines: {node: '>=8'}
548 |
549 | jackspeak@3.4.3:
550 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
551 |
552 | js-yaml@4.1.1:
553 | resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
554 | hasBin: true
555 |
556 | lcov-parse@1.0.0:
557 | resolution: {integrity: sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==}
558 | hasBin: true
559 |
560 | lodash-es@4.17.21:
561 | resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
562 |
563 | loupe@3.2.1:
564 | resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
565 |
566 | lru-cache@10.4.3:
567 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
568 |
569 | magic-string@0.30.21:
570 | resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
571 |
572 | magicast@0.3.5:
573 | resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
574 |
575 | make-dir@4.0.0:
576 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
577 | engines: {node: '>=10'}
578 |
579 | minimatch@9.0.5:
580 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
581 | engines: {node: '>=16 || 14 >=14.17'}
582 |
583 | minipass@7.1.2:
584 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
585 | engines: {node: '>=16 || 14 >=14.17'}
586 |
587 | ms@2.1.3:
588 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
589 |
590 | nanoid@3.3.11:
591 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
592 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
593 | hasBin: true
594 |
595 | package-json-from-dist@1.0.1:
596 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
597 |
598 | path-key@3.1.1:
599 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
600 | engines: {node: '>=8'}
601 |
602 | path-scurry@1.11.1:
603 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
604 | engines: {node: '>=16 || 14 >=14.18'}
605 |
606 | pathe@1.1.2:
607 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
608 |
609 | pathval@2.0.1:
610 | resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
611 | engines: {node: '>= 14.16'}
612 |
613 | picocolors@1.1.1:
614 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
615 |
616 | postcss@8.5.6:
617 | resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
618 | engines: {node: ^10 || ^12 || >=14}
619 |
620 | prettier@3.7.4:
621 | resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
622 | engines: {node: '>=14'}
623 | hasBin: true
624 |
625 | rollup@4.53.3:
626 | resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==}
627 | engines: {node: '>=18.0.0', npm: '>=8.0.0'}
628 | hasBin: true
629 |
630 | semver@7.7.3:
631 | resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
632 | engines: {node: '>=10'}
633 | hasBin: true
634 |
635 | shebang-command@2.0.0:
636 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
637 | engines: {node: '>=8'}
638 |
639 | shebang-regex@3.0.0:
640 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
641 | engines: {node: '>=8'}
642 |
643 | siginfo@2.0.0:
644 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
645 |
646 | signal-exit@4.1.0:
647 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
648 | engines: {node: '>=14'}
649 |
650 | source-map-js@1.2.1:
651 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
652 | engines: {node: '>=0.10.0'}
653 |
654 | stackback@0.0.2:
655 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
656 |
657 | std-env@3.10.0:
658 | resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
659 |
660 | string-width@4.2.3:
661 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
662 | engines: {node: '>=8'}
663 |
664 | string-width@5.1.2:
665 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
666 | engines: {node: '>=12'}
667 |
668 | strip-ansi@6.0.1:
669 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
670 | engines: {node: '>=8'}
671 |
672 | strip-ansi@7.1.2:
673 | resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
674 | engines: {node: '>=12'}
675 |
676 | supports-color@7.2.0:
677 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
678 | engines: {node: '>=8'}
679 |
680 | test-exclude@7.0.1:
681 | resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
682 | engines: {node: '>=18'}
683 |
684 | tinybench@2.9.0:
685 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
686 |
687 | tinyexec@0.3.2:
688 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
689 |
690 | tinypool@1.1.1:
691 | resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
692 | engines: {node: ^18.0.0 || >=20.0.0}
693 |
694 | tinyrainbow@1.2.0:
695 | resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
696 | engines: {node: '>=14.0.0'}
697 |
698 | tinyspy@3.0.2:
699 | resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
700 | engines: {node: '>=14.0.0'}
701 |
702 | typescript@5.9.3:
703 | resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
704 | engines: {node: '>=14.17'}
705 | hasBin: true
706 |
707 | undici-types@6.21.0:
708 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
709 |
710 | vite-node@2.1.9:
711 | resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
712 | engines: {node: ^18.0.0 || >=20.0.0}
713 | hasBin: true
714 |
715 | vite@5.4.21:
716 | resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
717 | engines: {node: ^18.0.0 || >=20.0.0}
718 | hasBin: true
719 | peerDependencies:
720 | '@types/node': ^18.0.0 || >=20.0.0
721 | less: '*'
722 | lightningcss: ^1.21.0
723 | sass: '*'
724 | sass-embedded: '*'
725 | stylus: '*'
726 | sugarss: '*'
727 | terser: ^5.4.0
728 | peerDependenciesMeta:
729 | '@types/node':
730 | optional: true
731 | less:
732 | optional: true
733 | lightningcss:
734 | optional: true
735 | sass:
736 | optional: true
737 | sass-embedded:
738 | optional: true
739 | stylus:
740 | optional: true
741 | sugarss:
742 | optional: true
743 | terser:
744 | optional: true
745 |
746 | vitest@2.1.9:
747 | resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==}
748 | engines: {node: ^18.0.0 || >=20.0.0}
749 | hasBin: true
750 | peerDependencies:
751 | '@edge-runtime/vm': '*'
752 | '@types/node': ^18.0.0 || >=20.0.0
753 | '@vitest/browser': 2.1.9
754 | '@vitest/ui': 2.1.9
755 | happy-dom: '*'
756 | jsdom: '*'
757 | peerDependenciesMeta:
758 | '@edge-runtime/vm':
759 | optional: true
760 | '@types/node':
761 | optional: true
762 | '@vitest/browser':
763 | optional: true
764 | '@vitest/ui':
765 | optional: true
766 | happy-dom:
767 | optional: true
768 | jsdom:
769 | optional: true
770 |
771 | which@2.0.2:
772 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
773 | engines: {node: '>= 8'}
774 | hasBin: true
775 |
776 | why-is-node-running@2.3.0:
777 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
778 | engines: {node: '>=8'}
779 | hasBin: true
780 |
781 | wrap-ansi@7.0.0:
782 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
783 | engines: {node: '>=10'}
784 |
785 | wrap-ansi@8.1.0:
786 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
787 | engines: {node: '>=12'}
788 |
789 | snapshots:
790 |
791 | '@ampproject/remapping@2.3.0':
792 | dependencies:
793 | '@jridgewell/gen-mapping': 0.3.13
794 | '@jridgewell/trace-mapping': 0.3.31
795 |
796 | '@babel/helper-string-parser@7.27.1': {}
797 |
798 | '@babel/helper-validator-identifier@7.28.5': {}
799 |
800 | '@babel/parser@7.28.5':
801 | dependencies:
802 | '@babel/types': 7.28.5
803 |
804 | '@babel/types@7.28.5':
805 | dependencies:
806 | '@babel/helper-string-parser': 7.27.1
807 | '@babel/helper-validator-identifier': 7.28.5
808 |
809 | '@bcoe/v8-coverage@0.2.3': {}
810 |
811 | '@esbuild/aix-ppc64@0.25.12':
812 | optional: true
813 |
814 | '@esbuild/android-arm64@0.25.12':
815 | optional: true
816 |
817 | '@esbuild/android-arm@0.25.12':
818 | optional: true
819 |
820 | '@esbuild/android-x64@0.25.12':
821 | optional: true
822 |
823 | '@esbuild/darwin-arm64@0.25.12':
824 | optional: true
825 |
826 | '@esbuild/darwin-x64@0.25.12':
827 | optional: true
828 |
829 | '@esbuild/freebsd-arm64@0.25.12':
830 | optional: true
831 |
832 | '@esbuild/freebsd-x64@0.25.12':
833 | optional: true
834 |
835 | '@esbuild/linux-arm64@0.25.12':
836 | optional: true
837 |
838 | '@esbuild/linux-arm@0.25.12':
839 | optional: true
840 |
841 | '@esbuild/linux-ia32@0.25.12':
842 | optional: true
843 |
844 | '@esbuild/linux-loong64@0.25.12':
845 | optional: true
846 |
847 | '@esbuild/linux-mips64el@0.25.12':
848 | optional: true
849 |
850 | '@esbuild/linux-ppc64@0.25.12':
851 | optional: true
852 |
853 | '@esbuild/linux-riscv64@0.25.12':
854 | optional: true
855 |
856 | '@esbuild/linux-s390x@0.25.12':
857 | optional: true
858 |
859 | '@esbuild/linux-x64@0.25.12':
860 | optional: true
861 |
862 | '@esbuild/netbsd-arm64@0.25.12':
863 | optional: true
864 |
865 | '@esbuild/netbsd-x64@0.25.12':
866 | optional: true
867 |
868 | '@esbuild/openbsd-arm64@0.25.12':
869 | optional: true
870 |
871 | '@esbuild/openbsd-x64@0.25.12':
872 | optional: true
873 |
874 | '@esbuild/openharmony-arm64@0.25.12':
875 | optional: true
876 |
877 | '@esbuild/sunos-x64@0.25.12':
878 | optional: true
879 |
880 | '@esbuild/win32-arm64@0.25.12':
881 | optional: true
882 |
883 | '@esbuild/win32-ia32@0.25.12':
884 | optional: true
885 |
886 | '@esbuild/win32-x64@0.25.12':
887 | optional: true
888 |
889 | '@isaacs/cliui@8.0.2':
890 | dependencies:
891 | string-width: 5.1.2
892 | string-width-cjs: string-width@4.2.3
893 | strip-ansi: 7.1.2
894 | strip-ansi-cjs: strip-ansi@6.0.1
895 | wrap-ansi: 8.1.0
896 | wrap-ansi-cjs: wrap-ansi@7.0.0
897 |
898 | '@istanbuljs/schema@0.1.3': {}
899 |
900 | '@jridgewell/gen-mapping@0.3.13':
901 | dependencies:
902 | '@jridgewell/sourcemap-codec': 1.5.5
903 | '@jridgewell/trace-mapping': 0.3.31
904 |
905 | '@jridgewell/resolve-uri@3.1.2': {}
906 |
907 | '@jridgewell/sourcemap-codec@1.5.5': {}
908 |
909 | '@jridgewell/trace-mapping@0.3.31':
910 | dependencies:
911 | '@jridgewell/resolve-uri': 3.1.2
912 | '@jridgewell/sourcemap-codec': 1.5.5
913 |
914 | '@pkgjs/parseargs@0.11.0':
915 | optional: true
916 |
917 | '@rollup/rollup-android-arm-eabi@4.53.3':
918 | optional: true
919 |
920 | '@rollup/rollup-android-arm64@4.53.3':
921 | optional: true
922 |
923 | '@rollup/rollup-darwin-arm64@4.53.3':
924 | optional: true
925 |
926 | '@rollup/rollup-darwin-x64@4.53.3':
927 | optional: true
928 |
929 | '@rollup/rollup-freebsd-arm64@4.53.3':
930 | optional: true
931 |
932 | '@rollup/rollup-freebsd-x64@4.53.3':
933 | optional: true
934 |
935 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3':
936 | optional: true
937 |
938 | '@rollup/rollup-linux-arm-musleabihf@4.53.3':
939 | optional: true
940 |
941 | '@rollup/rollup-linux-arm64-gnu@4.53.3':
942 | optional: true
943 |
944 | '@rollup/rollup-linux-arm64-musl@4.53.3':
945 | optional: true
946 |
947 | '@rollup/rollup-linux-loong64-gnu@4.53.3':
948 | optional: true
949 |
950 | '@rollup/rollup-linux-ppc64-gnu@4.53.3':
951 | optional: true
952 |
953 | '@rollup/rollup-linux-riscv64-gnu@4.53.3':
954 | optional: true
955 |
956 | '@rollup/rollup-linux-riscv64-musl@4.53.3':
957 | optional: true
958 |
959 | '@rollup/rollup-linux-s390x-gnu@4.53.3':
960 | optional: true
961 |
962 | '@rollup/rollup-linux-x64-gnu@4.53.3':
963 | optional: true
964 |
965 | '@rollup/rollup-linux-x64-musl@4.53.3':
966 | optional: true
967 |
968 | '@rollup/rollup-openharmony-arm64@4.53.3':
969 | optional: true
970 |
971 | '@rollup/rollup-win32-arm64-msvc@4.53.3':
972 | optional: true
973 |
974 | '@rollup/rollup-win32-ia32-msvc@4.53.3':
975 | optional: true
976 |
977 | '@rollup/rollup-win32-x64-gnu@4.53.3':
978 | optional: true
979 |
980 | '@rollup/rollup-win32-x64-msvc@4.53.3':
981 | optional: true
982 |
983 | '@types/estree@1.0.8': {}
984 |
985 | '@types/lodash-es@4.17.12':
986 | dependencies:
987 | '@types/lodash': 4.17.21
988 |
989 | '@types/lodash@4.17.21': {}
990 |
991 | '@types/node@22.19.2':
992 | dependencies:
993 | undici-types: 6.21.0
994 |
995 | '@vitest/coverage-v8@2.1.8(vitest@2.1.9(@types/node@22.19.2))':
996 | dependencies:
997 | '@ampproject/remapping': 2.3.0
998 | '@bcoe/v8-coverage': 0.2.3
999 | debug: 4.4.3
1000 | istanbul-lib-coverage: 3.2.2
1001 | istanbul-lib-report: 3.0.1
1002 | istanbul-lib-source-maps: 5.0.6
1003 | istanbul-reports: 3.2.0
1004 | magic-string: 0.30.21
1005 | magicast: 0.3.5
1006 | std-env: 3.10.0
1007 | test-exclude: 7.0.1
1008 | tinyrainbow: 1.2.0
1009 | vitest: 2.1.9(@types/node@22.19.2)
1010 | transitivePeerDependencies:
1011 | - supports-color
1012 |
1013 | '@vitest/expect@2.1.9':
1014 | dependencies:
1015 | '@vitest/spy': 2.1.9
1016 | '@vitest/utils': 2.1.9
1017 | chai: 5.3.3
1018 | tinyrainbow: 1.2.0
1019 |
1020 | '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.19.2))':
1021 | dependencies:
1022 | '@vitest/spy': 2.1.9
1023 | estree-walker: 3.0.3
1024 | magic-string: 0.30.21
1025 | optionalDependencies:
1026 | vite: 5.4.21(@types/node@22.19.2)
1027 |
1028 | '@vitest/pretty-format@2.1.9':
1029 | dependencies:
1030 | tinyrainbow: 1.2.0
1031 |
1032 | '@vitest/runner@2.1.9':
1033 | dependencies:
1034 | '@vitest/utils': 2.1.9
1035 | pathe: 1.1.2
1036 |
1037 | '@vitest/snapshot@2.1.9':
1038 | dependencies:
1039 | '@vitest/pretty-format': 2.1.9
1040 | magic-string: 0.30.21
1041 | pathe: 1.1.2
1042 |
1043 | '@vitest/spy@2.1.9':
1044 | dependencies:
1045 | tinyspy: 3.0.2
1046 |
1047 | '@vitest/utils@2.1.9':
1048 | dependencies:
1049 | '@vitest/pretty-format': 2.1.9
1050 | loupe: 3.2.1
1051 | tinyrainbow: 1.2.0
1052 |
1053 | ansi-regex@5.0.1: {}
1054 |
1055 | ansi-regex@6.2.2: {}
1056 |
1057 | ansi-styles@4.3.0:
1058 | dependencies:
1059 | color-convert: 2.0.1
1060 |
1061 | ansi-styles@6.2.3: {}
1062 |
1063 | argparse@2.0.1: {}
1064 |
1065 | assertion-error@2.0.1: {}
1066 |
1067 | balanced-match@1.0.2: {}
1068 |
1069 | brace-expansion@2.0.2:
1070 | dependencies:
1071 | balanced-match: 1.0.2
1072 |
1073 | cac@6.7.14: {}
1074 |
1075 | chai@5.3.3:
1076 | dependencies:
1077 | assertion-error: 2.0.1
1078 | check-error: 2.1.1
1079 | deep-eql: 5.0.2
1080 | loupe: 3.2.1
1081 | pathval: 2.0.1
1082 |
1083 | check-error@2.1.1: {}
1084 |
1085 | color-convert@2.0.1:
1086 | dependencies:
1087 | color-name: 1.1.4
1088 |
1089 | color-name@1.1.4: {}
1090 |
1091 | coveralls-next@6.0.1:
1092 | dependencies:
1093 | js-yaml: 4.1.1
1094 | lcov-parse: 1.0.0
1095 |
1096 | cross-spawn@7.0.6:
1097 | dependencies:
1098 | path-key: 3.1.1
1099 | shebang-command: 2.0.0
1100 | which: 2.0.2
1101 |
1102 | debug@4.4.3:
1103 | dependencies:
1104 | ms: 2.1.3
1105 |
1106 | deep-eql@5.0.2: {}
1107 |
1108 | eastasianwidth@0.2.0: {}
1109 |
1110 | emoji-regex@8.0.0: {}
1111 |
1112 | emoji-regex@9.2.2: {}
1113 |
1114 | es-module-lexer@1.7.0: {}
1115 |
1116 | esbuild@0.25.12:
1117 | optionalDependencies:
1118 | '@esbuild/aix-ppc64': 0.25.12
1119 | '@esbuild/android-arm': 0.25.12
1120 | '@esbuild/android-arm64': 0.25.12
1121 | '@esbuild/android-x64': 0.25.12
1122 | '@esbuild/darwin-arm64': 0.25.12
1123 | '@esbuild/darwin-x64': 0.25.12
1124 | '@esbuild/freebsd-arm64': 0.25.12
1125 | '@esbuild/freebsd-x64': 0.25.12
1126 | '@esbuild/linux-arm': 0.25.12
1127 | '@esbuild/linux-arm64': 0.25.12
1128 | '@esbuild/linux-ia32': 0.25.12
1129 | '@esbuild/linux-loong64': 0.25.12
1130 | '@esbuild/linux-mips64el': 0.25.12
1131 | '@esbuild/linux-ppc64': 0.25.12
1132 | '@esbuild/linux-riscv64': 0.25.12
1133 | '@esbuild/linux-s390x': 0.25.12
1134 | '@esbuild/linux-x64': 0.25.12
1135 | '@esbuild/netbsd-arm64': 0.25.12
1136 | '@esbuild/netbsd-x64': 0.25.12
1137 | '@esbuild/openbsd-arm64': 0.25.12
1138 | '@esbuild/openbsd-x64': 0.25.12
1139 | '@esbuild/openharmony-arm64': 0.25.12
1140 | '@esbuild/sunos-x64': 0.25.12
1141 | '@esbuild/win32-arm64': 0.25.12
1142 | '@esbuild/win32-ia32': 0.25.12
1143 | '@esbuild/win32-x64': 0.25.12
1144 |
1145 | estree-walker@3.0.3:
1146 | dependencies:
1147 | '@types/estree': 1.0.8
1148 |
1149 | expect-type@1.3.0: {}
1150 |
1151 | foreground-child@3.3.1:
1152 | dependencies:
1153 | cross-spawn: 7.0.6
1154 | signal-exit: 4.1.0
1155 |
1156 | fsevents@2.3.3:
1157 | optional: true
1158 |
1159 | glob@10.5.0:
1160 | dependencies:
1161 | foreground-child: 3.3.1
1162 | jackspeak: 3.4.3
1163 | minimatch: 9.0.5
1164 | minipass: 7.1.2
1165 | package-json-from-dist: 1.0.1
1166 | path-scurry: 1.11.1
1167 |
1168 | has-flag@4.0.0: {}
1169 |
1170 | html-escaper@2.0.2: {}
1171 |
1172 | is-fullwidth-code-point@3.0.0: {}
1173 |
1174 | isexe@2.0.0: {}
1175 |
1176 | istanbul-lib-coverage@3.2.2: {}
1177 |
1178 | istanbul-lib-report@3.0.1:
1179 | dependencies:
1180 | istanbul-lib-coverage: 3.2.2
1181 | make-dir: 4.0.0
1182 | supports-color: 7.2.0
1183 |
1184 | istanbul-lib-source-maps@5.0.6:
1185 | dependencies:
1186 | '@jridgewell/trace-mapping': 0.3.31
1187 | debug: 4.4.3
1188 | istanbul-lib-coverage: 3.2.2
1189 | transitivePeerDependencies:
1190 | - supports-color
1191 |
1192 | istanbul-reports@3.2.0:
1193 | dependencies:
1194 | html-escaper: 2.0.2
1195 | istanbul-lib-report: 3.0.1
1196 |
1197 | jackspeak@3.4.3:
1198 | dependencies:
1199 | '@isaacs/cliui': 8.0.2
1200 | optionalDependencies:
1201 | '@pkgjs/parseargs': 0.11.0
1202 |
1203 | js-yaml@4.1.1:
1204 | dependencies:
1205 | argparse: 2.0.1
1206 |
1207 | lcov-parse@1.0.0: {}
1208 |
1209 | lodash-es@4.17.21: {}
1210 |
1211 | loupe@3.2.1: {}
1212 |
1213 | lru-cache@10.4.3: {}
1214 |
1215 | magic-string@0.30.21:
1216 | dependencies:
1217 | '@jridgewell/sourcemap-codec': 1.5.5
1218 |
1219 | magicast@0.3.5:
1220 | dependencies:
1221 | '@babel/parser': 7.28.5
1222 | '@babel/types': 7.28.5
1223 | source-map-js: 1.2.1
1224 |
1225 | make-dir@4.0.0:
1226 | dependencies:
1227 | semver: 7.7.3
1228 |
1229 | minimatch@9.0.5:
1230 | dependencies:
1231 | brace-expansion: 2.0.2
1232 |
1233 | minipass@7.1.2: {}
1234 |
1235 | ms@2.1.3: {}
1236 |
1237 | nanoid@3.3.11: {}
1238 |
1239 | package-json-from-dist@1.0.1: {}
1240 |
1241 | path-key@3.1.1: {}
1242 |
1243 | path-scurry@1.11.1:
1244 | dependencies:
1245 | lru-cache: 10.4.3
1246 | minipass: 7.1.2
1247 |
1248 | pathe@1.1.2: {}
1249 |
1250 | pathval@2.0.1: {}
1251 |
1252 | picocolors@1.1.1: {}
1253 |
1254 | postcss@8.5.6:
1255 | dependencies:
1256 | nanoid: 3.3.11
1257 | picocolors: 1.1.1
1258 | source-map-js: 1.2.1
1259 |
1260 | prettier@3.7.4: {}
1261 |
1262 | rollup@4.53.3:
1263 | dependencies:
1264 | '@types/estree': 1.0.8
1265 | optionalDependencies:
1266 | '@rollup/rollup-android-arm-eabi': 4.53.3
1267 | '@rollup/rollup-android-arm64': 4.53.3
1268 | '@rollup/rollup-darwin-arm64': 4.53.3
1269 | '@rollup/rollup-darwin-x64': 4.53.3
1270 | '@rollup/rollup-freebsd-arm64': 4.53.3
1271 | '@rollup/rollup-freebsd-x64': 4.53.3
1272 | '@rollup/rollup-linux-arm-gnueabihf': 4.53.3
1273 | '@rollup/rollup-linux-arm-musleabihf': 4.53.3
1274 | '@rollup/rollup-linux-arm64-gnu': 4.53.3
1275 | '@rollup/rollup-linux-arm64-musl': 4.53.3
1276 | '@rollup/rollup-linux-loong64-gnu': 4.53.3
1277 | '@rollup/rollup-linux-ppc64-gnu': 4.53.3
1278 | '@rollup/rollup-linux-riscv64-gnu': 4.53.3
1279 | '@rollup/rollup-linux-riscv64-musl': 4.53.3
1280 | '@rollup/rollup-linux-s390x-gnu': 4.53.3
1281 | '@rollup/rollup-linux-x64-gnu': 4.53.3
1282 | '@rollup/rollup-linux-x64-musl': 4.53.3
1283 | '@rollup/rollup-openharmony-arm64': 4.53.3
1284 | '@rollup/rollup-win32-arm64-msvc': 4.53.3
1285 | '@rollup/rollup-win32-ia32-msvc': 4.53.3
1286 | '@rollup/rollup-win32-x64-gnu': 4.53.3
1287 | '@rollup/rollup-win32-x64-msvc': 4.53.3
1288 | fsevents: 2.3.3
1289 |
1290 | semver@7.7.3: {}
1291 |
1292 | shebang-command@2.0.0:
1293 | dependencies:
1294 | shebang-regex: 3.0.0
1295 |
1296 | shebang-regex@3.0.0: {}
1297 |
1298 | siginfo@2.0.0: {}
1299 |
1300 | signal-exit@4.1.0: {}
1301 |
1302 | source-map-js@1.2.1: {}
1303 |
1304 | stackback@0.0.2: {}
1305 |
1306 | std-env@3.10.0: {}
1307 |
1308 | string-width@4.2.3:
1309 | dependencies:
1310 | emoji-regex: 8.0.0
1311 | is-fullwidth-code-point: 3.0.0
1312 | strip-ansi: 6.0.1
1313 |
1314 | string-width@5.1.2:
1315 | dependencies:
1316 | eastasianwidth: 0.2.0
1317 | emoji-regex: 9.2.2
1318 | strip-ansi: 7.1.2
1319 |
1320 | strip-ansi@6.0.1:
1321 | dependencies:
1322 | ansi-regex: 5.0.1
1323 |
1324 | strip-ansi@7.1.2:
1325 | dependencies:
1326 | ansi-regex: 6.2.2
1327 |
1328 | supports-color@7.2.0:
1329 | dependencies:
1330 | has-flag: 4.0.0
1331 |
1332 | test-exclude@7.0.1:
1333 | dependencies:
1334 | '@istanbuljs/schema': 0.1.3
1335 | glob: 10.5.0
1336 | minimatch: 9.0.5
1337 |
1338 | tinybench@2.9.0: {}
1339 |
1340 | tinyexec@0.3.2: {}
1341 |
1342 | tinypool@1.1.1: {}
1343 |
1344 | tinyrainbow@1.2.0: {}
1345 |
1346 | tinyspy@3.0.2: {}
1347 |
1348 | typescript@5.9.3: {}
1349 |
1350 | undici-types@6.21.0: {}
1351 |
1352 | vite-node@2.1.9(@types/node@22.19.2):
1353 | dependencies:
1354 | cac: 6.7.14
1355 | debug: 4.4.3
1356 | es-module-lexer: 1.7.0
1357 | pathe: 1.1.2
1358 | vite: 5.4.21(@types/node@22.19.2)
1359 | transitivePeerDependencies:
1360 | - '@types/node'
1361 | - less
1362 | - lightningcss
1363 | - sass
1364 | - sass-embedded
1365 | - stylus
1366 | - sugarss
1367 | - supports-color
1368 | - terser
1369 |
1370 | vite@5.4.21(@types/node@22.19.2):
1371 | dependencies:
1372 | esbuild: 0.25.12
1373 | postcss: 8.5.6
1374 | rollup: 4.53.3
1375 | optionalDependencies:
1376 | '@types/node': 22.19.2
1377 | fsevents: 2.3.3
1378 |
1379 | vitest@2.1.9(@types/node@22.19.2):
1380 | dependencies:
1381 | '@vitest/expect': 2.1.9
1382 | '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.19.2))
1383 | '@vitest/pretty-format': 2.1.9
1384 | '@vitest/runner': 2.1.9
1385 | '@vitest/snapshot': 2.1.9
1386 | '@vitest/spy': 2.1.9
1387 | '@vitest/utils': 2.1.9
1388 | chai: 5.3.3
1389 | debug: 4.4.3
1390 | expect-type: 1.3.0
1391 | magic-string: 0.30.21
1392 | pathe: 1.1.2
1393 | std-env: 3.10.0
1394 | tinybench: 2.9.0
1395 | tinyexec: 0.3.2
1396 | tinypool: 1.1.1
1397 | tinyrainbow: 1.2.0
1398 | vite: 5.4.21(@types/node@22.19.2)
1399 | vite-node: 2.1.9(@types/node@22.19.2)
1400 | why-is-node-running: 2.3.0
1401 | optionalDependencies:
1402 | '@types/node': 22.19.2
1403 | transitivePeerDependencies:
1404 | - less
1405 | - lightningcss
1406 | - msw
1407 | - sass
1408 | - sass-embedded
1409 | - stylus
1410 | - sugarss
1411 | - supports-color
1412 | - terser
1413 |
1414 | which@2.0.2:
1415 | dependencies:
1416 | isexe: 2.0.0
1417 |
1418 | why-is-node-running@2.3.0:
1419 | dependencies:
1420 | siginfo: 2.0.0
1421 | stackback: 0.0.2
1422 |
1423 | wrap-ansi@7.0.0:
1424 | dependencies:
1425 | ansi-styles: 4.3.0
1426 | string-width: 4.2.3
1427 | strip-ansi: 6.0.1
1428 |
1429 | wrap-ansi@8.1.0:
1430 | dependencies:
1431 | ansi-styles: 6.2.3
1432 | string-width: 5.1.2
1433 | strip-ansi: 7.1.2
1434 |
--------------------------------------------------------------------------------