├── .editorconfig ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .prettierrc.json ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── src └── index.ts ├── tests └── index.test.ts ├── tsconfig.json └── vitest.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{md,markdown}] 2 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /node_modules 3 | /coverage 4 | /dist -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true 6 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdown.extension.toc.levels": "1..3" 3 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/scambier/markov-strings.svg?branch=master)](https://travis-ci.org/scambier/markov-strings) 2 | [![Coverage Status](https://coveralls.io/repos/github/scambier/markov-strings/badge.svg?branch=master)](https://coveralls.io/github/scambier/markov-strings?branch=master) 3 | [![npm version](https://badge.fury.io/js/markov-strings.svg)](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 | -------------------------------------------------------------------------------- /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.13", 33 | "@types/lodash-es": "^4.17.12", 34 | "@types/node": "^22.10.4", 35 | "@vitest/coverage-v8": "2.1.8", 36 | "coveralls": "^3.1.1", 37 | "prettier": "^3.4.2", 38 | "typescript": "^5.7.2", 39 | "vitest": "^2.1.8" 40 | }, 41 | "dependencies": { 42 | "lodash-es": "^4.17.21" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | lodash-es: 12 | specifier: ^4.17.21 13 | version: 4.17.21 14 | devDependencies: 15 | '@types/lodash': 16 | specifier: ^4.17.13 17 | version: 4.17.13 18 | '@types/lodash-es': 19 | specifier: ^4.17.12 20 | version: 4.17.12 21 | '@types/node': 22 | specifier: ^22.10.4 23 | version: 22.10.4 24 | '@vitest/coverage-v8': 25 | specifier: 2.1.8 26 | version: 2.1.8(vitest@2.1.8(@types/node@22.10.4)) 27 | coveralls: 28 | specifier: ^3.1.1 29 | version: 3.1.1 30 | prettier: 31 | specifier: ^3.4.2 32 | version: 3.4.2 33 | typescript: 34 | specifier: ^5.7.2 35 | version: 5.7.2 36 | vitest: 37 | specifier: ^2.1.8 38 | version: 2.1.8(@types/node@22.10.4) 39 | 40 | packages: 41 | 42 | '@ampproject/remapping@2.3.0': 43 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 44 | engines: {node: '>=6.0.0'} 45 | 46 | '@babel/helper-string-parser@7.25.9': 47 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 48 | engines: {node: '>=6.9.0'} 49 | 50 | '@babel/helper-validator-identifier@7.25.9': 51 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 52 | engines: {node: '>=6.9.0'} 53 | 54 | '@babel/parser@7.26.3': 55 | resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} 56 | engines: {node: '>=6.0.0'} 57 | hasBin: true 58 | 59 | '@babel/types@7.26.3': 60 | resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} 61 | engines: {node: '>=6.9.0'} 62 | 63 | '@bcoe/v8-coverage@0.2.3': 64 | resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} 65 | 66 | '@esbuild/aix-ppc64@0.21.5': 67 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 68 | engines: {node: '>=12'} 69 | cpu: [ppc64] 70 | os: [aix] 71 | 72 | '@esbuild/android-arm64@0.21.5': 73 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 74 | engines: {node: '>=12'} 75 | cpu: [arm64] 76 | os: [android] 77 | 78 | '@esbuild/android-arm@0.21.5': 79 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 80 | engines: {node: '>=12'} 81 | cpu: [arm] 82 | os: [android] 83 | 84 | '@esbuild/android-x64@0.21.5': 85 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 86 | engines: {node: '>=12'} 87 | cpu: [x64] 88 | os: [android] 89 | 90 | '@esbuild/darwin-arm64@0.21.5': 91 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 92 | engines: {node: '>=12'} 93 | cpu: [arm64] 94 | os: [darwin] 95 | 96 | '@esbuild/darwin-x64@0.21.5': 97 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 98 | engines: {node: '>=12'} 99 | cpu: [x64] 100 | os: [darwin] 101 | 102 | '@esbuild/freebsd-arm64@0.21.5': 103 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 104 | engines: {node: '>=12'} 105 | cpu: [arm64] 106 | os: [freebsd] 107 | 108 | '@esbuild/freebsd-x64@0.21.5': 109 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 110 | engines: {node: '>=12'} 111 | cpu: [x64] 112 | os: [freebsd] 113 | 114 | '@esbuild/linux-arm64@0.21.5': 115 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 116 | engines: {node: '>=12'} 117 | cpu: [arm64] 118 | os: [linux] 119 | 120 | '@esbuild/linux-arm@0.21.5': 121 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 122 | engines: {node: '>=12'} 123 | cpu: [arm] 124 | os: [linux] 125 | 126 | '@esbuild/linux-ia32@0.21.5': 127 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 128 | engines: {node: '>=12'} 129 | cpu: [ia32] 130 | os: [linux] 131 | 132 | '@esbuild/linux-loong64@0.21.5': 133 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 134 | engines: {node: '>=12'} 135 | cpu: [loong64] 136 | os: [linux] 137 | 138 | '@esbuild/linux-mips64el@0.21.5': 139 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 140 | engines: {node: '>=12'} 141 | cpu: [mips64el] 142 | os: [linux] 143 | 144 | '@esbuild/linux-ppc64@0.21.5': 145 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 146 | engines: {node: '>=12'} 147 | cpu: [ppc64] 148 | os: [linux] 149 | 150 | '@esbuild/linux-riscv64@0.21.5': 151 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 152 | engines: {node: '>=12'} 153 | cpu: [riscv64] 154 | os: [linux] 155 | 156 | '@esbuild/linux-s390x@0.21.5': 157 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 158 | engines: {node: '>=12'} 159 | cpu: [s390x] 160 | os: [linux] 161 | 162 | '@esbuild/linux-x64@0.21.5': 163 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 164 | engines: {node: '>=12'} 165 | cpu: [x64] 166 | os: [linux] 167 | 168 | '@esbuild/netbsd-x64@0.21.5': 169 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 170 | engines: {node: '>=12'} 171 | cpu: [x64] 172 | os: [netbsd] 173 | 174 | '@esbuild/openbsd-x64@0.21.5': 175 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 176 | engines: {node: '>=12'} 177 | cpu: [x64] 178 | os: [openbsd] 179 | 180 | '@esbuild/sunos-x64@0.21.5': 181 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 182 | engines: {node: '>=12'} 183 | cpu: [x64] 184 | os: [sunos] 185 | 186 | '@esbuild/win32-arm64@0.21.5': 187 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 188 | engines: {node: '>=12'} 189 | cpu: [arm64] 190 | os: [win32] 191 | 192 | '@esbuild/win32-ia32@0.21.5': 193 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 194 | engines: {node: '>=12'} 195 | cpu: [ia32] 196 | os: [win32] 197 | 198 | '@esbuild/win32-x64@0.21.5': 199 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 200 | engines: {node: '>=12'} 201 | cpu: [x64] 202 | os: [win32] 203 | 204 | '@isaacs/cliui@8.0.2': 205 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 206 | engines: {node: '>=12'} 207 | 208 | '@istanbuljs/schema@0.1.3': 209 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} 210 | engines: {node: '>=8'} 211 | 212 | '@jridgewell/gen-mapping@0.3.8': 213 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 214 | engines: {node: '>=6.0.0'} 215 | 216 | '@jridgewell/resolve-uri@3.1.2': 217 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 218 | engines: {node: '>=6.0.0'} 219 | 220 | '@jridgewell/set-array@1.2.1': 221 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 222 | engines: {node: '>=6.0.0'} 223 | 224 | '@jridgewell/sourcemap-codec@1.5.0': 225 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 226 | 227 | '@jridgewell/trace-mapping@0.3.25': 228 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 229 | 230 | '@pkgjs/parseargs@0.11.0': 231 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 232 | engines: {node: '>=14'} 233 | 234 | '@rollup/rollup-android-arm-eabi@4.29.1': 235 | resolution: {integrity: sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==} 236 | cpu: [arm] 237 | os: [android] 238 | 239 | '@rollup/rollup-android-arm64@4.29.1': 240 | resolution: {integrity: sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==} 241 | cpu: [arm64] 242 | os: [android] 243 | 244 | '@rollup/rollup-darwin-arm64@4.29.1': 245 | resolution: {integrity: sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==} 246 | cpu: [arm64] 247 | os: [darwin] 248 | 249 | '@rollup/rollup-darwin-x64@4.29.1': 250 | resolution: {integrity: sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==} 251 | cpu: [x64] 252 | os: [darwin] 253 | 254 | '@rollup/rollup-freebsd-arm64@4.29.1': 255 | resolution: {integrity: sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==} 256 | cpu: [arm64] 257 | os: [freebsd] 258 | 259 | '@rollup/rollup-freebsd-x64@4.29.1': 260 | resolution: {integrity: sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==} 261 | cpu: [x64] 262 | os: [freebsd] 263 | 264 | '@rollup/rollup-linux-arm-gnueabihf@4.29.1': 265 | resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} 266 | cpu: [arm] 267 | os: [linux] 268 | 269 | '@rollup/rollup-linux-arm-musleabihf@4.29.1': 270 | resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} 271 | cpu: [arm] 272 | os: [linux] 273 | 274 | '@rollup/rollup-linux-arm64-gnu@4.29.1': 275 | resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} 276 | cpu: [arm64] 277 | os: [linux] 278 | 279 | '@rollup/rollup-linux-arm64-musl@4.29.1': 280 | resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} 281 | cpu: [arm64] 282 | os: [linux] 283 | 284 | '@rollup/rollup-linux-loongarch64-gnu@4.29.1': 285 | resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} 286 | cpu: [loong64] 287 | os: [linux] 288 | 289 | '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': 290 | resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} 291 | cpu: [ppc64] 292 | os: [linux] 293 | 294 | '@rollup/rollup-linux-riscv64-gnu@4.29.1': 295 | resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} 296 | cpu: [riscv64] 297 | os: [linux] 298 | 299 | '@rollup/rollup-linux-s390x-gnu@4.29.1': 300 | resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} 301 | cpu: [s390x] 302 | os: [linux] 303 | 304 | '@rollup/rollup-linux-x64-gnu@4.29.1': 305 | resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} 306 | cpu: [x64] 307 | os: [linux] 308 | 309 | '@rollup/rollup-linux-x64-musl@4.29.1': 310 | resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} 311 | cpu: [x64] 312 | os: [linux] 313 | 314 | '@rollup/rollup-win32-arm64-msvc@4.29.1': 315 | resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} 316 | cpu: [arm64] 317 | os: [win32] 318 | 319 | '@rollup/rollup-win32-ia32-msvc@4.29.1': 320 | resolution: {integrity: sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==} 321 | cpu: [ia32] 322 | os: [win32] 323 | 324 | '@rollup/rollup-win32-x64-msvc@4.29.1': 325 | resolution: {integrity: sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==} 326 | cpu: [x64] 327 | os: [win32] 328 | 329 | '@types/estree@1.0.6': 330 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 331 | 332 | '@types/lodash-es@4.17.12': 333 | resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} 334 | 335 | '@types/lodash@4.17.13': 336 | resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} 337 | 338 | '@types/node@22.10.4': 339 | resolution: {integrity: sha512-99l6wv4HEzBQhvaU/UGoeBoCK61SCROQaCCGyQSgX2tEQ3rKkNZ2S7CEWnS/4s1LV+8ODdK21UeyR1fHP2mXug==} 340 | 341 | '@vitest/coverage-v8@2.1.8': 342 | resolution: {integrity: sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==} 343 | peerDependencies: 344 | '@vitest/browser': 2.1.8 345 | vitest: 2.1.8 346 | peerDependenciesMeta: 347 | '@vitest/browser': 348 | optional: true 349 | 350 | '@vitest/expect@2.1.8': 351 | resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} 352 | 353 | '@vitest/mocker@2.1.8': 354 | resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} 355 | peerDependencies: 356 | msw: ^2.4.9 357 | vite: ^5.0.0 358 | peerDependenciesMeta: 359 | msw: 360 | optional: true 361 | vite: 362 | optional: true 363 | 364 | '@vitest/pretty-format@2.1.8': 365 | resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} 366 | 367 | '@vitest/runner@2.1.8': 368 | resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} 369 | 370 | '@vitest/snapshot@2.1.8': 371 | resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} 372 | 373 | '@vitest/spy@2.1.8': 374 | resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} 375 | 376 | '@vitest/utils@2.1.8': 377 | resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} 378 | 379 | ajv@6.12.6: 380 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 381 | 382 | ansi-regex@5.0.1: 383 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 384 | engines: {node: '>=8'} 385 | 386 | ansi-regex@6.1.0: 387 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 388 | engines: {node: '>=12'} 389 | 390 | ansi-styles@4.3.0: 391 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 392 | engines: {node: '>=8'} 393 | 394 | ansi-styles@6.2.1: 395 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 396 | engines: {node: '>=12'} 397 | 398 | argparse@1.0.10: 399 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 400 | 401 | asn1@0.2.6: 402 | resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} 403 | 404 | assert-plus@1.0.0: 405 | resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} 406 | engines: {node: '>=0.8'} 407 | 408 | assertion-error@2.0.1: 409 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 410 | engines: {node: '>=12'} 411 | 412 | asynckit@0.4.0: 413 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 414 | 415 | aws-sign2@0.7.0: 416 | resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} 417 | 418 | aws4@1.13.2: 419 | resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} 420 | 421 | balanced-match@1.0.2: 422 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 423 | 424 | bcrypt-pbkdf@1.0.2: 425 | resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} 426 | 427 | brace-expansion@2.0.1: 428 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 429 | 430 | cac@6.7.14: 431 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 432 | engines: {node: '>=8'} 433 | 434 | caseless@0.12.0: 435 | resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} 436 | 437 | chai@5.1.2: 438 | resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} 439 | engines: {node: '>=12'} 440 | 441 | check-error@2.1.1: 442 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 443 | engines: {node: '>= 16'} 444 | 445 | color-convert@2.0.1: 446 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 447 | engines: {node: '>=7.0.0'} 448 | 449 | color-name@1.1.4: 450 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 451 | 452 | combined-stream@1.0.8: 453 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 454 | engines: {node: '>= 0.8'} 455 | 456 | core-util-is@1.0.2: 457 | resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} 458 | 459 | coveralls@3.1.1: 460 | resolution: {integrity: sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==} 461 | engines: {node: '>=6'} 462 | hasBin: true 463 | 464 | cross-spawn@7.0.6: 465 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 466 | engines: {node: '>= 8'} 467 | 468 | dashdash@1.14.1: 469 | resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} 470 | engines: {node: '>=0.10'} 471 | 472 | debug@4.4.0: 473 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 474 | engines: {node: '>=6.0'} 475 | peerDependencies: 476 | supports-color: '*' 477 | peerDependenciesMeta: 478 | supports-color: 479 | optional: true 480 | 481 | deep-eql@5.0.2: 482 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 483 | engines: {node: '>=6'} 484 | 485 | delayed-stream@1.0.0: 486 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 487 | engines: {node: '>=0.4.0'} 488 | 489 | eastasianwidth@0.2.0: 490 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 491 | 492 | ecc-jsbn@0.1.2: 493 | resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} 494 | 495 | emoji-regex@8.0.0: 496 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 497 | 498 | emoji-regex@9.2.2: 499 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 500 | 501 | es-module-lexer@1.6.0: 502 | resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} 503 | 504 | esbuild@0.21.5: 505 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 506 | engines: {node: '>=12'} 507 | hasBin: true 508 | 509 | esprima@4.0.1: 510 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 511 | engines: {node: '>=4'} 512 | hasBin: true 513 | 514 | estree-walker@3.0.3: 515 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 516 | 517 | expect-type@1.1.0: 518 | resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} 519 | engines: {node: '>=12.0.0'} 520 | 521 | extend@3.0.2: 522 | resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} 523 | 524 | extsprintf@1.3.0: 525 | resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} 526 | engines: {'0': node >=0.6.0} 527 | 528 | fast-deep-equal@3.1.3: 529 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 530 | 531 | fast-json-stable-stringify@2.1.0: 532 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 533 | 534 | foreground-child@3.3.0: 535 | resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} 536 | engines: {node: '>=14'} 537 | 538 | forever-agent@0.6.1: 539 | resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} 540 | 541 | form-data@2.3.3: 542 | resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} 543 | engines: {node: '>= 0.12'} 544 | 545 | fsevents@2.3.3: 546 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 547 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 548 | os: [darwin] 549 | 550 | getpass@0.1.7: 551 | resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} 552 | 553 | glob@10.4.5: 554 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 555 | hasBin: true 556 | 557 | har-schema@2.0.0: 558 | resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} 559 | engines: {node: '>=4'} 560 | 561 | har-validator@5.1.5: 562 | resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} 563 | engines: {node: '>=6'} 564 | deprecated: this library is no longer supported 565 | 566 | has-flag@4.0.0: 567 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 568 | engines: {node: '>=8'} 569 | 570 | html-escaper@2.0.2: 571 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 572 | 573 | http-signature@1.2.0: 574 | resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} 575 | engines: {node: '>=0.8', npm: '>=1.3.7'} 576 | 577 | is-fullwidth-code-point@3.0.0: 578 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 579 | engines: {node: '>=8'} 580 | 581 | is-typedarray@1.0.0: 582 | resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} 583 | 584 | isexe@2.0.0: 585 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 586 | 587 | isstream@0.1.2: 588 | resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} 589 | 590 | istanbul-lib-coverage@3.2.2: 591 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} 592 | engines: {node: '>=8'} 593 | 594 | istanbul-lib-report@3.0.1: 595 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} 596 | engines: {node: '>=10'} 597 | 598 | istanbul-lib-source-maps@5.0.6: 599 | resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} 600 | engines: {node: '>=10'} 601 | 602 | istanbul-reports@3.1.7: 603 | resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} 604 | engines: {node: '>=8'} 605 | 606 | jackspeak@3.4.3: 607 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 608 | 609 | js-yaml@3.14.1: 610 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 611 | hasBin: true 612 | 613 | jsbn@0.1.1: 614 | resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} 615 | 616 | json-schema-traverse@0.4.1: 617 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 618 | 619 | json-schema@0.4.0: 620 | resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} 621 | 622 | json-stringify-safe@5.0.1: 623 | resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} 624 | 625 | jsprim@1.4.2: 626 | resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} 627 | engines: {node: '>=0.6.0'} 628 | 629 | lcov-parse@1.0.0: 630 | resolution: {integrity: sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==} 631 | hasBin: true 632 | 633 | lodash-es@4.17.21: 634 | resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} 635 | 636 | log-driver@1.2.7: 637 | resolution: {integrity: sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==} 638 | engines: {node: '>=0.8.6'} 639 | 640 | loupe@3.1.2: 641 | resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} 642 | 643 | lru-cache@10.4.3: 644 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 645 | 646 | magic-string@0.30.17: 647 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 648 | 649 | magicast@0.3.5: 650 | resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} 651 | 652 | make-dir@4.0.0: 653 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} 654 | engines: {node: '>=10'} 655 | 656 | mime-db@1.52.0: 657 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 658 | engines: {node: '>= 0.6'} 659 | 660 | mime-types@2.1.35: 661 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 662 | engines: {node: '>= 0.6'} 663 | 664 | minimatch@9.0.5: 665 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 666 | engines: {node: '>=16 || 14 >=14.17'} 667 | 668 | minimist@1.2.8: 669 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 670 | 671 | minipass@7.1.2: 672 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 673 | engines: {node: '>=16 || 14 >=14.17'} 674 | 675 | ms@2.1.3: 676 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 677 | 678 | nanoid@3.3.8: 679 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 680 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 681 | hasBin: true 682 | 683 | oauth-sign@0.9.0: 684 | resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} 685 | 686 | package-json-from-dist@1.0.1: 687 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 688 | 689 | path-key@3.1.1: 690 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 691 | engines: {node: '>=8'} 692 | 693 | path-scurry@1.11.1: 694 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 695 | engines: {node: '>=16 || 14 >=14.18'} 696 | 697 | pathe@1.1.2: 698 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} 699 | 700 | pathval@2.0.0: 701 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} 702 | engines: {node: '>= 14.16'} 703 | 704 | performance-now@2.1.0: 705 | resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} 706 | 707 | picocolors@1.1.1: 708 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 709 | 710 | postcss@8.4.49: 711 | resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} 712 | engines: {node: ^10 || ^12 || >=14} 713 | 714 | prettier@3.4.2: 715 | resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} 716 | engines: {node: '>=14'} 717 | hasBin: true 718 | 719 | psl@1.15.0: 720 | resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} 721 | 722 | punycode@2.3.1: 723 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 724 | engines: {node: '>=6'} 725 | 726 | qs@6.5.3: 727 | resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} 728 | engines: {node: '>=0.6'} 729 | 730 | request@2.88.2: 731 | resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} 732 | engines: {node: '>= 6'} 733 | deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 734 | 735 | rollup@4.29.1: 736 | resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} 737 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 738 | hasBin: true 739 | 740 | safe-buffer@5.2.1: 741 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 742 | 743 | safer-buffer@2.1.2: 744 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 745 | 746 | semver@7.6.3: 747 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} 748 | engines: {node: '>=10'} 749 | hasBin: true 750 | 751 | shebang-command@2.0.0: 752 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 753 | engines: {node: '>=8'} 754 | 755 | shebang-regex@3.0.0: 756 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 757 | engines: {node: '>=8'} 758 | 759 | siginfo@2.0.0: 760 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 761 | 762 | signal-exit@4.1.0: 763 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 764 | engines: {node: '>=14'} 765 | 766 | source-map-js@1.2.1: 767 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 768 | engines: {node: '>=0.10.0'} 769 | 770 | sprintf-js@1.0.3: 771 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 772 | 773 | sshpk@1.18.0: 774 | resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} 775 | engines: {node: '>=0.10.0'} 776 | hasBin: true 777 | 778 | stackback@0.0.2: 779 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 780 | 781 | std-env@3.8.0: 782 | resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} 783 | 784 | string-width@4.2.3: 785 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 786 | engines: {node: '>=8'} 787 | 788 | string-width@5.1.2: 789 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 790 | engines: {node: '>=12'} 791 | 792 | strip-ansi@6.0.1: 793 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 794 | engines: {node: '>=8'} 795 | 796 | strip-ansi@7.1.0: 797 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 798 | engines: {node: '>=12'} 799 | 800 | supports-color@7.2.0: 801 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 802 | engines: {node: '>=8'} 803 | 804 | test-exclude@7.0.1: 805 | resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} 806 | engines: {node: '>=18'} 807 | 808 | tinybench@2.9.0: 809 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 810 | 811 | tinyexec@0.3.2: 812 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 813 | 814 | tinypool@1.0.2: 815 | resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} 816 | engines: {node: ^18.0.0 || >=20.0.0} 817 | 818 | tinyrainbow@1.2.0: 819 | resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} 820 | engines: {node: '>=14.0.0'} 821 | 822 | tinyspy@3.0.2: 823 | resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} 824 | engines: {node: '>=14.0.0'} 825 | 826 | tough-cookie@2.5.0: 827 | resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} 828 | engines: {node: '>=0.8'} 829 | 830 | tunnel-agent@0.6.0: 831 | resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} 832 | 833 | tweetnacl@0.14.5: 834 | resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} 835 | 836 | typescript@5.7.2: 837 | resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} 838 | engines: {node: '>=14.17'} 839 | hasBin: true 840 | 841 | undici-types@6.20.0: 842 | resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} 843 | 844 | uri-js@4.4.1: 845 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 846 | 847 | uuid@3.4.0: 848 | resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} 849 | deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. 850 | hasBin: true 851 | 852 | verror@1.10.0: 853 | resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=} 854 | engines: {'0': node >=0.6.0} 855 | 856 | vite-node@2.1.8: 857 | resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} 858 | engines: {node: ^18.0.0 || >=20.0.0} 859 | hasBin: true 860 | 861 | vite@5.4.11: 862 | resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} 863 | engines: {node: ^18.0.0 || >=20.0.0} 864 | hasBin: true 865 | peerDependencies: 866 | '@types/node': ^18.0.0 || >=20.0.0 867 | less: '*' 868 | lightningcss: ^1.21.0 869 | sass: '*' 870 | sass-embedded: '*' 871 | stylus: '*' 872 | sugarss: '*' 873 | terser: ^5.4.0 874 | peerDependenciesMeta: 875 | '@types/node': 876 | optional: true 877 | less: 878 | optional: true 879 | lightningcss: 880 | optional: true 881 | sass: 882 | optional: true 883 | sass-embedded: 884 | optional: true 885 | stylus: 886 | optional: true 887 | sugarss: 888 | optional: true 889 | terser: 890 | optional: true 891 | 892 | vitest@2.1.8: 893 | resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} 894 | engines: {node: ^18.0.0 || >=20.0.0} 895 | hasBin: true 896 | peerDependencies: 897 | '@edge-runtime/vm': '*' 898 | '@types/node': ^18.0.0 || >=20.0.0 899 | '@vitest/browser': 2.1.8 900 | '@vitest/ui': 2.1.8 901 | happy-dom: '*' 902 | jsdom: '*' 903 | peerDependenciesMeta: 904 | '@edge-runtime/vm': 905 | optional: true 906 | '@types/node': 907 | optional: true 908 | '@vitest/browser': 909 | optional: true 910 | '@vitest/ui': 911 | optional: true 912 | happy-dom: 913 | optional: true 914 | jsdom: 915 | optional: true 916 | 917 | which@2.0.2: 918 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 919 | engines: {node: '>= 8'} 920 | hasBin: true 921 | 922 | why-is-node-running@2.3.0: 923 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 924 | engines: {node: '>=8'} 925 | hasBin: true 926 | 927 | wrap-ansi@7.0.0: 928 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 929 | engines: {node: '>=10'} 930 | 931 | wrap-ansi@8.1.0: 932 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 933 | engines: {node: '>=12'} 934 | 935 | snapshots: 936 | 937 | '@ampproject/remapping@2.3.0': 938 | dependencies: 939 | '@jridgewell/gen-mapping': 0.3.8 940 | '@jridgewell/trace-mapping': 0.3.25 941 | 942 | '@babel/helper-string-parser@7.25.9': {} 943 | 944 | '@babel/helper-validator-identifier@7.25.9': {} 945 | 946 | '@babel/parser@7.26.3': 947 | dependencies: 948 | '@babel/types': 7.26.3 949 | 950 | '@babel/types@7.26.3': 951 | dependencies: 952 | '@babel/helper-string-parser': 7.25.9 953 | '@babel/helper-validator-identifier': 7.25.9 954 | 955 | '@bcoe/v8-coverage@0.2.3': {} 956 | 957 | '@esbuild/aix-ppc64@0.21.5': 958 | optional: true 959 | 960 | '@esbuild/android-arm64@0.21.5': 961 | optional: true 962 | 963 | '@esbuild/android-arm@0.21.5': 964 | optional: true 965 | 966 | '@esbuild/android-x64@0.21.5': 967 | optional: true 968 | 969 | '@esbuild/darwin-arm64@0.21.5': 970 | optional: true 971 | 972 | '@esbuild/darwin-x64@0.21.5': 973 | optional: true 974 | 975 | '@esbuild/freebsd-arm64@0.21.5': 976 | optional: true 977 | 978 | '@esbuild/freebsd-x64@0.21.5': 979 | optional: true 980 | 981 | '@esbuild/linux-arm64@0.21.5': 982 | optional: true 983 | 984 | '@esbuild/linux-arm@0.21.5': 985 | optional: true 986 | 987 | '@esbuild/linux-ia32@0.21.5': 988 | optional: true 989 | 990 | '@esbuild/linux-loong64@0.21.5': 991 | optional: true 992 | 993 | '@esbuild/linux-mips64el@0.21.5': 994 | optional: true 995 | 996 | '@esbuild/linux-ppc64@0.21.5': 997 | optional: true 998 | 999 | '@esbuild/linux-riscv64@0.21.5': 1000 | optional: true 1001 | 1002 | '@esbuild/linux-s390x@0.21.5': 1003 | optional: true 1004 | 1005 | '@esbuild/linux-x64@0.21.5': 1006 | optional: true 1007 | 1008 | '@esbuild/netbsd-x64@0.21.5': 1009 | optional: true 1010 | 1011 | '@esbuild/openbsd-x64@0.21.5': 1012 | optional: true 1013 | 1014 | '@esbuild/sunos-x64@0.21.5': 1015 | optional: true 1016 | 1017 | '@esbuild/win32-arm64@0.21.5': 1018 | optional: true 1019 | 1020 | '@esbuild/win32-ia32@0.21.5': 1021 | optional: true 1022 | 1023 | '@esbuild/win32-x64@0.21.5': 1024 | optional: true 1025 | 1026 | '@isaacs/cliui@8.0.2': 1027 | dependencies: 1028 | string-width: 5.1.2 1029 | string-width-cjs: string-width@4.2.3 1030 | strip-ansi: 7.1.0 1031 | strip-ansi-cjs: strip-ansi@6.0.1 1032 | wrap-ansi: 8.1.0 1033 | wrap-ansi-cjs: wrap-ansi@7.0.0 1034 | 1035 | '@istanbuljs/schema@0.1.3': {} 1036 | 1037 | '@jridgewell/gen-mapping@0.3.8': 1038 | dependencies: 1039 | '@jridgewell/set-array': 1.2.1 1040 | '@jridgewell/sourcemap-codec': 1.5.0 1041 | '@jridgewell/trace-mapping': 0.3.25 1042 | 1043 | '@jridgewell/resolve-uri@3.1.2': {} 1044 | 1045 | '@jridgewell/set-array@1.2.1': {} 1046 | 1047 | '@jridgewell/sourcemap-codec@1.5.0': {} 1048 | 1049 | '@jridgewell/trace-mapping@0.3.25': 1050 | dependencies: 1051 | '@jridgewell/resolve-uri': 3.1.2 1052 | '@jridgewell/sourcemap-codec': 1.5.0 1053 | 1054 | '@pkgjs/parseargs@0.11.0': 1055 | optional: true 1056 | 1057 | '@rollup/rollup-android-arm-eabi@4.29.1': 1058 | optional: true 1059 | 1060 | '@rollup/rollup-android-arm64@4.29.1': 1061 | optional: true 1062 | 1063 | '@rollup/rollup-darwin-arm64@4.29.1': 1064 | optional: true 1065 | 1066 | '@rollup/rollup-darwin-x64@4.29.1': 1067 | optional: true 1068 | 1069 | '@rollup/rollup-freebsd-arm64@4.29.1': 1070 | optional: true 1071 | 1072 | '@rollup/rollup-freebsd-x64@4.29.1': 1073 | optional: true 1074 | 1075 | '@rollup/rollup-linux-arm-gnueabihf@4.29.1': 1076 | optional: true 1077 | 1078 | '@rollup/rollup-linux-arm-musleabihf@4.29.1': 1079 | optional: true 1080 | 1081 | '@rollup/rollup-linux-arm64-gnu@4.29.1': 1082 | optional: true 1083 | 1084 | '@rollup/rollup-linux-arm64-musl@4.29.1': 1085 | optional: true 1086 | 1087 | '@rollup/rollup-linux-loongarch64-gnu@4.29.1': 1088 | optional: true 1089 | 1090 | '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': 1091 | optional: true 1092 | 1093 | '@rollup/rollup-linux-riscv64-gnu@4.29.1': 1094 | optional: true 1095 | 1096 | '@rollup/rollup-linux-s390x-gnu@4.29.1': 1097 | optional: true 1098 | 1099 | '@rollup/rollup-linux-x64-gnu@4.29.1': 1100 | optional: true 1101 | 1102 | '@rollup/rollup-linux-x64-musl@4.29.1': 1103 | optional: true 1104 | 1105 | '@rollup/rollup-win32-arm64-msvc@4.29.1': 1106 | optional: true 1107 | 1108 | '@rollup/rollup-win32-ia32-msvc@4.29.1': 1109 | optional: true 1110 | 1111 | '@rollup/rollup-win32-x64-msvc@4.29.1': 1112 | optional: true 1113 | 1114 | '@types/estree@1.0.6': {} 1115 | 1116 | '@types/lodash-es@4.17.12': 1117 | dependencies: 1118 | '@types/lodash': 4.17.13 1119 | 1120 | '@types/lodash@4.17.13': {} 1121 | 1122 | '@types/node@22.10.4': 1123 | dependencies: 1124 | undici-types: 6.20.0 1125 | 1126 | '@vitest/coverage-v8@2.1.8(vitest@2.1.8(@types/node@22.10.4))': 1127 | dependencies: 1128 | '@ampproject/remapping': 2.3.0 1129 | '@bcoe/v8-coverage': 0.2.3 1130 | debug: 4.4.0 1131 | istanbul-lib-coverage: 3.2.2 1132 | istanbul-lib-report: 3.0.1 1133 | istanbul-lib-source-maps: 5.0.6 1134 | istanbul-reports: 3.1.7 1135 | magic-string: 0.30.17 1136 | magicast: 0.3.5 1137 | std-env: 3.8.0 1138 | test-exclude: 7.0.1 1139 | tinyrainbow: 1.2.0 1140 | vitest: 2.1.8(@types/node@22.10.4) 1141 | transitivePeerDependencies: 1142 | - supports-color 1143 | 1144 | '@vitest/expect@2.1.8': 1145 | dependencies: 1146 | '@vitest/spy': 2.1.8 1147 | '@vitest/utils': 2.1.8 1148 | chai: 5.1.2 1149 | tinyrainbow: 1.2.0 1150 | 1151 | '@vitest/mocker@2.1.8(vite@5.4.11(@types/node@22.10.4))': 1152 | dependencies: 1153 | '@vitest/spy': 2.1.8 1154 | estree-walker: 3.0.3 1155 | magic-string: 0.30.17 1156 | optionalDependencies: 1157 | vite: 5.4.11(@types/node@22.10.4) 1158 | 1159 | '@vitest/pretty-format@2.1.8': 1160 | dependencies: 1161 | tinyrainbow: 1.2.0 1162 | 1163 | '@vitest/runner@2.1.8': 1164 | dependencies: 1165 | '@vitest/utils': 2.1.8 1166 | pathe: 1.1.2 1167 | 1168 | '@vitest/snapshot@2.1.8': 1169 | dependencies: 1170 | '@vitest/pretty-format': 2.1.8 1171 | magic-string: 0.30.17 1172 | pathe: 1.1.2 1173 | 1174 | '@vitest/spy@2.1.8': 1175 | dependencies: 1176 | tinyspy: 3.0.2 1177 | 1178 | '@vitest/utils@2.1.8': 1179 | dependencies: 1180 | '@vitest/pretty-format': 2.1.8 1181 | loupe: 3.1.2 1182 | tinyrainbow: 1.2.0 1183 | 1184 | ajv@6.12.6: 1185 | dependencies: 1186 | fast-deep-equal: 3.1.3 1187 | fast-json-stable-stringify: 2.1.0 1188 | json-schema-traverse: 0.4.1 1189 | uri-js: 4.4.1 1190 | 1191 | ansi-regex@5.0.1: {} 1192 | 1193 | ansi-regex@6.1.0: {} 1194 | 1195 | ansi-styles@4.3.0: 1196 | dependencies: 1197 | color-convert: 2.0.1 1198 | 1199 | ansi-styles@6.2.1: {} 1200 | 1201 | argparse@1.0.10: 1202 | dependencies: 1203 | sprintf-js: 1.0.3 1204 | 1205 | asn1@0.2.6: 1206 | dependencies: 1207 | safer-buffer: 2.1.2 1208 | 1209 | assert-plus@1.0.0: {} 1210 | 1211 | assertion-error@2.0.1: {} 1212 | 1213 | asynckit@0.4.0: {} 1214 | 1215 | aws-sign2@0.7.0: {} 1216 | 1217 | aws4@1.13.2: {} 1218 | 1219 | balanced-match@1.0.2: {} 1220 | 1221 | bcrypt-pbkdf@1.0.2: 1222 | dependencies: 1223 | tweetnacl: 0.14.5 1224 | 1225 | brace-expansion@2.0.1: 1226 | dependencies: 1227 | balanced-match: 1.0.2 1228 | 1229 | cac@6.7.14: {} 1230 | 1231 | caseless@0.12.0: {} 1232 | 1233 | chai@5.1.2: 1234 | dependencies: 1235 | assertion-error: 2.0.1 1236 | check-error: 2.1.1 1237 | deep-eql: 5.0.2 1238 | loupe: 3.1.2 1239 | pathval: 2.0.0 1240 | 1241 | check-error@2.1.1: {} 1242 | 1243 | color-convert@2.0.1: 1244 | dependencies: 1245 | color-name: 1.1.4 1246 | 1247 | color-name@1.1.4: {} 1248 | 1249 | combined-stream@1.0.8: 1250 | dependencies: 1251 | delayed-stream: 1.0.0 1252 | 1253 | core-util-is@1.0.2: {} 1254 | 1255 | coveralls@3.1.1: 1256 | dependencies: 1257 | js-yaml: 3.14.1 1258 | lcov-parse: 1.0.0 1259 | log-driver: 1.2.7 1260 | minimist: 1.2.8 1261 | request: 2.88.2 1262 | 1263 | cross-spawn@7.0.6: 1264 | dependencies: 1265 | path-key: 3.1.1 1266 | shebang-command: 2.0.0 1267 | which: 2.0.2 1268 | 1269 | dashdash@1.14.1: 1270 | dependencies: 1271 | assert-plus: 1.0.0 1272 | 1273 | debug@4.4.0: 1274 | dependencies: 1275 | ms: 2.1.3 1276 | 1277 | deep-eql@5.0.2: {} 1278 | 1279 | delayed-stream@1.0.0: {} 1280 | 1281 | eastasianwidth@0.2.0: {} 1282 | 1283 | ecc-jsbn@0.1.2: 1284 | dependencies: 1285 | jsbn: 0.1.1 1286 | safer-buffer: 2.1.2 1287 | 1288 | emoji-regex@8.0.0: {} 1289 | 1290 | emoji-regex@9.2.2: {} 1291 | 1292 | es-module-lexer@1.6.0: {} 1293 | 1294 | esbuild@0.21.5: 1295 | optionalDependencies: 1296 | '@esbuild/aix-ppc64': 0.21.5 1297 | '@esbuild/android-arm': 0.21.5 1298 | '@esbuild/android-arm64': 0.21.5 1299 | '@esbuild/android-x64': 0.21.5 1300 | '@esbuild/darwin-arm64': 0.21.5 1301 | '@esbuild/darwin-x64': 0.21.5 1302 | '@esbuild/freebsd-arm64': 0.21.5 1303 | '@esbuild/freebsd-x64': 0.21.5 1304 | '@esbuild/linux-arm': 0.21.5 1305 | '@esbuild/linux-arm64': 0.21.5 1306 | '@esbuild/linux-ia32': 0.21.5 1307 | '@esbuild/linux-loong64': 0.21.5 1308 | '@esbuild/linux-mips64el': 0.21.5 1309 | '@esbuild/linux-ppc64': 0.21.5 1310 | '@esbuild/linux-riscv64': 0.21.5 1311 | '@esbuild/linux-s390x': 0.21.5 1312 | '@esbuild/linux-x64': 0.21.5 1313 | '@esbuild/netbsd-x64': 0.21.5 1314 | '@esbuild/openbsd-x64': 0.21.5 1315 | '@esbuild/sunos-x64': 0.21.5 1316 | '@esbuild/win32-arm64': 0.21.5 1317 | '@esbuild/win32-ia32': 0.21.5 1318 | '@esbuild/win32-x64': 0.21.5 1319 | 1320 | esprima@4.0.1: {} 1321 | 1322 | estree-walker@3.0.3: 1323 | dependencies: 1324 | '@types/estree': 1.0.6 1325 | 1326 | expect-type@1.1.0: {} 1327 | 1328 | extend@3.0.2: {} 1329 | 1330 | extsprintf@1.3.0: {} 1331 | 1332 | fast-deep-equal@3.1.3: {} 1333 | 1334 | fast-json-stable-stringify@2.1.0: {} 1335 | 1336 | foreground-child@3.3.0: 1337 | dependencies: 1338 | cross-spawn: 7.0.6 1339 | signal-exit: 4.1.0 1340 | 1341 | forever-agent@0.6.1: {} 1342 | 1343 | form-data@2.3.3: 1344 | dependencies: 1345 | asynckit: 0.4.0 1346 | combined-stream: 1.0.8 1347 | mime-types: 2.1.35 1348 | 1349 | fsevents@2.3.3: 1350 | optional: true 1351 | 1352 | getpass@0.1.7: 1353 | dependencies: 1354 | assert-plus: 1.0.0 1355 | 1356 | glob@10.4.5: 1357 | dependencies: 1358 | foreground-child: 3.3.0 1359 | jackspeak: 3.4.3 1360 | minimatch: 9.0.5 1361 | minipass: 7.1.2 1362 | package-json-from-dist: 1.0.1 1363 | path-scurry: 1.11.1 1364 | 1365 | har-schema@2.0.0: {} 1366 | 1367 | har-validator@5.1.5: 1368 | dependencies: 1369 | ajv: 6.12.6 1370 | har-schema: 2.0.0 1371 | 1372 | has-flag@4.0.0: {} 1373 | 1374 | html-escaper@2.0.2: {} 1375 | 1376 | http-signature@1.2.0: 1377 | dependencies: 1378 | assert-plus: 1.0.0 1379 | jsprim: 1.4.2 1380 | sshpk: 1.18.0 1381 | 1382 | is-fullwidth-code-point@3.0.0: {} 1383 | 1384 | is-typedarray@1.0.0: {} 1385 | 1386 | isexe@2.0.0: {} 1387 | 1388 | isstream@0.1.2: {} 1389 | 1390 | istanbul-lib-coverage@3.2.2: {} 1391 | 1392 | istanbul-lib-report@3.0.1: 1393 | dependencies: 1394 | istanbul-lib-coverage: 3.2.2 1395 | make-dir: 4.0.0 1396 | supports-color: 7.2.0 1397 | 1398 | istanbul-lib-source-maps@5.0.6: 1399 | dependencies: 1400 | '@jridgewell/trace-mapping': 0.3.25 1401 | debug: 4.4.0 1402 | istanbul-lib-coverage: 3.2.2 1403 | transitivePeerDependencies: 1404 | - supports-color 1405 | 1406 | istanbul-reports@3.1.7: 1407 | dependencies: 1408 | html-escaper: 2.0.2 1409 | istanbul-lib-report: 3.0.1 1410 | 1411 | jackspeak@3.4.3: 1412 | dependencies: 1413 | '@isaacs/cliui': 8.0.2 1414 | optionalDependencies: 1415 | '@pkgjs/parseargs': 0.11.0 1416 | 1417 | js-yaml@3.14.1: 1418 | dependencies: 1419 | argparse: 1.0.10 1420 | esprima: 4.0.1 1421 | 1422 | jsbn@0.1.1: {} 1423 | 1424 | json-schema-traverse@0.4.1: {} 1425 | 1426 | json-schema@0.4.0: {} 1427 | 1428 | json-stringify-safe@5.0.1: {} 1429 | 1430 | jsprim@1.4.2: 1431 | dependencies: 1432 | assert-plus: 1.0.0 1433 | extsprintf: 1.3.0 1434 | json-schema: 0.4.0 1435 | verror: 1.10.0 1436 | 1437 | lcov-parse@1.0.0: {} 1438 | 1439 | lodash-es@4.17.21: {} 1440 | 1441 | log-driver@1.2.7: {} 1442 | 1443 | loupe@3.1.2: {} 1444 | 1445 | lru-cache@10.4.3: {} 1446 | 1447 | magic-string@0.30.17: 1448 | dependencies: 1449 | '@jridgewell/sourcemap-codec': 1.5.0 1450 | 1451 | magicast@0.3.5: 1452 | dependencies: 1453 | '@babel/parser': 7.26.3 1454 | '@babel/types': 7.26.3 1455 | source-map-js: 1.2.1 1456 | 1457 | make-dir@4.0.0: 1458 | dependencies: 1459 | semver: 7.6.3 1460 | 1461 | mime-db@1.52.0: {} 1462 | 1463 | mime-types@2.1.35: 1464 | dependencies: 1465 | mime-db: 1.52.0 1466 | 1467 | minimatch@9.0.5: 1468 | dependencies: 1469 | brace-expansion: 2.0.1 1470 | 1471 | minimist@1.2.8: {} 1472 | 1473 | minipass@7.1.2: {} 1474 | 1475 | ms@2.1.3: {} 1476 | 1477 | nanoid@3.3.8: {} 1478 | 1479 | oauth-sign@0.9.0: {} 1480 | 1481 | package-json-from-dist@1.0.1: {} 1482 | 1483 | path-key@3.1.1: {} 1484 | 1485 | path-scurry@1.11.1: 1486 | dependencies: 1487 | lru-cache: 10.4.3 1488 | minipass: 7.1.2 1489 | 1490 | pathe@1.1.2: {} 1491 | 1492 | pathval@2.0.0: {} 1493 | 1494 | performance-now@2.1.0: {} 1495 | 1496 | picocolors@1.1.1: {} 1497 | 1498 | postcss@8.4.49: 1499 | dependencies: 1500 | nanoid: 3.3.8 1501 | picocolors: 1.1.1 1502 | source-map-js: 1.2.1 1503 | 1504 | prettier@3.4.2: {} 1505 | 1506 | psl@1.15.0: 1507 | dependencies: 1508 | punycode: 2.3.1 1509 | 1510 | punycode@2.3.1: {} 1511 | 1512 | qs@6.5.3: {} 1513 | 1514 | request@2.88.2: 1515 | dependencies: 1516 | aws-sign2: 0.7.0 1517 | aws4: 1.13.2 1518 | caseless: 0.12.0 1519 | combined-stream: 1.0.8 1520 | extend: 3.0.2 1521 | forever-agent: 0.6.1 1522 | form-data: 2.3.3 1523 | har-validator: 5.1.5 1524 | http-signature: 1.2.0 1525 | is-typedarray: 1.0.0 1526 | isstream: 0.1.2 1527 | json-stringify-safe: 5.0.1 1528 | mime-types: 2.1.35 1529 | oauth-sign: 0.9.0 1530 | performance-now: 2.1.0 1531 | qs: 6.5.3 1532 | safe-buffer: 5.2.1 1533 | tough-cookie: 2.5.0 1534 | tunnel-agent: 0.6.0 1535 | uuid: 3.4.0 1536 | 1537 | rollup@4.29.1: 1538 | dependencies: 1539 | '@types/estree': 1.0.6 1540 | optionalDependencies: 1541 | '@rollup/rollup-android-arm-eabi': 4.29.1 1542 | '@rollup/rollup-android-arm64': 4.29.1 1543 | '@rollup/rollup-darwin-arm64': 4.29.1 1544 | '@rollup/rollup-darwin-x64': 4.29.1 1545 | '@rollup/rollup-freebsd-arm64': 4.29.1 1546 | '@rollup/rollup-freebsd-x64': 4.29.1 1547 | '@rollup/rollup-linux-arm-gnueabihf': 4.29.1 1548 | '@rollup/rollup-linux-arm-musleabihf': 4.29.1 1549 | '@rollup/rollup-linux-arm64-gnu': 4.29.1 1550 | '@rollup/rollup-linux-arm64-musl': 4.29.1 1551 | '@rollup/rollup-linux-loongarch64-gnu': 4.29.1 1552 | '@rollup/rollup-linux-powerpc64le-gnu': 4.29.1 1553 | '@rollup/rollup-linux-riscv64-gnu': 4.29.1 1554 | '@rollup/rollup-linux-s390x-gnu': 4.29.1 1555 | '@rollup/rollup-linux-x64-gnu': 4.29.1 1556 | '@rollup/rollup-linux-x64-musl': 4.29.1 1557 | '@rollup/rollup-win32-arm64-msvc': 4.29.1 1558 | '@rollup/rollup-win32-ia32-msvc': 4.29.1 1559 | '@rollup/rollup-win32-x64-msvc': 4.29.1 1560 | fsevents: 2.3.3 1561 | 1562 | safe-buffer@5.2.1: {} 1563 | 1564 | safer-buffer@2.1.2: {} 1565 | 1566 | semver@7.6.3: {} 1567 | 1568 | shebang-command@2.0.0: 1569 | dependencies: 1570 | shebang-regex: 3.0.0 1571 | 1572 | shebang-regex@3.0.0: {} 1573 | 1574 | siginfo@2.0.0: {} 1575 | 1576 | signal-exit@4.1.0: {} 1577 | 1578 | source-map-js@1.2.1: {} 1579 | 1580 | sprintf-js@1.0.3: {} 1581 | 1582 | sshpk@1.18.0: 1583 | dependencies: 1584 | asn1: 0.2.6 1585 | assert-plus: 1.0.0 1586 | bcrypt-pbkdf: 1.0.2 1587 | dashdash: 1.14.1 1588 | ecc-jsbn: 0.1.2 1589 | getpass: 0.1.7 1590 | jsbn: 0.1.1 1591 | safer-buffer: 2.1.2 1592 | tweetnacl: 0.14.5 1593 | 1594 | stackback@0.0.2: {} 1595 | 1596 | std-env@3.8.0: {} 1597 | 1598 | string-width@4.2.3: 1599 | dependencies: 1600 | emoji-regex: 8.0.0 1601 | is-fullwidth-code-point: 3.0.0 1602 | strip-ansi: 6.0.1 1603 | 1604 | string-width@5.1.2: 1605 | dependencies: 1606 | eastasianwidth: 0.2.0 1607 | emoji-regex: 9.2.2 1608 | strip-ansi: 7.1.0 1609 | 1610 | strip-ansi@6.0.1: 1611 | dependencies: 1612 | ansi-regex: 5.0.1 1613 | 1614 | strip-ansi@7.1.0: 1615 | dependencies: 1616 | ansi-regex: 6.1.0 1617 | 1618 | supports-color@7.2.0: 1619 | dependencies: 1620 | has-flag: 4.0.0 1621 | 1622 | test-exclude@7.0.1: 1623 | dependencies: 1624 | '@istanbuljs/schema': 0.1.3 1625 | glob: 10.4.5 1626 | minimatch: 9.0.5 1627 | 1628 | tinybench@2.9.0: {} 1629 | 1630 | tinyexec@0.3.2: {} 1631 | 1632 | tinypool@1.0.2: {} 1633 | 1634 | tinyrainbow@1.2.0: {} 1635 | 1636 | tinyspy@3.0.2: {} 1637 | 1638 | tough-cookie@2.5.0: 1639 | dependencies: 1640 | psl: 1.15.0 1641 | punycode: 2.3.1 1642 | 1643 | tunnel-agent@0.6.0: 1644 | dependencies: 1645 | safe-buffer: 5.2.1 1646 | 1647 | tweetnacl@0.14.5: {} 1648 | 1649 | typescript@5.7.2: {} 1650 | 1651 | undici-types@6.20.0: {} 1652 | 1653 | uri-js@4.4.1: 1654 | dependencies: 1655 | punycode: 2.3.1 1656 | 1657 | uuid@3.4.0: {} 1658 | 1659 | verror@1.10.0: 1660 | dependencies: 1661 | assert-plus: 1.0.0 1662 | core-util-is: 1.0.2 1663 | extsprintf: 1.3.0 1664 | 1665 | vite-node@2.1.8(@types/node@22.10.4): 1666 | dependencies: 1667 | cac: 6.7.14 1668 | debug: 4.4.0 1669 | es-module-lexer: 1.6.0 1670 | pathe: 1.1.2 1671 | vite: 5.4.11(@types/node@22.10.4) 1672 | transitivePeerDependencies: 1673 | - '@types/node' 1674 | - less 1675 | - lightningcss 1676 | - sass 1677 | - sass-embedded 1678 | - stylus 1679 | - sugarss 1680 | - supports-color 1681 | - terser 1682 | 1683 | vite@5.4.11(@types/node@22.10.4): 1684 | dependencies: 1685 | esbuild: 0.21.5 1686 | postcss: 8.4.49 1687 | rollup: 4.29.1 1688 | optionalDependencies: 1689 | '@types/node': 22.10.4 1690 | fsevents: 2.3.3 1691 | 1692 | vitest@2.1.8(@types/node@22.10.4): 1693 | dependencies: 1694 | '@vitest/expect': 2.1.8 1695 | '@vitest/mocker': 2.1.8(vite@5.4.11(@types/node@22.10.4)) 1696 | '@vitest/pretty-format': 2.1.8 1697 | '@vitest/runner': 2.1.8 1698 | '@vitest/snapshot': 2.1.8 1699 | '@vitest/spy': 2.1.8 1700 | '@vitest/utils': 2.1.8 1701 | chai: 5.1.2 1702 | debug: 4.4.0 1703 | expect-type: 1.1.0 1704 | magic-string: 0.30.17 1705 | pathe: 1.1.2 1706 | std-env: 3.8.0 1707 | tinybench: 2.9.0 1708 | tinyexec: 0.3.2 1709 | tinypool: 1.0.2 1710 | tinyrainbow: 1.2.0 1711 | vite: 5.4.11(@types/node@22.10.4) 1712 | vite-node: 2.1.8(@types/node@22.10.4) 1713 | why-is-node-running: 2.3.0 1714 | optionalDependencies: 1715 | '@types/node': 22.10.4 1716 | transitivePeerDependencies: 1717 | - less 1718 | - lightningcss 1719 | - msw 1720 | - sass 1721 | - sass-embedded 1722 | - stylus 1723 | - sugarss 1724 | - supports-color 1725 | - terser 1726 | 1727 | which@2.0.2: 1728 | dependencies: 1729 | isexe: 2.0.0 1730 | 1731 | why-is-node-running@2.3.0: 1732 | dependencies: 1733 | siginfo: 2.0.0 1734 | stackback: 0.0.2 1735 | 1736 | wrap-ansi@7.0.0: 1737 | dependencies: 1738 | ansi-styles: 4.3.0 1739 | string-width: 4.2.3 1740 | strip-ansi: 6.0.1 1741 | 1742 | wrap-ansi@8.1.0: 1743 | dependencies: 1744 | ansi-styles: 6.2.1 1745 | string-width: 5.1.2 1746 | strip-ansi: 7.1.0 1747 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | reporter: ['lcov'], 7 | }, 8 | }, 9 | }) --------------------------------------------------------------------------------