├── .changeset
├── README.md
└── config.json
├── .cleanmodules-default
├── .gitattributes
├── .github
└── workflows
│ ├── changesets.yml
│ └── checks.yml
├── .gitignore
├── .prettierrc
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── __mocks__
└── fs
│ ├── index.ts
│ └── promises.ts
├── bin
└── cli.js
├── biome.json
├── images
├── dry-run.png
├── large-project.png
└── small-project.png
├── package.json
├── pnpm-lock.yaml
├── src
├── __test__
│ ├── getMockedFileStructure.ts
│ └── path.serializer.ts
├── analyze.test.ts
├── analyze.ts
├── clean.test.ts
├── clean.ts
├── cli
│ ├── cli.ts
│ ├── commands
│ │ ├── analyze.command.ts
│ │ └── clean.command.ts
│ ├── helpers
│ │ └── base.command.ts
│ └── utils
│ │ └── terminal.ts
├── index.ts
├── shared.ts
└── utils
│ ├── filesystem.test.ts
│ ├── filesystem.ts
│ ├── glob.test.ts
│ └── glob.ts
├── tsconfig.json
├── tsup.config.ts
├── vitest.config.ts
└── vitest.setup.ts
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4 | with multi-package repos, or single-package repos to help you version and publish your code. You can
5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6 |
7 | We have a quick list of common questions to get you started engaging with this project in
8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
9 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@2.1.1/schema.json",
3 | "changelog": ["changesets-changelog-clean", { "repo": "duniul/clean-modules" }],
4 | "commit": false,
5 | "fixed": [],
6 | "linked": [],
7 | "access": "public",
8 | "baseBranch": "main",
9 | "updateInternalDependencies": "patch",
10 | "ignore": []
11 | }
12 |
--------------------------------------------------------------------------------
/.cleanmodules-default:
--------------------------------------------------------------------------------
1 | #
2 | # DIRECTORIES
3 | # Directory globs must end with either / or /* or /**
4 | #
5 |
6 | # test
7 | __tests__/
8 | test/
9 | tests/
10 | powered-test/
11 |
12 | # docs
13 | docs/
14 | doc/
15 |
16 | # IDE
17 | .idea/
18 | .vscode/
19 |
20 | # examples
21 | example/
22 | examples/
23 |
24 | # code coverage
25 | coverage/
26 | .nyc_output/
27 | .nycrc/
28 |
29 | # CI/CD
30 | .circleci/
31 | .github/
32 |
33 | # git
34 | .git/
35 |
36 | # other
37 | website/
38 | .husky/
39 |
40 | #
41 | # FILE EXTENSIONS
42 | #
43 |
44 | # IDE
45 | *.iml
46 |
47 | # tests
48 | *.test.*
49 |
50 | # source maps
51 | *.map
52 |
53 | # docs/text
54 | *.@(md|mkd|markdown|mdown)
55 | *.todo
56 | *.mustache
57 | *.@(adoc|asciidoc)
58 | *.DOCS
59 |
60 | # compiled
61 | # include .ts files but not .d.ts
62 | \!(*.d).ts
63 | *.coffee
64 |
65 | # compressed
66 | *.zip
67 | *.7z
68 | *.rar
69 | *.tar
70 | *.tgz
71 |
72 | # images
73 | *.@(jpg|jpeg)
74 | *.png
75 | *.gif
76 |
77 | # compiled
78 | *.h
79 | *.c
80 | *.hpp
81 | *.cpp
82 | *.o
83 | *.mk
84 |
85 | # other
86 | *.log
87 | *.tlog
88 | *.patch
89 | *.sln
90 | *.pdb
91 | *.jst
92 | *.swp
93 | *.lock
94 | *.vcxproj*(.*)
95 | *.orig
96 | *.rej
97 |
98 | #
99 | # FILES
100 | #
101 |
102 | # build scripts/files
103 | makefile*(.*)
104 | gemfile*(.*)
105 | gulpfile*(.*)
106 | gruntfile*(.*)
107 | rakefile*(.*)
108 |
109 | # CI/CD
110 | Jenkinsfile
111 | .travis.yml
112 | .gitlab-ci.yml
113 | .appveyor.yml
114 | circle.yml
115 | .nojekyll
116 |
117 | # Mac OS
118 | .DS_Store
119 |
120 | # Windows
121 | Desktop.ini
122 | Thumbs.db
123 |
124 | # linters
125 | .eslintrc*(.*)
126 | eslint.config.@(cjs|js|mjs)
127 | stylelint.config.js
128 | .stylelintrc*(.*)
129 | .htmllintrc*(.*)
130 | htmllint.js
131 | .jshintrc*(.*)
132 | .lint
133 | tslint.json
134 | .lintignore
135 | .jshintignore
136 | .eslintignore
137 |
138 | # prettier
139 | .prettierrc*(.*)
140 | prettier.config.js
141 |
142 | # testing
143 | \!(utils)/test.js
144 | jest.config.js
145 | karma.conf.js
146 | wallaby.js
147 | wallaby.conf.js
148 | .coveralls.yml
149 | .airtap.yml
150 |
151 | # docs
152 | readme*(.*)
153 | changelog*(.*)
154 | changes*(.*)
155 | authors*(.*)
156 | contributors*(.*)
157 | contributing*(.*)
158 | notice*(.*)
159 | copying*(.*)
160 |
161 | # licenses
162 | licen@(s|c)e
163 | licen@(s|c)e-mit
164 | licen@(s|c)e.txt
165 | licen@(s|c)e-mit.txt
166 |
167 | # typescript
168 | .tsbuildinfo
169 |
170 | # npm
171 | .npmrc
172 |
173 | # ignore files
174 | .*ignore
175 |
176 | # yarn
177 | yarn.lock
178 | .yarnclean
179 | .yarn-metadata.json
180 |
181 | # git
182 | .gitmodules
183 | .gitattributes
184 |
185 | # configs
186 | .npmrc
187 | .babelrc
188 | .editorconfig
189 | .tern-project
190 | .flowconfig
191 | .documentup.json
192 | .yo-rc.json
193 | _config.yml
194 | bower.json
195 | renovate.json
196 | .vimrc*(.*)
197 | .zuul.yml
198 | .istanbul.yml
199 | .nycrc
200 | .jscsrc
201 |
202 | # versioning
203 | .bmp.yml
204 | .release-it.@(cjs|js|json|toml|ts|yaml|yml)
205 |
206 | # other
207 | .dir-locals.el
208 | binding.gyp
209 | cakefile
210 | component.json
211 | composer.json
212 | contributors
213 | .jamignore
214 | .codecov.yml
215 | pom.xml
216 | OSSMETADATA
217 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 | *.jpg binary
3 | *.png binary
4 | *.gif binary
5 |
--------------------------------------------------------------------------------
/.github/workflows/changesets.yml:
--------------------------------------------------------------------------------
1 | name: 🆕 Release management
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - '.vscode/**'
9 | - 'images/**'
10 | - '*.md'
11 |
12 | concurrency: ${{ github.workflow }}-${{ github.ref }}
13 |
14 | permissions:
15 | contents: write
16 | pull-requests: write
17 |
18 | jobs:
19 | main:
20 | name: Publish changed packages
21 | runs-on: ubuntu-latest
22 | steps:
23 | - name: 🏗 Setup repo
24 | uses: actions/checkout@v4
25 |
26 | - name: 🏗 Setup pnpm
27 | uses: pnpm/action-setup@v2
28 | with:
29 | version: 8
30 |
31 | - name: 🏗 Setup Node
32 | uses: actions/setup-node@v3
33 | with:
34 | node-version: 18.x
35 | cache: pnpm
36 |
37 | - name: 📦 Install dependencies
38 | run: pnpm install
39 |
40 | - name: 🆕 Publish to npm or create release PR
41 | id: changesets
42 | uses: changesets/action@v1
43 | with:
44 | title: '🆕 Upcoming release'
45 | commit: 'chore: bump version'
46 | version: pnpm run version
47 | publish: pnpm run release
48 | env:
49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
51 |
--------------------------------------------------------------------------------
/.github/workflows/checks.yml:
--------------------------------------------------------------------------------
1 | name: 🕵️ Checks
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | paths-ignore:
7 | - '.vscode/**'
8 | - 'images/**'
9 | - '*.md'
10 |
11 | permissions:
12 | contents: read
13 |
14 | jobs:
15 | build:
16 | name: 🧱 Build
17 | runs-on: ubuntu-latest
18 | permissions:
19 | contents: read
20 | steps:
21 | - name: 🏗 Setup repo
22 | uses: actions/checkout@v4
23 |
24 | - name: 🏗 Setup pnpm
25 | uses: pnpm/action-setup@v2
26 | with:
27 | version: 8
28 |
29 | - name: 🏗 Setup Node
30 | uses: actions/setup-node@v3
31 | with:
32 | node-version: 18.x
33 | cache: pnpm
34 |
35 | - name: 📦 Install dependencies
36 | run: pnpm install
37 |
38 | - name: 🧱 Build project
39 | run: pnpm build
40 |
41 | test:
42 | name: 🧪 Test
43 | strategy:
44 | matrix:
45 | os: [ubuntu-latest, macos-latest, windows-latest]
46 | node-version: [14.x, 18.x]
47 |
48 | runs-on: ${{ matrix.os }}
49 |
50 | steps:
51 | - name: 🏗 Setup repo
52 | uses: actions/checkout@v4
53 |
54 | - name: 🏗 Setup pnpm
55 | uses: pnpm/action-setup@v2
56 | with:
57 | version: 8
58 |
59 | - name: 🏗 Setup Node
60 | uses: actions/setup-node@v3
61 | with:
62 | node-version: 18.x
63 | cache: pnpm
64 |
65 | - name: 📦 Install dependencies
66 | run: pnpm install
67 |
68 | - name: 🧪 Run tests
69 | run: pnpm test
70 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # Snowpack dependency directory (https://snowpack.dev/)
45 | web_modules/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 | .parcel-cache
78 |
79 | # Next.js build output
80 | .next
81 | out
82 |
83 | # Nuxt.js build / generate output
84 | .nuxt
85 | dist
86 |
87 | # Gatsby files
88 | .cache/
89 | # Comment in the public line in if your project uses Gatsby and not Next.js
90 | # https://nextjs.org/blog/next-9-1#public-directory-support
91 | # public
92 |
93 | # vuepress build output
94 | .vuepress/dist
95 |
96 | # Serverless directories
97 | .serverless/
98 |
99 | # FuseBox cache
100 | .fusebox/
101 |
102 | # DynamoDB Local files
103 | .dynamodb/
104 |
105 | # TernJS port file
106 | .tern-port
107 |
108 | # Stores VSCode versions used for testing VSCode extensions
109 | .vscode-test
110 |
111 | # yarn v2
112 | .yarn/*
113 | !.yarn/patches
114 | !.yarn/releases
115 | !.yarn/plugins
116 | !.yarn/sdks
117 | !.yarn/versions
118 | .pnp.*
119 |
120 | # Built files
121 | lib
122 | .tsbuildinfo
123 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "singleQuote": true,
4 | "printWidth": 100,
5 | "arrowParens": "avoid"
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // Make VSCode warn about same commit lengths for everyone
3 | "git.inputValidation": "warn",
4 | "git.inputValidationLength": 100,
5 | "git.inputValidationSubjectLength": 72,
6 |
7 | // Insert correct new lines and remove redundant whitespace to keep POSIX-compliant
8 | "files.insertFinalNewline": true,
9 | "files.trimFinalNewlines": true,
10 | "files.trimTrailingWhitespace": true,
11 |
12 | // Exclude frequently updated/large files that we usually don't care about
13 | "files.watcherExclude": {
14 | // VSCode defaults
15 | "**/.git/objects/**": true,
16 | "**/.git/subtree-cache/**": true,
17 | "**/node_modules/**": true,
18 | "**/.hg/store/**": true,
19 |
20 | // custom
21 | "**/dist/**": true,
22 | "**/lib/**": true,
23 | "**/coverage/**": true
24 | },
25 |
26 | // Treat .cleanmodules files as ignore files
27 | "files.associations": {
28 | ".cleanmodules*": "ignore",
29 | },
30 |
31 | // Ensure we use the same formatter for files
32 | "[javascript]": {
33 | "editor.defaultFormatter": "esbenp.prettier-vscode"
34 | },
35 | "[typescript]": {
36 | "editor.defaultFormatter": "esbenp.prettier-vscode"
37 | },
38 | "[json]": {
39 | "editor.defaultFormatter": "esbenp.prettier-vscode"
40 | },
41 | "[jsonc]": {
42 | "editor.defaultFormatter": "esbenp.prettier-vscode"
43 | },
44 | "[markdown]": {
45 | "editor.defaultFormatter": "esbenp.prettier-vscode",
46 | "files.trimTrailingWhitespace": false // Markdown uses trailing whitespace for line breaks
47 | },
48 |
49 | // Use same TypeScript version as repo rather than local user version
50 | "typescript.tsdk": "node_modules/typescript/lib",
51 | }
52 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # clean-modules
2 |
3 | ## 3.1.1
4 |
5 | ### Patch Changes
6 |
7 | - Respect `directory` option in `analyze` command. _[`529502e`](https://github.com/duniul/clean-modules/commit/529502e1de3da64b87dd40f631b0abd6f91879b7) [@duniul](https://github.com/duniul)_
8 |
9 | ## 3.1.0
10 |
11 | ### Minor Changes
12 |
13 | - Add default patterns for GitHub Pages, JetBrains, airtap, husky, bmp, release-it, Windows, and GNU COPYING. _[`#35`](https://github.com/duniul/clean-modules/pull/35) [`89fcb28`](https://github.com/duniul/clean-modules/commit/89fcb2862ab07bbd52cded0288b3bf694a974238) [@sdavids](https://github.com/sdavids)_
14 |
15 | ### Patch Changes
16 |
17 | - Include up to 2 fraction digits when reporting reduced size. _[`89dd555`](https://github.com/duniul/clean-modules/commit/89dd5554b44e8229ba8be7d6a2472d4c14bd9c02) [@duniul](https://github.com/duniul)_
18 |
19 | ## 3.0.5
20 |
21 | ### Patch Changes
22 |
23 | - Add `adoc` to the AsciiDoc glob in `.cleanmodules-default`. _[`#32`](https://github.com/duniul/clean-modules/pull/32) [`e0b0239`](https://github.com/duniul/clean-modules/commit/e0b0239ea1fbddde9382ead635716a8d2253a41b) [@sdavids](https://github.com/sdavids)_
24 | - Add glob for OSSMETADATA to `.cleanmodules-default`. _[`#30`](https://github.com/duniul/clean-modules/pull/30) [`cf70c0b`](https://github.com/duniul/clean-modules/commit/cf70c0b326320078a08d91a98a9f4216100477c4) [@sdavids](https://github.com/sdavids)_
25 | - Add glob for new ESLint config files to `.cleanmodules-default`. _[`#28`](https://github.com/duniul/clean-modules/pull/28) [`680825a`](https://github.com/duniul/clean-modules/commit/680825ae8b554bc047627c51c032e01990f4b9f6) [@sdavids](https://github.com/sdavids)_
26 |
27 | ## 3.0.4
28 |
29 | ### Patch Changes
30 |
31 | - Add `.stylelintrc*(.*)` to `.cleanmodules-default`. _[`#24`](https://github.com/duniul/clean-modules/pull/24) [`31fb7eb`](https://github.com/duniul/clean-modules/commit/31fb7eb5a2807a54888f60d1d704b1ef565d1d9d) [@SukkaW](https://github.com/SukkaW)_
32 |
33 | ## 3.0.3
34 |
35 | ### Patch Changes
36 |
37 | - Fix `import.meta.url` not being transpiled to an equivalent value for CJS builds. _[`#22`](https://github.com/duniul/clean-modules/pull/22) [`efa65b5`](https://github.com/duniul/clean-modules/commit/efa65b5aa011053f57279eb9233c83331549e3f8) [@duniul](https://github.com/duniul)_
38 |
39 | ## 3.0.2
40 |
41 | (includes 3.0.0 and 3.0.1, which were unpublished)
42 |
43 | ### Major Changes
44 |
45 | - **BREAKING** Replace `-i,--include` and `-e,--exclude` with globs passed as positional arguments. This makes them consistent with the glob file patterns. _[`de47cf2`](https://github.com/duniul/clean-modules/commit/de47cf22adb5a44507a0dde1caa763fd98c16eba) [@duniul](https://github.com/duniul)_
46 |
47 | To migrate, move included and excluded globs to the end of the command, and prefix any exclusion globs with `!`.
48 |
49 | ```sh
50 | # before
51 | clean-modules --include "foo" "bar" --exclude "baz" "qux"
52 |
53 | # after
54 | clean-modules "foo" "bar" "!baz" "!qux"
55 | ```
56 |
57 | - **BREAKING** Replace old programmatic API with one that better correspond to the CLI commands. See the README for information on how to import them. _[`6c8dfff`](https://github.com/duniul/clean-modules/commit/6c8dfff6f151d56a661a7759d36e35162889afad) [@duniul](https://github.com/duniul)_
58 | - **BREAKING** Drop support for Node 12, require Node >= 14. _[`0ebf930`](https://github.com/duniul/clean-modules/commit/0ebf9307371cbd6d4a966139f020a8d1a9e0d0a1) [@duniul](https://github.com/duniul)_
59 |
60 | ### Patch Changes
61 |
62 | - Replace `yargs` with `clipanion` for CLI parsing. _[`de47cf2`](https://github.com/duniul/clean-modules/commit/de47cf22adb5a44507a0dde1caa763fd98c16eba) [@duniul](https://github.com/duniul)_
63 | - Don't remove `tsconfig.json` files by default, as they can be shared. _[`17603eb`](https://github.com/duniul/clean-modules/commit/17603ebcdd9d27d46abdce4805e8dfbe0deae3ae) [@duniul](https://github.com/duniul)_
64 | - Update `pretty-bytes`, `pretty-ms` and `supports-color`. _[`e198b46`](https://github.com/duniul/clean-modules/commit/e198b468174afa9b72fe160a553a659bfe255bf0) [@duniul](https://github.com/duniul)_
65 | - Remove `arg` as a runtime dependency. _[`95b0dcf`](https://github.com/duniul/clean-modules/commit/95b0dcf0693b6c14635497c866d717ae89820299) [@duniul](https://github.com/duniul)_
66 | - Try to avoid test util files when cleaning up test files. _[`cf7ede5`](https://github.com/duniul/clean-modules/commit/cf7ede5037e865851afff1e3b22502e5fb165fca) [@duniul](https://github.com/duniul)_
67 | - Fix issue where `--glob-file` could be passed as an array, causing a crash. _[`de47cf2`](https://github.com/duniul/clean-modules/commit/de47cf22adb5a44507a0dde1caa763fd98c16eba) [@duniul](https://github.com/duniul)_
68 |
69 | ## 2.0.6
70 |
71 | ### Patch Changes
72 |
73 | - Reduce `console` instead of `console.log` _[`#16`](https://github.com/duniul/clean-modules/pull/16) [`a0077d5`](https://github.com/duniul/clean-modules/commit/a0077d579b17650b284c4a5bc4f452e66356a423) [@Miikis](https://github.com/Miikis)_
74 |
75 | ## 2.0.5
76 |
77 | ### Patch Changes
78 |
79 | - Fix path issues on Windows. _[`#14`](https://github.com/duniul/clean-modules/pull/14) [`6a7fb5c`](https://github.com/duniul/clean-modules/commit/6a7fb5c015d9f1869fa8b016d63c8cd390a5e2a1) [@duniul](https://github.com/duniul)_
80 |
81 | ## 2.0.4
82 |
83 | ### Patch Changes
84 |
85 | - Remove custom help and version options in favor of yargs builtins. _[`#10`](https://github.com/duniul/clean-modules/pull/10) [`0f5fa14`](https://github.com/duniul/clean-modules/commit/0f5fa148b81a6bca1650430596ebc34779a4b126) [@duniul](https://github.com/duniul)_
86 |
87 | ## 2.0.3
88 |
89 | ### Patch Changes
90 |
91 | - Wrap globs with parantheses to prevent issues with scoped packages. _[`31b35c4`](https://github.com/duniul/clean-modules/commit/31b35c4e7aa2bc7ffc76300bb9177c43f794940a) [@duniul](https://github.com/duniul)_
92 | - Improve globs for files with optional file extensions. _[`a71a8e4`](https://github.com/duniul/clean-modules/commit/a71a8e4ca29a35e74806267e379a85c2e5764721) [@duniul](https://github.com/duniul)_
93 | - Bump dependencies _[`735bf95`](https://github.com/duniul/clean-modules/commit/735bf9586bac7fab59f01170bf192090de274903) [@duniul](https://github.com/duniul)_
94 | - Make files included by dir globs excludable. _[`6d4eceb`](https://github.com/duniul/clean-modules/commit/6d4ecebe33034be2a2997ebb93d8c1cb012f363a) [@duniul](https://github.com/duniul)_
95 | - Change `--directory` to expect a string. _[`#7`](https://github.com/duniul/clean-modules/pull/7) [`8e77f83`](https://github.com/duniul/clean-modules/commit/8e77f830c5b523d47906f87c8e68a988e55f5cdf) [@ImedAdel](https://github.com/ImedAdel)_
96 |
97 | ## 2.0.2
98 |
99 | ### Patch Changes
100 |
101 | - Use existing `.cleanmodules` file by default. _[`403045d`](https://github.com/duniul/clean-modules/commit/403045d275c36f2c27f13646fdb45ed53902b01a) [@duniul](https://github.com/duniul)_
102 |
103 | ## 2.0.1
104 |
105 | ### Patch Changes
106 |
107 | - Include `.cleanmodules-default` file. _[`61decf7`](https://github.com/duniul/clean-modules/commit/61decf7fd9b635f35daba10a58e7464c4db26b4a) [@duniul](https://github.com/duniul)_
108 |
109 | # 2.0.0
110 |
111 | ### BREAKING CHANGES
112 |
113 | - Node versions lower than 12 are no longer supported. _[`#5`](https://github.com/duniul/clean-modules/pull/5) [`d6c66f2`](https://github.com/duniul/clean-modules/commit/d6c66f2ab75ec03a573b848c396d74316fc085d6) [@duniul](https://github.com/duniul)_
114 | - A path to `node_modules` should now be supplied to the `--directory` option instead of a positional. _[`#5`](https://github.com/duniul/clean-modules/pull/5) [`6aa9d55`](https://github.com/duniul/clean-modules/commit/6aa9d556fe0fa42b70966c6e7788442dae7a3426) [@duniul](https://github.com/duniul)_
115 | - The `--analyze` option has been replaced by a separate command. _[`#5`](https://github.com/duniul/clean-modules/pull/5) [`6aa9d55`](https://github.com/duniul/clean-modules/commit/6aa9d556fe0fa42b70966c6e7788442dae7a3426) [@duniul](https://github.com/duniul)_
116 |
117 | ### Minor Changes
118 |
119 | - Add glob file support. _[`#5`](https://github.com/duniul/clean-modules/pull/5) [`43832f0`](https://github.com/duniul/clean-modules/commit/43832f08582ef55f33c7ee481c949a267a8f8a1d) [@duniul](https://github.com/duniul)_
120 |
121 | ## 1.0.4
122 |
123 | ### Patch Changes
124 |
125 | - Bump dependencies. _[`6aa9d55`](https://github.com/duniul/clean-modules/commit/6aa9d556fe0fa42b70966c6e7788442dae7a3426) [@duniul](https://github.com/duniul)_
126 | - Don't fail on invalid file paths. _[`#2`](https://github.com/duniul/clean-modules/pull/2) [`541ba1b`](https://github.com/duniul/clean-modules/commit/541ba1b3ca033b90df414fdcf6cea5f655daf3ae) [@duniul](https://github.com/duniul)_
127 |
128 | ## 1.0.3
129 |
130 | ### Patch Changes
131 |
132 | - Restrict license glob. _[`17bc9c0`](https://github.com/duniul/clean-modules/commit/17bc9c029f8197a7cb4514fd11eef32023855243) [@duniul](https://github.com/duniul)_
133 |
134 | ## 1.0.2
135 |
136 | ### Patch Changes
137 |
138 | - Add correct bin link. _[`75283b3`](https://github.com/duniul/clean-modules/commit/75283b3b0e5a42597e90209f60f85e83fc7429d7) [@duniul](https://github.com/duniul)_
139 |
140 | ## 1.0.1
141 |
142 | ### Patch Changes
143 |
144 | - Set `engines` to Node >=10. _[`75de40e`](https://github.com/duniul/clean-modules/commit/75de40eca44847cefb269b2b36ce2f36b27a93ca) [@duniul](https://github.com/duniul)_
145 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2020, Daniel Grefberg
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # clean-modules 🧹
2 |
3 |
4 |
5 |
6 |
7 |
8 | > Clean up/prune unnecessary files and reduce the size of your `node_modules` directory. Useful for
9 | > CI caches or for reducing the size of serverless functions.
10 |
11 | - 🧹 Removes directories and files that are unnecessary and **safe to remove in production**
12 | - 🛠 Easily customizable through glob patterns (either through [CLI args](#positionals) or a
13 | [configuration file](#glob-patterns-and-configuration-file))
14 | - 📁 Cleans up empty directories after removing files
15 | - ⚡️ Super fast, but still written in Node
16 | - 🔍 Allows analyzing results, like which pattern excluded which file
17 | - 🧑💻 Supports both CLI and programmatic usage
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## Table of contents
26 |
27 | Click to open
28 |
29 | - [Quick start](#quick-start)
30 | - [Installation](#installation)
31 | - [Commands](#commands)
32 | - [`clean-modules clean` (default command) 🧹](#clean-modules-clean-default-command-)
33 | - [Usage](#usage)
34 | - [Positionals](#positionals)
35 | - [Options](#options)
36 | - [`--directory | -D`](#--directory---d)
37 | - [`--glob-file | -f`](#--glob-file---f)
38 | - [`--no-defaults | -n`](#--no-defaults---n)
39 | - [`--keep-empty | -k`](#--keep-empty---k)
40 | - [`--dry-run | -d`](#--dry-run---d)
41 | - [`--json | -j`](#--json---j)
42 | - [`--yes | -y`](#--yes---y)
43 | - [`clean-modules analyze` 🔎](#clean-modules-analyze-)
44 | - [Usage](#usage-1)
45 | - [Positionals](#positionals-1)
46 | - [Options](#options-1)
47 | - [Example output](#example-output)
48 | - [Glob patterns and configuration file](#glob-patterns-and-configuration-file)
49 | - [Example configuration file](#example-configuration-file)
50 | - [Default globs](#default-globs)
51 | - [Common extra inclusions](#common-extra-inclusions)
52 | - [Common extra exclusions](#common-extra-exclusions)
53 | - [Programmatic usage](#programmatic-usage)
54 | - [Alternatives](#alternatives)
55 | - [Comparisons](#comparisons)
56 | - [clean-modules (this project)](#clean-modules-this-project)
57 | - [yarn autoclean](#yarn-autoclean)
58 | - [modclean](#modclean)
59 | - [node-prune](#node-prune)
60 | - [nm-prune](#nm-prune)
61 |
62 |
63 |
64 | ## Quick start
65 |
66 | Simply run the command in the directory where your `node_modules` are:
67 |
68 | ```bash
69 | clean-modules
70 | ```
71 |
72 | You can also pass any options that you need, like custom globs or a path to a specific
73 | `node_modules` directory.
74 |
75 | ```bash
76 | clean-modules --directory "path/to/node_modules" "extra/included/file/glob.txt" "!extra/excluded/glob.ts
77 | ```
78 |
79 | Check out the [command](#clean-modules-clean-default-command-🧹) section for all available options.
80 |
81 | ## Installation
82 |
83 | `clean-modules` can be installed globally if you only want to use it as a CLI tool. You can also
84 | install it locally if you want to use it in a package command.
85 |
86 | ```bash
87 | # global
88 | npm install --global clean-modules
89 |
90 | # dev dependency
91 | npm install --save-dev clean-modules
92 | ```
93 |
94 | ## Commands
95 |
96 | ### `clean-modules clean` (default command) 🧹
97 |
98 | The default command, cleans up your `node_modules` based on a set of _most likely_ safe glob
99 | patterns and removes empty directories.
100 |
101 | #### Usage
102 |
103 | ```bash
104 | clean-modules [options] <...globs>
105 | ```
106 |
107 | #### Positionals
108 |
109 | Extra glob patterns can be passed as positional arguments. By default they are combined with the globs loaded from the the default globs file and any custom globs file passed through the [`--glob-file`](#glob-file---f) option.
110 |
111 | For information on how the globs are parsed, see the [Glob patterns](#glob-patterns-and-configuration-file) section.
112 |
113 | **Example**:
114 |
115 | ```bash
116 | # include all TypeScript declaration files and @types folders
117 | clean-modules "**/*.d.ts" "**/@types/**"
118 |
119 | # exclude all sourcemap files and PNG files
120 | clean-modules "!**/*.map.js" "!**/*.png"
121 |
122 | # include .d.ts files but exclude PNG files
123 | clean-modules "**/*.d.ts" "!**/*.png"
124 | ```
125 |
126 | #### Options
127 |
128 | ##### `--directory | -D`
129 |
130 | `string` [default: `./node_modules`]
131 |
132 | Accepts a path to a directory to run the script on.
133 |
134 | **Example**:
135 |
136 | ```bash
137 | clean-modules --directory "path/to/custom/node_modules"
138 | ```
139 |
140 | ##### `--glob-file | -f`
141 |
142 | `string` [default: `./.cleanmodules`]
143 |
144 | Accepts a path to a file from which clean-modules should read any custom globs. See the
145 | [glob patterns](#glob-patterns-and-configuration-file) section for information about how the glob
146 | file works and what patterns work.
147 |
148 | ##### `--no-defaults | -n`
149 |
150 | `boolean`
151 |
152 | Excludes all default globs, using only custom globs added through the
153 | [glob file](#glob-patterns-and-configuration-file) or by the include or exclude options. Useful if
154 | you want complete control over what files to include.
155 |
156 | See the [`.cleanmodules-default`](./cleanmodules-default) to see what patterns are included by
157 | default by default.
158 |
159 | ##### `--keep-empty | -k`
160 |
161 | `boolean`
162 |
163 | Skips removing empty folders after removing files.
164 |
165 | ##### `--dry-run | -d`
166 |
167 | `boolean`
168 |
169 | Runs the script and prints the result without actually removing any files. Does not count the number
170 | of removed empty directories.
171 |
172 | ##### `--json | -j`
173 |
174 | `boolean`
175 |
176 | Only logs a final JSON dump at the end of the script (useful for logs or services).
177 |
178 | ##### `--yes | -y`
179 |
180 | `boolean`
181 |
182 | Skips the confirmation prompt at the start of the script.
183 |
184 | ### `clean-modules analyze` 🔎
185 |
186 | Compiles a list of all files that would be included by `clean-modules` and gives a breakdown of:
187 |
188 | - exact file path
189 | - what glob patterns it was included by
190 | - how the patterns were formatted and passed along to `picomatch`
191 | - if the file was included by default
192 |
193 | #### Usage
194 |
195 | ```bash
196 | clean-modules analyze [options]
197 | ```
198 |
199 | Because of the amount of data it can be useful to pipe it somewhere, like:
200 |
201 | ```bash
202 | clean-modules analyze >> clean-modules-result.json
203 | ```
204 |
205 | #### Positionals
206 |
207 | The `analyze` command accepts the same type of positionals as the [default command]().
208 |
209 | #### Options
210 |
211 | The `analyze` command accepts several of the default command's options and applies them in the same
212 | way:
213 |
214 | - [`--directory`](#directory---d)
215 | - [`--glob-file`](#glob-file---f)
216 | - [`--no-defaults`](#no-defaults---n)
217 |
218 | #### Example output
219 |
220 | ```json
221 | [
222 | {
223 | "filePath": "/Users/me/projects/foo/node_modules/dependency/__tests__/test1.js",
224 | "includedByDefault": true,
225 | "includedByGlobs": [
226 | {
227 | "original": "__tests__/",
228 | "derived": "/Users/me/projects/foo/node_modules/dependency/**/__tests__/**"
229 | }
230 | ]
231 | }
232 | // ...
233 | ]
234 | ```
235 |
236 | ## Glob patterns and configuration file
237 |
238 | clean-modules accepts globs from either a configuration file (`.cleanmodules` next to
239 | `node_modules` by default) or CLI arguments. It uses
240 | [`.gitignore`-like](https://www.atlassian.com/git/tutorials/saving-changes/gitignore) glob patterns
241 | that are converted to valid [`picomatch`](https://github.com/micromatch/picomatch) globs, which is
242 | what is used to match file paths under the hood.
243 |
244 | **Differences from regular gitignore syntax:**
245 |
246 | - To include a directory the pattern _must_ end with `/`, `/*` or `/**`
247 | - This is to prevent directories matching common file names from being included by the globs.
248 | - Casing is ignored.
249 |
250 | **Like with .gitignore, globs should use forward-slashes as separators on all operative systems (including Windows)!**
251 |
252 | ### Example configuration file
253 |
254 | ```ignore
255 | # this is a comment (starts with a #)
256 |
257 | # to include include directories, end patterns with / or /* or /**
258 | dep1/
259 | dep1/*
260 | dep2/**
261 |
262 | # files are matched in any directory by default
263 | **/*.test.js
264 | # is the same as
265 | *.test.js
266 |
267 | # use a leading / to include a file or directory at a specific place
268 | /dep4/this/specific/directory/**
269 | /dep4/this/specific/file.js
270 |
271 | # to exclude a path, prepend it with a !
272 | !/not/this/directory/
273 | !not-me.js
274 |
275 | # to use leading exclamation marks without excluding, escape them
276 | \!(*.d).ts
277 | ```
278 |
279 | ### Default globs
280 |
281 | The default globs can be found in the [`.cleanmodules-default`](./.cleanmodules-default) file. It
282 | only contains inclusions (as exclusions would override custom inclusions) and consists of a large
283 | list of the most common files that are safe to remove.
284 |
285 | That said, it's impossible to guarantee that none of the files are needed, and you might need to do
286 | custom exclusions depending on what packages you use.
287 |
288 | #### Common extra inclusions
289 |
290 | - `**/*.d.ts`: **If you don't use TypeScript.** TypeScript declaration files take up a lot of space
291 | in your `node_modules` folder, but they are most likely required to build your application. Useful
292 | locally even if you don't use TypeScript since they can be parsed by your IDE.
293 |
294 | #### Common extra exclusions
295 |
296 | - `!**/*.map.js`: **If you are running `clean-modules` locally or need source files in production.**
297 | `clean-modules` removes sourcemap files by default since they take up a lot of space and does not
298 | break builds when removed. They can be nice to have though, especially while developing.
299 |
300 | ## Programmatic usage
301 |
302 | Clean modules can be used programmatically too!
303 |
304 | Simply import the corresponding function from the package:
305 |
306 | ````ts
307 | import { clean, analyze } from 'clean-modules';
308 |
309 | // analyze, all options are optional
310 | const analyzeResult = await analyze({
311 | directory: '/path/to/node_modules',
312 | globFile: '/path/to/.cleanmodules',
313 | globs: ['**/*.js'],
314 | noDefaults: false,
315 | });
316 |
317 | // clean, all options are optional
318 | const cleanResult = await clean({
319 | directory: '/path/to/node_modules',
320 | globFile: '/path/to/.cleanmodules',
321 | globs: ['**/*.js'],
322 | noDefaults: false,
323 | keepEmpty: false,
324 | dryRun: false,
325 | });
326 | ````
327 |
328 | ## Alternatives
329 |
330 | The most common issues I found with available tools are:
331 |
332 | - They only allow inclusion/exclusion of file names, not file paths. This prevents you from e.g.
333 | excluding subdirectories of a specific folder, like `@types/react-native`.
334 | - They include too many, or too few, patterns by default. Lots of them also include patterns like
335 | `*.ts` by default, which breaks TypeScript declaration files on build.
336 | - They are too slow (only relevant when running on large projects)
337 | - They are abandoned or don't respond to issues.
338 |
339 | ### Comparisons
340 |
341 | #### clean-modules (this project)
342 |
343 | - ✅ Inclusion/exclusion through file path globs
344 | - ✅ Fast
345 | - ✅ Safe list of files and folders included by default (for production use)
346 | - ✅ Cleans up empty directories
347 |
348 | #### [yarn autoclean](https://classic.yarnpkg.com/en/docs/cli/autoclean/)
349 |
350 | - ✅ Included with Yarn by default
351 | - ✅ Inclusion/exclusion through globs
352 | - ⛔️ Very slow compared to alternatives
353 | - ⛔️ Runs on every install, both locally and in CI
354 | - ⛔️ Small list of files included by default
355 |
356 | #### [modclean](https://github.com/ModClean/modclean)
357 |
358 | - ✅ Cleans up empty directories
359 | - ✅ Safe list of files and folders included by default
360 | - ⛔️ Slow, only slightly faster than `yarn clean`
361 | - ⛔️ Only allows inclusion/exclusion by file name globs, not file path
362 | - ⛔️ Complains about empty folders that doesn't exist
363 | - ⛔️ Abandoned
364 |
365 | #### [node-prune](https://github.com/tj/node-prune)
366 |
367 | - ✅ Fastest option available
368 | - ⛔️ Written in Go and might require separate binary download
369 | - ⛔️ Removes some dangerous files by default (like `.d.ts` files and `assets` folder)
370 | - ⛔️ Only allows inclusion/exclusion by file name globs, not file path
371 | - ⛔️ Globs are very limited since it uses Go's `filepath.Match`
372 | - ⛔️ Does not remove empty folders
373 |
374 | #### [nm-prune](https://github.com/tuananh/node-prune)
375 |
376 | - ✅ Fast
377 | - ⛔️ Removes some dangerous files by default (like `.d.ts` files and `assets` folder)
378 | - ⛔️ Only allows inclusion/exclusion by file name, not file paths or globs
379 | - ⛔️ Does not remove empty folders
380 | - ⛔️ Small list of files included by default
381 |
--------------------------------------------------------------------------------
/__mocks__/fs/index.ts:
--------------------------------------------------------------------------------
1 | import { fs } from 'memfs';
2 |
3 | module.exports = fs;
4 |
--------------------------------------------------------------------------------
/__mocks__/fs/promises.ts:
--------------------------------------------------------------------------------
1 | import { fs } from 'memfs';
2 |
3 | module.exports = fs
4 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 |
3 | // requires built files to avoid resetting file permissions between builds
4 | import '../dist/cli/cli.js';
5 |
--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
3 | "formatter": {
4 | "enabled": false
5 | },
6 | "organizeImports": {
7 | "enabled": false
8 | },
9 | "linter": {
10 | "enabled": true,
11 | "rules": {
12 | "suspicious": {
13 | "noExplicitAny": "off"
14 | },
15 | "style": {
16 | "useTemplate": "off",
17 | "noUnusedTemplateLiteral": "off"
18 | }
19 | }
20 | },
21 | "files": {
22 | "ignore": ["**/*.json"]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/images/dry-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duniul/clean-modules/cb2bb80e188510db7b06d880137ecce346ecf889/images/dry-run.png
--------------------------------------------------------------------------------
/images/large-project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duniul/clean-modules/cb2bb80e188510db7b06d880137ecce346ecf889/images/large-project.png
--------------------------------------------------------------------------------
/images/small-project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duniul/clean-modules/cb2bb80e188510db7b06d880137ecce346ecf889/images/small-project.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clean-modules",
3 | "author": "Daniel Grefberg ",
4 | "version": "3.1.1",
5 | "description": "Clean up/prune unnecessary files and reduce the size of your `node_modules` directory. Useful for CI caches or for reducing the size of serverless functions.",
6 | "repository": "https://github.com/duniul/clean-modules.git",
7 | "homepage": "https://github.com/duniul/clean-modules#readme",
8 | "bugs": {
9 | "url": "https://github.com/duniul/clean-modules/issues"
10 | },
11 | "keywords": [
12 | "node",
13 | "node-modules",
14 | "npm",
15 | "yarn",
16 | "pnpm",
17 | "cli-tool",
18 | "ci"
19 | ],
20 | "license": "ISC",
21 | "engines": {
22 | "node": ">=14"
23 | },
24 | "files": [
25 | "dist",
26 | ".cleanmodules-default",
27 | "!.tsbuildinfo"
28 | ],
29 | "packageManager": "pnpm@9.11.0",
30 | "type": "module",
31 | "exports": {
32 | ".": {
33 | "import": {
34 | "types": "./dist/index.d.ts",
35 | "default": "./dist/index.js"
36 | },
37 | "require": {
38 | "types": "./dist/index.d.cts",
39 | "default": "./dist/index.cjs"
40 | }
41 | }
42 | },
43 | "main": "dist/index.cjs",
44 | "module": "dist/index.js",
45 | "types": "dist/index.d.ts",
46 | "bin": "bin/cli.js",
47 | "scripts": {
48 | "cli": "tsx src/cli/cli.ts",
49 | "build": "tsup",
50 | "dev": "tsc --watch",
51 | "test": "vitest",
52 | "prepublishOnly": "pnpm build",
53 | "lint": "biome check src && prettier --check src",
54 | "lint:fix": "biome check --apply src && prettier --write src",
55 | "version": "changeset version",
56 | "release": "changeset publish"
57 | },
58 | "dependencies": {
59 | "clipanion": "^3.2.1",
60 | "picomatch": "^2.3.0",
61 | "pretty-bytes": "^6.1.0",
62 | "pretty-ms": "^8.0.0",
63 | "supports-color": "^9.4.0"
64 | },
65 | "devDependencies": {
66 | "@biomejs/biome": "^1.9.2",
67 | "@changesets/cli": "^2.27.8",
68 | "@tsconfig/node14": "^14.1.2",
69 | "@types/mock-fs": "4.13.4",
70 | "@types/node": "16",
71 | "@types/picomatch": "2.3.4",
72 | "@types/supports-color": "8.1.3",
73 | "changesets-changelog-clean": "^1.3.0",
74 | "memfs": "^4.12.0",
75 | "prettier": "3.3.3",
76 | "prettier-plugin-organize-imports": "4.1.0",
77 | "tslib": "^2.7.0",
78 | "tsup": "^8.3.0",
79 | "tsx": "^4.19.1",
80 | "typescript": "5.6.2",
81 | "vitest": "^2.1.1"
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | clipanion:
12 | specifier: ^3.2.1
13 | version: 3.2.1(typanion@3.14.0)
14 | picomatch:
15 | specifier: ^2.3.0
16 | version: 2.3.1
17 | pretty-bytes:
18 | specifier: ^6.1.0
19 | version: 6.1.1
20 | pretty-ms:
21 | specifier: ^8.0.0
22 | version: 8.0.0
23 | supports-color:
24 | specifier: ^9.4.0
25 | version: 9.4.0
26 | devDependencies:
27 | '@biomejs/biome':
28 | specifier: ^1.9.2
29 | version: 1.9.2
30 | '@changesets/cli':
31 | specifier: ^2.27.8
32 | version: 2.27.8
33 | '@tsconfig/node14':
34 | specifier: ^14.1.2
35 | version: 14.1.2
36 | '@types/mock-fs':
37 | specifier: 4.13.4
38 | version: 4.13.4
39 | '@types/node':
40 | specifier: '16'
41 | version: 16.18.82
42 | '@types/picomatch':
43 | specifier: 2.3.4
44 | version: 2.3.4
45 | '@types/supports-color':
46 | specifier: 8.1.3
47 | version: 8.1.3
48 | changesets-changelog-clean:
49 | specifier: ^1.3.0
50 | version: 1.3.0
51 | memfs:
52 | specifier: ^4.12.0
53 | version: 4.12.0
54 | prettier:
55 | specifier: 3.3.3
56 | version: 3.3.3
57 | prettier-plugin-organize-imports:
58 | specifier: 4.1.0
59 | version: 4.1.0(prettier@3.3.3)(typescript@5.6.2)
60 | tslib:
61 | specifier: ^2.7.0
62 | version: 2.7.0
63 | tsup:
64 | specifier: ^8.3.0
65 | version: 8.3.0(postcss@8.4.35)(supports-color@9.4.0)(tsx@4.19.1)(typescript@5.6.2)
66 | tsx:
67 | specifier: ^4.19.1
68 | version: 4.19.1
69 | typescript:
70 | specifier: 5.6.2
71 | version: 5.6.2
72 | vitest:
73 | specifier: ^2.1.1
74 | version: 2.1.1(@types/node@16.18.82)(supports-color@9.4.0)
75 |
76 | packages:
77 |
78 | '@babel/runtime@7.23.9':
79 | resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==}
80 | engines: {node: '>=6.9.0'}
81 |
82 | '@biomejs/biome@1.9.2':
83 | resolution: {integrity: sha512-4j2Gfwft8Jqp1X0qLYvK4TEy4xhTo4o6rlvJPsjPeEame8gsmbGQfOPBkw7ur+7/Z/f0HZmCZKqbMvR7vTXQYQ==}
84 | engines: {node: '>=14.21.3'}
85 | hasBin: true
86 |
87 | '@biomejs/cli-darwin-arm64@1.9.2':
88 | resolution: {integrity: sha512-rbs9uJHFmhqB3Td0Ro+1wmeZOHhAPTL3WHr8NtaVczUmDhXkRDWScaxicG9+vhSLj1iLrW47itiK6xiIJy6vaA==}
89 | engines: {node: '>=14.21.3'}
90 | cpu: [arm64]
91 | os: [darwin]
92 |
93 | '@biomejs/cli-darwin-x64@1.9.2':
94 | resolution: {integrity: sha512-BlfULKijNaMigQ9GH9fqJVt+3JTDOSiZeWOQtG/1S1sa8Lp046JHG3wRJVOvekTPL9q/CNFW1NVG8J0JN+L1OA==}
95 | engines: {node: '>=14.21.3'}
96 | cpu: [x64]
97 | os: [darwin]
98 |
99 | '@biomejs/cli-linux-arm64-musl@1.9.2':
100 | resolution: {integrity: sha512-ZATvbUWhNxegSALUnCKWqetTZqrK72r2RsFD19OK5jXDj/7o1hzI1KzDNG78LloZxftrwr3uI9SqCLh06shSZw==}
101 | engines: {node: '>=14.21.3'}
102 | cpu: [arm64]
103 | os: [linux]
104 |
105 | '@biomejs/cli-linux-arm64@1.9.2':
106 | resolution: {integrity: sha512-T8TJuSxuBDeQCQzxZu2o3OU4eyLumTofhCxxFd3+aH2AEWVMnH7Z/c3QP1lHI5RRMBP9xIJeMORqDQ5j+gVZzw==}
107 | engines: {node: '>=14.21.3'}
108 | cpu: [arm64]
109 | os: [linux]
110 |
111 | '@biomejs/cli-linux-x64-musl@1.9.2':
112 | resolution: {integrity: sha512-CjPM6jT1miV5pry9C7qv8YJk0FIZvZd86QRD3atvDgfgeh9WQU0k2Aoo0xUcPdTnoz0WNwRtDicHxwik63MmSg==}
113 | engines: {node: '>=14.21.3'}
114 | cpu: [x64]
115 | os: [linux]
116 |
117 | '@biomejs/cli-linux-x64@1.9.2':
118 | resolution: {integrity: sha512-T0cPk3C3Jr2pVlsuQVTBqk2qPjTm8cYcTD9p/wmR9MeVqui1C/xTVfOIwd3miRODFMrJaVQ8MYSXnVIhV9jTjg==}
119 | engines: {node: '>=14.21.3'}
120 | cpu: [x64]
121 | os: [linux]
122 |
123 | '@biomejs/cli-win32-arm64@1.9.2':
124 | resolution: {integrity: sha512-2x7gSty75bNIeD23ZRPXyox6Z/V0M71ObeJtvQBhi1fgrvPdtkEuw7/0wEHg6buNCubzOFuN9WYJm6FKoUHfhg==}
125 | engines: {node: '>=14.21.3'}
126 | cpu: [arm64]
127 | os: [win32]
128 |
129 | '@biomejs/cli-win32-x64@1.9.2':
130 | resolution: {integrity: sha512-JC3XvdYcjmu1FmAehVwVV0SebLpeNTnO2ZaMdGCSOdS7f8O9Fq14T2P1gTG1Q29Q8Dt1S03hh0IdVpIZykOL8g==}
131 | engines: {node: '>=14.21.3'}
132 | cpu: [x64]
133 | os: [win32]
134 |
135 | '@changesets/apply-release-plan@7.0.5':
136 | resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==}
137 |
138 | '@changesets/assemble-release-plan@6.0.4':
139 | resolution: {integrity: sha512-nqICnvmrwWj4w2x0fOhVj2QEGdlUuwVAwESrUo5HLzWMI1rE5SWfsr9ln+rDqWB6RQ2ZyaMZHUcU7/IRaUJS+Q==}
140 |
141 | '@changesets/changelog-git@0.2.0':
142 | resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==}
143 |
144 | '@changesets/cli@2.27.8':
145 | resolution: {integrity: sha512-gZNyh+LdSsI82wBSHLQ3QN5J30P4uHKJ4fXgoGwQxfXwYFTJzDdvIJasZn8rYQtmKhyQuiBj4SSnLuKlxKWq4w==}
146 | hasBin: true
147 |
148 | '@changesets/config@3.0.3':
149 | resolution: {integrity: sha512-vqgQZMyIcuIpw9nqFIpTSNyc/wgm/Lu1zKN5vECy74u95Qx/Wa9g27HdgO4NkVAaq+BGA8wUc/qvbvVNs93n6A==}
150 |
151 | '@changesets/errors@0.2.0':
152 | resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==}
153 |
154 | '@changesets/get-dependents-graph@2.1.2':
155 | resolution: {integrity: sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==}
156 |
157 | '@changesets/get-github-info@0.6.0':
158 | resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==}
159 |
160 | '@changesets/get-release-plan@4.0.4':
161 | resolution: {integrity: sha512-SicG/S67JmPTrdcc9Vpu0wSQt7IiuN0dc8iR5VScnnTVPfIaLvKmEGRvIaF0kcn8u5ZqLbormZNTO77bCEvyWw==}
162 |
163 | '@changesets/get-version-range-type@0.4.0':
164 | resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==}
165 |
166 | '@changesets/git@3.0.1':
167 | resolution: {integrity: sha512-pdgHcYBLCPcLd82aRcuO0kxCDbw/yISlOtkmwmE8Odo1L6hSiZrBOsRl84eYG7DRCab/iHnOkWqExqc4wxk2LQ==}
168 |
169 | '@changesets/logger@0.1.1':
170 | resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==}
171 |
172 | '@changesets/parse@0.4.0':
173 | resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==}
174 |
175 | '@changesets/pre@2.0.1':
176 | resolution: {integrity: sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==}
177 |
178 | '@changesets/read@0.6.1':
179 | resolution: {integrity: sha512-jYMbyXQk3nwP25nRzQQGa1nKLY0KfoOV7VLgwucI0bUO8t8ZLCr6LZmgjXsiKuRDc+5A6doKPr9w2d+FEJ55zQ==}
180 |
181 | '@changesets/should-skip-package@0.1.1':
182 | resolution: {integrity: sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==}
183 |
184 | '@changesets/types@4.1.0':
185 | resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==}
186 |
187 | '@changesets/types@6.0.0':
188 | resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==}
189 |
190 | '@changesets/write@0.3.2':
191 | resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==}
192 |
193 | '@esbuild/aix-ppc64@0.19.12':
194 | resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
195 | engines: {node: '>=12'}
196 | cpu: [ppc64]
197 | os: [aix]
198 |
199 | '@esbuild/aix-ppc64@0.23.1':
200 | resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
201 | engines: {node: '>=18'}
202 | cpu: [ppc64]
203 | os: [aix]
204 |
205 | '@esbuild/android-arm64@0.19.12':
206 | resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
207 | engines: {node: '>=12'}
208 | cpu: [arm64]
209 | os: [android]
210 |
211 | '@esbuild/android-arm64@0.23.1':
212 | resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
213 | engines: {node: '>=18'}
214 | cpu: [arm64]
215 | os: [android]
216 |
217 | '@esbuild/android-arm@0.19.12':
218 | resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
219 | engines: {node: '>=12'}
220 | cpu: [arm]
221 | os: [android]
222 |
223 | '@esbuild/android-arm@0.23.1':
224 | resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
225 | engines: {node: '>=18'}
226 | cpu: [arm]
227 | os: [android]
228 |
229 | '@esbuild/android-x64@0.19.12':
230 | resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
231 | engines: {node: '>=12'}
232 | cpu: [x64]
233 | os: [android]
234 |
235 | '@esbuild/android-x64@0.23.1':
236 | resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
237 | engines: {node: '>=18'}
238 | cpu: [x64]
239 | os: [android]
240 |
241 | '@esbuild/darwin-arm64@0.19.12':
242 | resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
243 | engines: {node: '>=12'}
244 | cpu: [arm64]
245 | os: [darwin]
246 |
247 | '@esbuild/darwin-arm64@0.23.1':
248 | resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
249 | engines: {node: '>=18'}
250 | cpu: [arm64]
251 | os: [darwin]
252 |
253 | '@esbuild/darwin-x64@0.19.12':
254 | resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
255 | engines: {node: '>=12'}
256 | cpu: [x64]
257 | os: [darwin]
258 |
259 | '@esbuild/darwin-x64@0.23.1':
260 | resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
261 | engines: {node: '>=18'}
262 | cpu: [x64]
263 | os: [darwin]
264 |
265 | '@esbuild/freebsd-arm64@0.19.12':
266 | resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
267 | engines: {node: '>=12'}
268 | cpu: [arm64]
269 | os: [freebsd]
270 |
271 | '@esbuild/freebsd-arm64@0.23.1':
272 | resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
273 | engines: {node: '>=18'}
274 | cpu: [arm64]
275 | os: [freebsd]
276 |
277 | '@esbuild/freebsd-x64@0.19.12':
278 | resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
279 | engines: {node: '>=12'}
280 | cpu: [x64]
281 | os: [freebsd]
282 |
283 | '@esbuild/freebsd-x64@0.23.1':
284 | resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
285 | engines: {node: '>=18'}
286 | cpu: [x64]
287 | os: [freebsd]
288 |
289 | '@esbuild/linux-arm64@0.19.12':
290 | resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
291 | engines: {node: '>=12'}
292 | cpu: [arm64]
293 | os: [linux]
294 |
295 | '@esbuild/linux-arm64@0.23.1':
296 | resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
297 | engines: {node: '>=18'}
298 | cpu: [arm64]
299 | os: [linux]
300 |
301 | '@esbuild/linux-arm@0.19.12':
302 | resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
303 | engines: {node: '>=12'}
304 | cpu: [arm]
305 | os: [linux]
306 |
307 | '@esbuild/linux-arm@0.23.1':
308 | resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
309 | engines: {node: '>=18'}
310 | cpu: [arm]
311 | os: [linux]
312 |
313 | '@esbuild/linux-ia32@0.19.12':
314 | resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
315 | engines: {node: '>=12'}
316 | cpu: [ia32]
317 | os: [linux]
318 |
319 | '@esbuild/linux-ia32@0.23.1':
320 | resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
321 | engines: {node: '>=18'}
322 | cpu: [ia32]
323 | os: [linux]
324 |
325 | '@esbuild/linux-loong64@0.19.12':
326 | resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
327 | engines: {node: '>=12'}
328 | cpu: [loong64]
329 | os: [linux]
330 |
331 | '@esbuild/linux-loong64@0.23.1':
332 | resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
333 | engines: {node: '>=18'}
334 | cpu: [loong64]
335 | os: [linux]
336 |
337 | '@esbuild/linux-mips64el@0.19.12':
338 | resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
339 | engines: {node: '>=12'}
340 | cpu: [mips64el]
341 | os: [linux]
342 |
343 | '@esbuild/linux-mips64el@0.23.1':
344 | resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
345 | engines: {node: '>=18'}
346 | cpu: [mips64el]
347 | os: [linux]
348 |
349 | '@esbuild/linux-ppc64@0.19.12':
350 | resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
351 | engines: {node: '>=12'}
352 | cpu: [ppc64]
353 | os: [linux]
354 |
355 | '@esbuild/linux-ppc64@0.23.1':
356 | resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
357 | engines: {node: '>=18'}
358 | cpu: [ppc64]
359 | os: [linux]
360 |
361 | '@esbuild/linux-riscv64@0.19.12':
362 | resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
363 | engines: {node: '>=12'}
364 | cpu: [riscv64]
365 | os: [linux]
366 |
367 | '@esbuild/linux-riscv64@0.23.1':
368 | resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
369 | engines: {node: '>=18'}
370 | cpu: [riscv64]
371 | os: [linux]
372 |
373 | '@esbuild/linux-s390x@0.19.12':
374 | resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
375 | engines: {node: '>=12'}
376 | cpu: [s390x]
377 | os: [linux]
378 |
379 | '@esbuild/linux-s390x@0.23.1':
380 | resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
381 | engines: {node: '>=18'}
382 | cpu: [s390x]
383 | os: [linux]
384 |
385 | '@esbuild/linux-x64@0.19.12':
386 | resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
387 | engines: {node: '>=12'}
388 | cpu: [x64]
389 | os: [linux]
390 |
391 | '@esbuild/linux-x64@0.23.1':
392 | resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
393 | engines: {node: '>=18'}
394 | cpu: [x64]
395 | os: [linux]
396 |
397 | '@esbuild/netbsd-x64@0.19.12':
398 | resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
399 | engines: {node: '>=12'}
400 | cpu: [x64]
401 | os: [netbsd]
402 |
403 | '@esbuild/netbsd-x64@0.23.1':
404 | resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
405 | engines: {node: '>=18'}
406 | cpu: [x64]
407 | os: [netbsd]
408 |
409 | '@esbuild/openbsd-arm64@0.23.1':
410 | resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
411 | engines: {node: '>=18'}
412 | cpu: [arm64]
413 | os: [openbsd]
414 |
415 | '@esbuild/openbsd-x64@0.19.12':
416 | resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
417 | engines: {node: '>=12'}
418 | cpu: [x64]
419 | os: [openbsd]
420 |
421 | '@esbuild/openbsd-x64@0.23.1':
422 | resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
423 | engines: {node: '>=18'}
424 | cpu: [x64]
425 | os: [openbsd]
426 |
427 | '@esbuild/sunos-x64@0.19.12':
428 | resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
429 | engines: {node: '>=12'}
430 | cpu: [x64]
431 | os: [sunos]
432 |
433 | '@esbuild/sunos-x64@0.23.1':
434 | resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
435 | engines: {node: '>=18'}
436 | cpu: [x64]
437 | os: [sunos]
438 |
439 | '@esbuild/win32-arm64@0.19.12':
440 | resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
441 | engines: {node: '>=12'}
442 | cpu: [arm64]
443 | os: [win32]
444 |
445 | '@esbuild/win32-arm64@0.23.1':
446 | resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
447 | engines: {node: '>=18'}
448 | cpu: [arm64]
449 | os: [win32]
450 |
451 | '@esbuild/win32-ia32@0.19.12':
452 | resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
453 | engines: {node: '>=12'}
454 | cpu: [ia32]
455 | os: [win32]
456 |
457 | '@esbuild/win32-ia32@0.23.1':
458 | resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
459 | engines: {node: '>=18'}
460 | cpu: [ia32]
461 | os: [win32]
462 |
463 | '@esbuild/win32-x64@0.19.12':
464 | resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
465 | engines: {node: '>=12'}
466 | cpu: [x64]
467 | os: [win32]
468 |
469 | '@esbuild/win32-x64@0.23.1':
470 | resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
471 | engines: {node: '>=18'}
472 | cpu: [x64]
473 | os: [win32]
474 |
475 | '@isaacs/cliui@8.0.2':
476 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
477 | engines: {node: '>=12'}
478 |
479 | '@jridgewell/gen-mapping@0.3.3':
480 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
481 | engines: {node: '>=6.0.0'}
482 |
483 | '@jridgewell/resolve-uri@3.1.2':
484 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
485 | engines: {node: '>=6.0.0'}
486 |
487 | '@jridgewell/set-array@1.1.2':
488 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
489 | engines: {node: '>=6.0.0'}
490 |
491 | '@jridgewell/sourcemap-codec@1.4.15':
492 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
493 |
494 | '@jridgewell/sourcemap-codec@1.5.0':
495 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
496 |
497 | '@jridgewell/trace-mapping@0.3.22':
498 | resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==}
499 |
500 | '@jsonjoy.com/base64@1.1.2':
501 | resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==}
502 | engines: {node: '>=10.0'}
503 | peerDependencies:
504 | tslib: '2'
505 |
506 | '@jsonjoy.com/json-pack@1.1.0':
507 | resolution: {integrity: sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==}
508 | engines: {node: '>=10.0'}
509 | peerDependencies:
510 | tslib: '2'
511 |
512 | '@jsonjoy.com/util@1.3.0':
513 | resolution: {integrity: sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==}
514 | engines: {node: '>=10.0'}
515 | peerDependencies:
516 | tslib: '2'
517 |
518 | '@manypkg/find-root@1.1.0':
519 | resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
520 |
521 | '@manypkg/get-packages@1.1.3':
522 | resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==}
523 |
524 | '@nodelib/fs.scandir@2.1.5':
525 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
526 | engines: {node: '>= 8'}
527 |
528 | '@nodelib/fs.stat@2.0.5':
529 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
530 | engines: {node: '>= 8'}
531 |
532 | '@nodelib/fs.walk@1.2.8':
533 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
534 | engines: {node: '>= 8'}
535 |
536 | '@pkgjs/parseargs@0.11.0':
537 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
538 | engines: {node: '>=14'}
539 |
540 | '@rollup/rollup-android-arm-eabi@4.23.0':
541 | resolution: {integrity: sha512-8OR+Ok3SGEMsAZispLx8jruuXw0HVF16k+ub2eNXKHDmdxL4cf9NlNpAzhlOhNyXzKDEJuFeq0nZm+XlNb1IFw==}
542 | cpu: [arm]
543 | os: [android]
544 |
545 | '@rollup/rollup-android-arm64@4.23.0':
546 | resolution: {integrity: sha512-rEFtX1nP8gqmLmPZsXRMoLVNB5JBwOzIAk/XAcEPuKrPa2nPJ+DuGGpfQUR0XjRm8KjHfTZLpWbKXkA5BoFL3w==}
547 | cpu: [arm64]
548 | os: [android]
549 |
550 | '@rollup/rollup-darwin-arm64@4.23.0':
551 | resolution: {integrity: sha512-ZbqlMkJRMMPeapfaU4drYHns7Q5MIxjM/QeOO62qQZGPh9XWziap+NF9fsqPHT0KzEL6HaPspC7sOwpgyA3J9g==}
552 | cpu: [arm64]
553 | os: [darwin]
554 |
555 | '@rollup/rollup-darwin-x64@4.23.0':
556 | resolution: {integrity: sha512-PfmgQp78xx5rBCgn2oYPQ1rQTtOaQCna0kRaBlc5w7RlA3TDGGo7m3XaptgitUZ54US9915i7KeVPHoy3/W8tA==}
557 | cpu: [x64]
558 | os: [darwin]
559 |
560 | '@rollup/rollup-linux-arm-gnueabihf@4.23.0':
561 | resolution: {integrity: sha512-WAeZfAAPus56eQgBioezXRRzArAjWJGjNo/M+BHZygUcs9EePIuGI1Wfc6U/Ki+tMW17FFGvhCfYnfcKPh18SA==}
562 | cpu: [arm]
563 | os: [linux]
564 |
565 | '@rollup/rollup-linux-arm-musleabihf@4.23.0':
566 | resolution: {integrity: sha512-v7PGcp1O5XKZxKX8phTXtmJDVpE20Ub1eF6w9iMmI3qrrPak6yR9/5eeq7ziLMrMTjppkkskXyxnmm00HdtXjA==}
567 | cpu: [arm]
568 | os: [linux]
569 |
570 | '@rollup/rollup-linux-arm64-gnu@4.23.0':
571 | resolution: {integrity: sha512-nAbWsDZ9UkU6xQiXEyXBNHAKbzSAi95H3gTStJq9UGiS1v+YVXwRHcQOQEF/3CHuhX5BVhShKoeOf6Q/1M+Zhg==}
572 | cpu: [arm64]
573 | os: [linux]
574 |
575 | '@rollup/rollup-linux-arm64-musl@4.23.0':
576 | resolution: {integrity: sha512-5QT/Di5FbGNPaVw8hHO1wETunwkPuZBIu6W+5GNArlKHD9fkMHy7vS8zGHJk38oObXfWdsuLMogD4sBySLJ54g==}
577 | cpu: [arm64]
578 | os: [linux]
579 |
580 | '@rollup/rollup-linux-powerpc64le-gnu@4.23.0':
581 | resolution: {integrity: sha512-Sefl6vPyn5axzCsO13r1sHLcmPuiSOrKIImnq34CBurntcJ+lkQgAaTt/9JkgGmaZJ+OkaHmAJl4Bfd0DmdtOQ==}
582 | cpu: [ppc64]
583 | os: [linux]
584 |
585 | '@rollup/rollup-linux-riscv64-gnu@4.23.0':
586 | resolution: {integrity: sha512-o4QI2KU/QbP7ZExMse6ULotdV3oJUYMrdx3rBZCgUF3ur3gJPfe8Fuasn6tia16c5kZBBw0aTmaUygad6VB/hQ==}
587 | cpu: [riscv64]
588 | os: [linux]
589 |
590 | '@rollup/rollup-linux-s390x-gnu@4.23.0':
591 | resolution: {integrity: sha512-+bxqx+V/D4FGrpXzPGKp/SEZIZ8cIW3K7wOtcJAoCrmXvzRtmdUhYNbgd+RztLzfDEfA2WtKj5F4tcbNPuqgeg==}
592 | cpu: [s390x]
593 | os: [linux]
594 |
595 | '@rollup/rollup-linux-x64-gnu@4.23.0':
596 | resolution: {integrity: sha512-I/eXsdVoCKtSgK9OwyQKPAfricWKUMNCwJKtatRYMmDo5N859tbO3UsBw5kT3dU1n6ZcM1JDzPRSGhAUkxfLxw==}
597 | cpu: [x64]
598 | os: [linux]
599 |
600 | '@rollup/rollup-linux-x64-musl@4.23.0':
601 | resolution: {integrity: sha512-4ZoDZy5ShLbbe1KPSafbFh1vbl0asTVfkABC7eWqIs01+66ncM82YJxV2VtV3YVJTqq2P8HMx3DCoRSWB/N3rw==}
602 | cpu: [x64]
603 | os: [linux]
604 |
605 | '@rollup/rollup-win32-arm64-msvc@4.23.0':
606 | resolution: {integrity: sha512-+5Ky8dhft4STaOEbZu3/NU4QIyYssKO+r1cD3FzuusA0vO5gso15on7qGzKdNXnc1gOrsgCqZjRw1w+zL4y4hQ==}
607 | cpu: [arm64]
608 | os: [win32]
609 |
610 | '@rollup/rollup-win32-ia32-msvc@4.23.0':
611 | resolution: {integrity: sha512-0SPJk4cPZQhq9qA1UhIRumSE3+JJIBBjtlGl5PNC///BoaByckNZd53rOYD0glpTkYFBQSt7AkMeLVPfx65+BQ==}
612 | cpu: [ia32]
613 | os: [win32]
614 |
615 | '@rollup/rollup-win32-x64-msvc@4.23.0':
616 | resolution: {integrity: sha512-lqCK5GQC8fNo0+JvTSxcG7YB1UKYp8yrNLhsArlvPWN+16ovSZgoehlVHg6X0sSWPUkpjRBR5TuR12ZugowZ4g==}
617 | cpu: [x64]
618 | os: [win32]
619 |
620 | '@tsconfig/node14@14.1.2':
621 | resolution: {integrity: sha512-1vncsbfCZ3TBLPxesRYz02Rn7SNJfbLoDVkcZ7F/ixOV6nwxwgdhD1mdPcc5YQ413qBJ8CvMxXMFfJ7oawjo7Q==}
622 |
623 | '@types/estree@1.0.6':
624 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
625 |
626 | '@types/mock-fs@4.13.4':
627 | resolution: {integrity: sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==}
628 |
629 | '@types/node@12.20.55':
630 | resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
631 |
632 | '@types/node@16.18.82':
633 | resolution: {integrity: sha512-pcDZtkx9z8XYV+ius2P3Ot2VVrcYOfXffBQUBuiszrlUzKSmoDYqo+mV+IoL8iIiIjjtOMvNSmH1hwJ+Q+f96Q==}
634 |
635 | '@types/picomatch@2.3.4':
636 | resolution: {integrity: sha512-0so8lU8O5zatZS/2Fi4zrwks+vZv7e0dygrgEZXljODXBig97l4cPQD+9LabXfGJOWwoRkTVz6Q4edZvD12UOA==}
637 |
638 | '@types/semver@7.5.7':
639 | resolution: {integrity: sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==}
640 |
641 | '@types/supports-color@8.1.3':
642 | resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==}
643 |
644 | '@vitest/expect@2.1.1':
645 | resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==}
646 |
647 | '@vitest/mocker@2.1.1':
648 | resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==}
649 | peerDependencies:
650 | '@vitest/spy': 2.1.1
651 | msw: ^2.3.5
652 | vite: ^5.0.0
653 | peerDependenciesMeta:
654 | msw:
655 | optional: true
656 | vite:
657 | optional: true
658 |
659 | '@vitest/pretty-format@2.1.1':
660 | resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==}
661 |
662 | '@vitest/runner@2.1.1':
663 | resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==}
664 |
665 | '@vitest/snapshot@2.1.1':
666 | resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==}
667 |
668 | '@vitest/spy@2.1.1':
669 | resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==}
670 |
671 | '@vitest/utils@2.1.1':
672 | resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==}
673 |
674 | ansi-colors@4.1.3:
675 | resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
676 | engines: {node: '>=6'}
677 |
678 | ansi-regex@5.0.1:
679 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
680 | engines: {node: '>=8'}
681 |
682 | ansi-regex@6.0.1:
683 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
684 | engines: {node: '>=12'}
685 |
686 | ansi-styles@4.3.0:
687 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
688 | engines: {node: '>=8'}
689 |
690 | ansi-styles@6.2.1:
691 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
692 | engines: {node: '>=12'}
693 |
694 | any-promise@1.3.0:
695 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
696 |
697 | anymatch@3.1.3:
698 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
699 | engines: {node: '>= 8'}
700 |
701 | argparse@1.0.10:
702 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
703 |
704 | array-union@2.1.0:
705 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
706 | engines: {node: '>=8'}
707 |
708 | assertion-error@2.0.1:
709 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
710 | engines: {node: '>=12'}
711 |
712 | balanced-match@1.0.2:
713 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
714 |
715 | better-path-resolve@1.0.0:
716 | resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
717 | engines: {node: '>=4'}
718 |
719 | binary-extensions@2.2.0:
720 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
721 | engines: {node: '>=8'}
722 |
723 | brace-expansion@2.0.1:
724 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
725 |
726 | braces@3.0.2:
727 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
728 | engines: {node: '>=8'}
729 |
730 | bundle-require@5.0.0:
731 | resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==}
732 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
733 | peerDependencies:
734 | esbuild: '>=0.18'
735 |
736 | cac@6.7.14:
737 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
738 | engines: {node: '>=8'}
739 |
740 | chai@5.1.1:
741 | resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==}
742 | engines: {node: '>=12'}
743 |
744 | changesets-changelog-clean@1.3.0:
745 | resolution: {integrity: sha512-3bGEYg+SuzS4TizAVwGxkiV+c/IMQI7+JPnrEApbvGeb5//c2cfcLG9pteNqpySVY6BNkpCFMM4dpZucnCPxtQ==}
746 |
747 | chardet@0.7.0:
748 | resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
749 |
750 | check-error@2.1.1:
751 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
752 | engines: {node: '>= 16'}
753 |
754 | chokidar@3.6.0:
755 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
756 | engines: {node: '>= 8.10.0'}
757 |
758 | ci-info@3.9.0:
759 | resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
760 | engines: {node: '>=8'}
761 |
762 | clipanion@3.2.1:
763 | resolution: {integrity: sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==}
764 | peerDependencies:
765 | typanion: '*'
766 |
767 | color-convert@2.0.1:
768 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
769 | engines: {node: '>=7.0.0'}
770 |
771 | color-name@1.1.4:
772 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
773 |
774 | commander@4.1.1:
775 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
776 | engines: {node: '>= 6'}
777 |
778 | consola@3.2.3:
779 | resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
780 | engines: {node: ^14.18.0 || >=16.10.0}
781 |
782 | cross-spawn@5.1.0:
783 | resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
784 |
785 | cross-spawn@7.0.3:
786 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
787 | engines: {node: '>= 8'}
788 |
789 | dataloader@1.4.0:
790 | resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
791 |
792 | debug@4.3.7:
793 | resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
794 | engines: {node: '>=6.0'}
795 | peerDependencies:
796 | supports-color: '*'
797 | peerDependenciesMeta:
798 | supports-color:
799 | optional: true
800 |
801 | deep-eql@5.0.2:
802 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
803 | engines: {node: '>=6'}
804 |
805 | detect-indent@6.1.0:
806 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
807 | engines: {node: '>=8'}
808 |
809 | dir-glob@3.0.1:
810 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
811 | engines: {node: '>=8'}
812 |
813 | eastasianwidth@0.2.0:
814 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
815 |
816 | emoji-regex@8.0.0:
817 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
818 |
819 | emoji-regex@9.2.2:
820 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
821 |
822 | enquirer@2.4.1:
823 | resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
824 | engines: {node: '>=8.6'}
825 |
826 | esbuild@0.19.12:
827 | resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
828 | engines: {node: '>=12'}
829 | hasBin: true
830 |
831 | esbuild@0.23.1:
832 | resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
833 | engines: {node: '>=18'}
834 | hasBin: true
835 |
836 | esprima@4.0.1:
837 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
838 | engines: {node: '>=4'}
839 | hasBin: true
840 |
841 | estree-walker@3.0.3:
842 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
843 |
844 | execa@5.1.1:
845 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
846 | engines: {node: '>=10'}
847 |
848 | extendable-error@0.1.7:
849 | resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==}
850 |
851 | external-editor@3.1.0:
852 | resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
853 | engines: {node: '>=4'}
854 |
855 | fast-glob@3.3.2:
856 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
857 | engines: {node: '>=8.6.0'}
858 |
859 | fastq@1.17.1:
860 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
861 |
862 | fdir@6.4.0:
863 | resolution: {integrity: sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==}
864 | peerDependencies:
865 | picomatch: ^3 || ^4
866 | peerDependenciesMeta:
867 | picomatch:
868 | optional: true
869 |
870 | fill-range@7.0.1:
871 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
872 | engines: {node: '>=8'}
873 |
874 | find-up@4.1.0:
875 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
876 | engines: {node: '>=8'}
877 |
878 | foreground-child@3.1.1:
879 | resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
880 | engines: {node: '>=14'}
881 |
882 | fs-extra@7.0.1:
883 | resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
884 | engines: {node: '>=6 <7 || >=8'}
885 |
886 | fs-extra@8.1.0:
887 | resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
888 | engines: {node: '>=6 <7 || >=8'}
889 |
890 | fsevents@2.3.3:
891 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
892 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
893 | os: [darwin]
894 |
895 | get-func-name@2.0.2:
896 | resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
897 |
898 | get-stream@6.0.1:
899 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
900 | engines: {node: '>=10'}
901 |
902 | get-tsconfig@4.8.1:
903 | resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==}
904 |
905 | glob-parent@5.1.2:
906 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
907 | engines: {node: '>= 6'}
908 |
909 | glob@10.3.10:
910 | resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
911 | engines: {node: '>=16 || 14 >=14.17'}
912 | hasBin: true
913 |
914 | globby@11.1.0:
915 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
916 | engines: {node: '>=10'}
917 |
918 | graceful-fs@4.2.11:
919 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
920 |
921 | human-id@1.0.2:
922 | resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==}
923 |
924 | human-signals@2.1.0:
925 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
926 | engines: {node: '>=10.17.0'}
927 |
928 | hyperdyperid@1.2.0:
929 | resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==}
930 | engines: {node: '>=10.18'}
931 |
932 | iconv-lite@0.4.24:
933 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
934 | engines: {node: '>=0.10.0'}
935 |
936 | ignore@5.3.1:
937 | resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
938 | engines: {node: '>= 4'}
939 |
940 | is-binary-path@2.1.0:
941 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
942 | engines: {node: '>=8'}
943 |
944 | is-extglob@2.1.1:
945 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
946 | engines: {node: '>=0.10.0'}
947 |
948 | is-fullwidth-code-point@3.0.0:
949 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
950 | engines: {node: '>=8'}
951 |
952 | is-glob@4.0.3:
953 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
954 | engines: {node: '>=0.10.0'}
955 |
956 | is-number@7.0.0:
957 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
958 | engines: {node: '>=0.12.0'}
959 |
960 | is-stream@2.0.1:
961 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
962 | engines: {node: '>=8'}
963 |
964 | is-subdir@1.2.0:
965 | resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==}
966 | engines: {node: '>=4'}
967 |
968 | is-windows@1.0.2:
969 | resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
970 | engines: {node: '>=0.10.0'}
971 |
972 | isexe@2.0.0:
973 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
974 |
975 | jackspeak@2.3.6:
976 | resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
977 | engines: {node: '>=14'}
978 |
979 | joycon@3.1.1:
980 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
981 | engines: {node: '>=10'}
982 |
983 | js-yaml@3.14.1:
984 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
985 | hasBin: true
986 |
987 | jsonfile@4.0.0:
988 | resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
989 |
990 | lilconfig@3.1.2:
991 | resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
992 | engines: {node: '>=14'}
993 |
994 | lines-and-columns@1.2.4:
995 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
996 |
997 | load-tsconfig@0.2.5:
998 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
999 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
1000 |
1001 | locate-path@5.0.0:
1002 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
1003 | engines: {node: '>=8'}
1004 |
1005 | lodash.sortby@4.7.0:
1006 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
1007 |
1008 | lodash.startcase@4.4.0:
1009 | resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
1010 |
1011 | loupe@3.1.1:
1012 | resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
1013 |
1014 | lru-cache@10.2.0:
1015 | resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
1016 | engines: {node: 14 || >=16.14}
1017 |
1018 | lru-cache@4.1.5:
1019 | resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
1020 |
1021 | lru-cache@6.0.0:
1022 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
1023 | engines: {node: '>=10'}
1024 |
1025 | magic-string@0.30.11:
1026 | resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
1027 |
1028 | memfs@4.12.0:
1029 | resolution: {integrity: sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==}
1030 | engines: {node: '>= 4.0.0'}
1031 |
1032 | merge-stream@2.0.0:
1033 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
1034 |
1035 | merge2@1.4.1:
1036 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
1037 | engines: {node: '>= 8'}
1038 |
1039 | micromatch@4.0.5:
1040 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
1041 | engines: {node: '>=8.6'}
1042 |
1043 | mimic-fn@2.1.0:
1044 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
1045 | engines: {node: '>=6'}
1046 |
1047 | minimatch@9.0.3:
1048 | resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
1049 | engines: {node: '>=16 || 14 >=14.17'}
1050 |
1051 | minipass@7.0.4:
1052 | resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
1053 | engines: {node: '>=16 || 14 >=14.17'}
1054 |
1055 | mri@1.2.0:
1056 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
1057 | engines: {node: '>=4'}
1058 |
1059 | ms@2.1.3:
1060 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1061 |
1062 | mz@2.7.0:
1063 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
1064 |
1065 | nanoid@3.3.7:
1066 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
1067 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1068 | hasBin: true
1069 |
1070 | node-fetch@2.7.0:
1071 | resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
1072 | engines: {node: 4.x || >=6.0.0}
1073 | peerDependencies:
1074 | encoding: ^0.1.0
1075 | peerDependenciesMeta:
1076 | encoding:
1077 | optional: true
1078 |
1079 | normalize-path@3.0.0:
1080 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
1081 | engines: {node: '>=0.10.0'}
1082 |
1083 | npm-run-path@4.0.1:
1084 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
1085 | engines: {node: '>=8'}
1086 |
1087 | object-assign@4.1.1:
1088 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
1089 | engines: {node: '>=0.10.0'}
1090 |
1091 | onetime@5.1.2:
1092 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
1093 | engines: {node: '>=6'}
1094 |
1095 | os-tmpdir@1.0.2:
1096 | resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
1097 | engines: {node: '>=0.10.0'}
1098 |
1099 | outdent@0.5.0:
1100 | resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
1101 |
1102 | p-filter@2.1.0:
1103 | resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
1104 | engines: {node: '>=8'}
1105 |
1106 | p-limit@2.3.0:
1107 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
1108 | engines: {node: '>=6'}
1109 |
1110 | p-locate@4.1.0:
1111 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
1112 | engines: {node: '>=8'}
1113 |
1114 | p-map@2.1.0:
1115 | resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
1116 | engines: {node: '>=6'}
1117 |
1118 | p-try@2.2.0:
1119 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
1120 | engines: {node: '>=6'}
1121 |
1122 | package-manager-detector@0.2.0:
1123 | resolution: {integrity: sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog==}
1124 |
1125 | parse-ms@3.0.0:
1126 | resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==}
1127 | engines: {node: '>=12'}
1128 |
1129 | path-exists@4.0.0:
1130 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
1131 | engines: {node: '>=8'}
1132 |
1133 | path-key@3.1.1:
1134 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1135 | engines: {node: '>=8'}
1136 |
1137 | path-scurry@1.10.1:
1138 | resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
1139 | engines: {node: '>=16 || 14 >=14.17'}
1140 |
1141 | path-type@4.0.0:
1142 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
1143 | engines: {node: '>=8'}
1144 |
1145 | pathe@1.1.2:
1146 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
1147 |
1148 | pathval@2.0.0:
1149 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
1150 | engines: {node: '>= 14.16'}
1151 |
1152 | picocolors@1.1.0:
1153 | resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
1154 |
1155 | picomatch@2.3.1:
1156 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1157 | engines: {node: '>=8.6'}
1158 |
1159 | picomatch@4.0.2:
1160 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
1161 | engines: {node: '>=12'}
1162 |
1163 | pify@4.0.1:
1164 | resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
1165 | engines: {node: '>=6'}
1166 |
1167 | pirates@4.0.6:
1168 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
1169 | engines: {node: '>= 6'}
1170 |
1171 | postcss-load-config@6.0.1:
1172 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
1173 | engines: {node: '>= 18'}
1174 | peerDependencies:
1175 | jiti: '>=1.21.0'
1176 | postcss: '>=8.0.9'
1177 | tsx: ^4.8.1
1178 | yaml: ^2.4.2
1179 | peerDependenciesMeta:
1180 | jiti:
1181 | optional: true
1182 | postcss:
1183 | optional: true
1184 | tsx:
1185 | optional: true
1186 | yaml:
1187 | optional: true
1188 |
1189 | postcss@8.4.35:
1190 | resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==}
1191 | engines: {node: ^10 || ^12 || >=14}
1192 |
1193 | prettier-plugin-organize-imports@4.1.0:
1194 | resolution: {integrity: sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==}
1195 | peerDependencies:
1196 | prettier: '>=2.0'
1197 | typescript: '>=2.9'
1198 | vue-tsc: ^2.1.0
1199 | peerDependenciesMeta:
1200 | vue-tsc:
1201 | optional: true
1202 |
1203 | prettier@2.8.8:
1204 | resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
1205 | engines: {node: '>=10.13.0'}
1206 | hasBin: true
1207 |
1208 | prettier@3.3.3:
1209 | resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
1210 | engines: {node: '>=14'}
1211 | hasBin: true
1212 |
1213 | pretty-bytes@6.1.1:
1214 | resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
1215 | engines: {node: ^14.13.1 || >=16.0.0}
1216 |
1217 | pretty-ms@8.0.0:
1218 | resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==}
1219 | engines: {node: '>=14.16'}
1220 |
1221 | pseudomap@1.0.2:
1222 | resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
1223 |
1224 | punycode@2.3.1:
1225 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
1226 | engines: {node: '>=6'}
1227 |
1228 | queue-microtask@1.2.3:
1229 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
1230 |
1231 | read-yaml-file@1.1.0:
1232 | resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==}
1233 | engines: {node: '>=6'}
1234 |
1235 | readdirp@3.6.0:
1236 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
1237 | engines: {node: '>=8.10.0'}
1238 |
1239 | regenerator-runtime@0.14.1:
1240 | resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
1241 |
1242 | resolve-from@5.0.0:
1243 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
1244 | engines: {node: '>=8'}
1245 |
1246 | resolve-pkg-maps@1.0.0:
1247 | resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
1248 |
1249 | reusify@1.0.4:
1250 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
1251 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1252 |
1253 | rollup@4.23.0:
1254 | resolution: {integrity: sha512-vXB4IT9/KLDrS2WRXmY22sVB2wTsTwkpxjB8Q3mnakTENcYw3FRmfdYDy/acNmls+lHmDazgrRjK/yQ6hQAtwA==}
1255 | engines: {node: '>=18.0.0', npm: '>=8.0.0'}
1256 | hasBin: true
1257 |
1258 | run-parallel@1.2.0:
1259 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
1260 |
1261 | safer-buffer@2.1.2:
1262 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
1263 |
1264 | semver@7.6.0:
1265 | resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
1266 | engines: {node: '>=10'}
1267 | hasBin: true
1268 |
1269 | shebang-command@1.2.0:
1270 | resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
1271 | engines: {node: '>=0.10.0'}
1272 |
1273 | shebang-command@2.0.0:
1274 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
1275 | engines: {node: '>=8'}
1276 |
1277 | shebang-regex@1.0.0:
1278 | resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
1279 | engines: {node: '>=0.10.0'}
1280 |
1281 | shebang-regex@3.0.0:
1282 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1283 | engines: {node: '>=8'}
1284 |
1285 | siginfo@2.0.0:
1286 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
1287 |
1288 | signal-exit@3.0.7:
1289 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
1290 |
1291 | signal-exit@4.1.0:
1292 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
1293 | engines: {node: '>=14'}
1294 |
1295 | slash@3.0.0:
1296 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
1297 | engines: {node: '>=8'}
1298 |
1299 | source-map-js@1.0.2:
1300 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
1301 | engines: {node: '>=0.10.0'}
1302 |
1303 | source-map@0.8.0-beta.0:
1304 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
1305 | engines: {node: '>= 8'}
1306 |
1307 | spawndamnit@2.0.0:
1308 | resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==}
1309 |
1310 | sprintf-js@1.0.3:
1311 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
1312 |
1313 | stackback@0.0.2:
1314 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
1315 |
1316 | std-env@3.7.0:
1317 | resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
1318 |
1319 | string-width@4.2.3:
1320 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
1321 | engines: {node: '>=8'}
1322 |
1323 | string-width@5.1.2:
1324 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
1325 | engines: {node: '>=12'}
1326 |
1327 | strip-ansi@6.0.1:
1328 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
1329 | engines: {node: '>=8'}
1330 |
1331 | strip-ansi@7.1.0:
1332 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
1333 | engines: {node: '>=12'}
1334 |
1335 | strip-bom@3.0.0:
1336 | resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
1337 | engines: {node: '>=4'}
1338 |
1339 | strip-final-newline@2.0.0:
1340 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
1341 | engines: {node: '>=6'}
1342 |
1343 | sucrase@3.35.0:
1344 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
1345 | engines: {node: '>=16 || 14 >=14.17'}
1346 | hasBin: true
1347 |
1348 | supports-color@9.4.0:
1349 | resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==}
1350 | engines: {node: '>=12'}
1351 |
1352 | term-size@2.2.1:
1353 | resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
1354 | engines: {node: '>=8'}
1355 |
1356 | thenify-all@1.6.0:
1357 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
1358 | engines: {node: '>=0.8'}
1359 |
1360 | thenify@3.3.1:
1361 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
1362 |
1363 | thingies@1.21.0:
1364 | resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==}
1365 | engines: {node: '>=10.18'}
1366 | peerDependencies:
1367 | tslib: ^2
1368 |
1369 | tinybench@2.9.0:
1370 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
1371 |
1372 | tinyexec@0.3.0:
1373 | resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==}
1374 |
1375 | tinyglobby@0.2.9:
1376 | resolution: {integrity: sha512-8or1+BGEdk1Zkkw2ii16qSS7uVrQJPre5A9o/XkWPATkk23FZh/15BKFxPnlTy6vkljZxLqYCzzBMj30ZrSvjw==}
1377 | engines: {node: '>=12.0.0'}
1378 |
1379 | tinypool@1.0.1:
1380 | resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==}
1381 | engines: {node: ^18.0.0 || >=20.0.0}
1382 |
1383 | tinyrainbow@1.2.0:
1384 | resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
1385 | engines: {node: '>=14.0.0'}
1386 |
1387 | tinyspy@3.0.2:
1388 | resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
1389 | engines: {node: '>=14.0.0'}
1390 |
1391 | tmp@0.0.33:
1392 | resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
1393 | engines: {node: '>=0.6.0'}
1394 |
1395 | to-regex-range@5.0.1:
1396 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1397 | engines: {node: '>=8.0'}
1398 |
1399 | tr46@0.0.3:
1400 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
1401 |
1402 | tr46@1.0.1:
1403 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
1404 |
1405 | tree-dump@1.0.2:
1406 | resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==}
1407 | engines: {node: '>=10.0'}
1408 | peerDependencies:
1409 | tslib: '2'
1410 |
1411 | tree-kill@1.2.2:
1412 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
1413 | hasBin: true
1414 |
1415 | ts-interface-checker@0.1.13:
1416 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
1417 |
1418 | tslib@2.7.0:
1419 | resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
1420 |
1421 | tsup@8.3.0:
1422 | resolution: {integrity: sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag==}
1423 | engines: {node: '>=18'}
1424 | hasBin: true
1425 | peerDependencies:
1426 | '@microsoft/api-extractor': ^7.36.0
1427 | '@swc/core': ^1
1428 | postcss: ^8.4.12
1429 | typescript: '>=4.5.0'
1430 | peerDependenciesMeta:
1431 | '@microsoft/api-extractor':
1432 | optional: true
1433 | '@swc/core':
1434 | optional: true
1435 | postcss:
1436 | optional: true
1437 | typescript:
1438 | optional: true
1439 |
1440 | tsx@4.19.1:
1441 | resolution: {integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==}
1442 | engines: {node: '>=18.0.0'}
1443 | hasBin: true
1444 |
1445 | typanion@3.14.0:
1446 | resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==}
1447 |
1448 | typescript@5.6.2:
1449 | resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==}
1450 | engines: {node: '>=14.17'}
1451 | hasBin: true
1452 |
1453 | universalify@0.1.2:
1454 | resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
1455 | engines: {node: '>= 4.0.0'}
1456 |
1457 | vite-node@2.1.1:
1458 | resolution: {integrity: sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==}
1459 | engines: {node: ^18.0.0 || >=20.0.0}
1460 | hasBin: true
1461 |
1462 | vite@5.1.3:
1463 | resolution: {integrity: sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==}
1464 | engines: {node: ^18.0.0 || >=20.0.0}
1465 | hasBin: true
1466 | peerDependencies:
1467 | '@types/node': ^18.0.0 || >=20.0.0
1468 | less: '*'
1469 | lightningcss: ^1.21.0
1470 | sass: '*'
1471 | stylus: '*'
1472 | sugarss: '*'
1473 | terser: ^5.4.0
1474 | peerDependenciesMeta:
1475 | '@types/node':
1476 | optional: true
1477 | less:
1478 | optional: true
1479 | lightningcss:
1480 | optional: true
1481 | sass:
1482 | optional: true
1483 | stylus:
1484 | optional: true
1485 | sugarss:
1486 | optional: true
1487 | terser:
1488 | optional: true
1489 |
1490 | vitest@2.1.1:
1491 | resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==}
1492 | engines: {node: ^18.0.0 || >=20.0.0}
1493 | hasBin: true
1494 | peerDependencies:
1495 | '@edge-runtime/vm': '*'
1496 | '@types/node': ^18.0.0 || >=20.0.0
1497 | '@vitest/browser': 2.1.1
1498 | '@vitest/ui': 2.1.1
1499 | happy-dom: '*'
1500 | jsdom: '*'
1501 | peerDependenciesMeta:
1502 | '@edge-runtime/vm':
1503 | optional: true
1504 | '@types/node':
1505 | optional: true
1506 | '@vitest/browser':
1507 | optional: true
1508 | '@vitest/ui':
1509 | optional: true
1510 | happy-dom:
1511 | optional: true
1512 | jsdom:
1513 | optional: true
1514 |
1515 | webidl-conversions@3.0.1:
1516 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
1517 |
1518 | webidl-conversions@4.0.2:
1519 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
1520 |
1521 | whatwg-url@5.0.0:
1522 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
1523 |
1524 | whatwg-url@7.1.0:
1525 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
1526 |
1527 | which@1.3.1:
1528 | resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
1529 | hasBin: true
1530 |
1531 | which@2.0.2:
1532 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
1533 | engines: {node: '>= 8'}
1534 | hasBin: true
1535 |
1536 | why-is-node-running@2.3.0:
1537 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
1538 | engines: {node: '>=8'}
1539 | hasBin: true
1540 |
1541 | wrap-ansi@7.0.0:
1542 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
1543 | engines: {node: '>=10'}
1544 |
1545 | wrap-ansi@8.1.0:
1546 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
1547 | engines: {node: '>=12'}
1548 |
1549 | yallist@2.1.2:
1550 | resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
1551 |
1552 | yallist@4.0.0:
1553 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
1554 |
1555 | snapshots:
1556 |
1557 | '@babel/runtime@7.23.9':
1558 | dependencies:
1559 | regenerator-runtime: 0.14.1
1560 |
1561 | '@biomejs/biome@1.9.2':
1562 | optionalDependencies:
1563 | '@biomejs/cli-darwin-arm64': 1.9.2
1564 | '@biomejs/cli-darwin-x64': 1.9.2
1565 | '@biomejs/cli-linux-arm64': 1.9.2
1566 | '@biomejs/cli-linux-arm64-musl': 1.9.2
1567 | '@biomejs/cli-linux-x64': 1.9.2
1568 | '@biomejs/cli-linux-x64-musl': 1.9.2
1569 | '@biomejs/cli-win32-arm64': 1.9.2
1570 | '@biomejs/cli-win32-x64': 1.9.2
1571 |
1572 | '@biomejs/cli-darwin-arm64@1.9.2':
1573 | optional: true
1574 |
1575 | '@biomejs/cli-darwin-x64@1.9.2':
1576 | optional: true
1577 |
1578 | '@biomejs/cli-linux-arm64-musl@1.9.2':
1579 | optional: true
1580 |
1581 | '@biomejs/cli-linux-arm64@1.9.2':
1582 | optional: true
1583 |
1584 | '@biomejs/cli-linux-x64-musl@1.9.2':
1585 | optional: true
1586 |
1587 | '@biomejs/cli-linux-x64@1.9.2':
1588 | optional: true
1589 |
1590 | '@biomejs/cli-win32-arm64@1.9.2':
1591 | optional: true
1592 |
1593 | '@biomejs/cli-win32-x64@1.9.2':
1594 | optional: true
1595 |
1596 | '@changesets/apply-release-plan@7.0.5':
1597 | dependencies:
1598 | '@changesets/config': 3.0.3
1599 | '@changesets/get-version-range-type': 0.4.0
1600 | '@changesets/git': 3.0.1
1601 | '@changesets/should-skip-package': 0.1.1
1602 | '@changesets/types': 6.0.0
1603 | '@manypkg/get-packages': 1.1.3
1604 | detect-indent: 6.1.0
1605 | fs-extra: 7.0.1
1606 | lodash.startcase: 4.4.0
1607 | outdent: 0.5.0
1608 | prettier: 2.8.8
1609 | resolve-from: 5.0.0
1610 | semver: 7.6.0
1611 |
1612 | '@changesets/assemble-release-plan@6.0.4':
1613 | dependencies:
1614 | '@changesets/errors': 0.2.0
1615 | '@changesets/get-dependents-graph': 2.1.2
1616 | '@changesets/should-skip-package': 0.1.1
1617 | '@changesets/types': 6.0.0
1618 | '@manypkg/get-packages': 1.1.3
1619 | semver: 7.6.0
1620 |
1621 | '@changesets/changelog-git@0.2.0':
1622 | dependencies:
1623 | '@changesets/types': 6.0.0
1624 |
1625 | '@changesets/cli@2.27.8':
1626 | dependencies:
1627 | '@changesets/apply-release-plan': 7.0.5
1628 | '@changesets/assemble-release-plan': 6.0.4
1629 | '@changesets/changelog-git': 0.2.0
1630 | '@changesets/config': 3.0.3
1631 | '@changesets/errors': 0.2.0
1632 | '@changesets/get-dependents-graph': 2.1.2
1633 | '@changesets/get-release-plan': 4.0.4
1634 | '@changesets/git': 3.0.1
1635 | '@changesets/logger': 0.1.1
1636 | '@changesets/pre': 2.0.1
1637 | '@changesets/read': 0.6.1
1638 | '@changesets/should-skip-package': 0.1.1
1639 | '@changesets/types': 6.0.0
1640 | '@changesets/write': 0.3.2
1641 | '@manypkg/get-packages': 1.1.3
1642 | '@types/semver': 7.5.7
1643 | ansi-colors: 4.1.3
1644 | ci-info: 3.9.0
1645 | enquirer: 2.4.1
1646 | external-editor: 3.1.0
1647 | fs-extra: 7.0.1
1648 | mri: 1.2.0
1649 | outdent: 0.5.0
1650 | p-limit: 2.3.0
1651 | package-manager-detector: 0.2.0
1652 | picocolors: 1.1.0
1653 | resolve-from: 5.0.0
1654 | semver: 7.6.0
1655 | spawndamnit: 2.0.0
1656 | term-size: 2.2.1
1657 |
1658 | '@changesets/config@3.0.3':
1659 | dependencies:
1660 | '@changesets/errors': 0.2.0
1661 | '@changesets/get-dependents-graph': 2.1.2
1662 | '@changesets/logger': 0.1.1
1663 | '@changesets/types': 6.0.0
1664 | '@manypkg/get-packages': 1.1.3
1665 | fs-extra: 7.0.1
1666 | micromatch: 4.0.5
1667 |
1668 | '@changesets/errors@0.2.0':
1669 | dependencies:
1670 | extendable-error: 0.1.7
1671 |
1672 | '@changesets/get-dependents-graph@2.1.2':
1673 | dependencies:
1674 | '@changesets/types': 6.0.0
1675 | '@manypkg/get-packages': 1.1.3
1676 | picocolors: 1.1.0
1677 | semver: 7.6.0
1678 |
1679 | '@changesets/get-github-info@0.6.0':
1680 | dependencies:
1681 | dataloader: 1.4.0
1682 | node-fetch: 2.7.0
1683 | transitivePeerDependencies:
1684 | - encoding
1685 |
1686 | '@changesets/get-release-plan@4.0.4':
1687 | dependencies:
1688 | '@changesets/assemble-release-plan': 6.0.4
1689 | '@changesets/config': 3.0.3
1690 | '@changesets/pre': 2.0.1
1691 | '@changesets/read': 0.6.1
1692 | '@changesets/types': 6.0.0
1693 | '@manypkg/get-packages': 1.1.3
1694 |
1695 | '@changesets/get-version-range-type@0.4.0': {}
1696 |
1697 | '@changesets/git@3.0.1':
1698 | dependencies:
1699 | '@changesets/errors': 0.2.0
1700 | '@manypkg/get-packages': 1.1.3
1701 | is-subdir: 1.2.0
1702 | micromatch: 4.0.5
1703 | spawndamnit: 2.0.0
1704 |
1705 | '@changesets/logger@0.1.1':
1706 | dependencies:
1707 | picocolors: 1.1.0
1708 |
1709 | '@changesets/parse@0.4.0':
1710 | dependencies:
1711 | '@changesets/types': 6.0.0
1712 | js-yaml: 3.14.1
1713 |
1714 | '@changesets/pre@2.0.1':
1715 | dependencies:
1716 | '@changesets/errors': 0.2.0
1717 | '@changesets/types': 6.0.0
1718 | '@manypkg/get-packages': 1.1.3
1719 | fs-extra: 7.0.1
1720 |
1721 | '@changesets/read@0.6.1':
1722 | dependencies:
1723 | '@changesets/git': 3.0.1
1724 | '@changesets/logger': 0.1.1
1725 | '@changesets/parse': 0.4.0
1726 | '@changesets/types': 6.0.0
1727 | fs-extra: 7.0.1
1728 | p-filter: 2.1.0
1729 | picocolors: 1.1.0
1730 |
1731 | '@changesets/should-skip-package@0.1.1':
1732 | dependencies:
1733 | '@changesets/types': 6.0.0
1734 | '@manypkg/get-packages': 1.1.3
1735 |
1736 | '@changesets/types@4.1.0': {}
1737 |
1738 | '@changesets/types@6.0.0': {}
1739 |
1740 | '@changesets/write@0.3.2':
1741 | dependencies:
1742 | '@changesets/types': 6.0.0
1743 | fs-extra: 7.0.1
1744 | human-id: 1.0.2
1745 | prettier: 2.8.8
1746 |
1747 | '@esbuild/aix-ppc64@0.19.12':
1748 | optional: true
1749 |
1750 | '@esbuild/aix-ppc64@0.23.1':
1751 | optional: true
1752 |
1753 | '@esbuild/android-arm64@0.19.12':
1754 | optional: true
1755 |
1756 | '@esbuild/android-arm64@0.23.1':
1757 | optional: true
1758 |
1759 | '@esbuild/android-arm@0.19.12':
1760 | optional: true
1761 |
1762 | '@esbuild/android-arm@0.23.1':
1763 | optional: true
1764 |
1765 | '@esbuild/android-x64@0.19.12':
1766 | optional: true
1767 |
1768 | '@esbuild/android-x64@0.23.1':
1769 | optional: true
1770 |
1771 | '@esbuild/darwin-arm64@0.19.12':
1772 | optional: true
1773 |
1774 | '@esbuild/darwin-arm64@0.23.1':
1775 | optional: true
1776 |
1777 | '@esbuild/darwin-x64@0.19.12':
1778 | optional: true
1779 |
1780 | '@esbuild/darwin-x64@0.23.1':
1781 | optional: true
1782 |
1783 | '@esbuild/freebsd-arm64@0.19.12':
1784 | optional: true
1785 |
1786 | '@esbuild/freebsd-arm64@0.23.1':
1787 | optional: true
1788 |
1789 | '@esbuild/freebsd-x64@0.19.12':
1790 | optional: true
1791 |
1792 | '@esbuild/freebsd-x64@0.23.1':
1793 | optional: true
1794 |
1795 | '@esbuild/linux-arm64@0.19.12':
1796 | optional: true
1797 |
1798 | '@esbuild/linux-arm64@0.23.1':
1799 | optional: true
1800 |
1801 | '@esbuild/linux-arm@0.19.12':
1802 | optional: true
1803 |
1804 | '@esbuild/linux-arm@0.23.1':
1805 | optional: true
1806 |
1807 | '@esbuild/linux-ia32@0.19.12':
1808 | optional: true
1809 |
1810 | '@esbuild/linux-ia32@0.23.1':
1811 | optional: true
1812 |
1813 | '@esbuild/linux-loong64@0.19.12':
1814 | optional: true
1815 |
1816 | '@esbuild/linux-loong64@0.23.1':
1817 | optional: true
1818 |
1819 | '@esbuild/linux-mips64el@0.19.12':
1820 | optional: true
1821 |
1822 | '@esbuild/linux-mips64el@0.23.1':
1823 | optional: true
1824 |
1825 | '@esbuild/linux-ppc64@0.19.12':
1826 | optional: true
1827 |
1828 | '@esbuild/linux-ppc64@0.23.1':
1829 | optional: true
1830 |
1831 | '@esbuild/linux-riscv64@0.19.12':
1832 | optional: true
1833 |
1834 | '@esbuild/linux-riscv64@0.23.1':
1835 | optional: true
1836 |
1837 | '@esbuild/linux-s390x@0.19.12':
1838 | optional: true
1839 |
1840 | '@esbuild/linux-s390x@0.23.1':
1841 | optional: true
1842 |
1843 | '@esbuild/linux-x64@0.19.12':
1844 | optional: true
1845 |
1846 | '@esbuild/linux-x64@0.23.1':
1847 | optional: true
1848 |
1849 | '@esbuild/netbsd-x64@0.19.12':
1850 | optional: true
1851 |
1852 | '@esbuild/netbsd-x64@0.23.1':
1853 | optional: true
1854 |
1855 | '@esbuild/openbsd-arm64@0.23.1':
1856 | optional: true
1857 |
1858 | '@esbuild/openbsd-x64@0.19.12':
1859 | optional: true
1860 |
1861 | '@esbuild/openbsd-x64@0.23.1':
1862 | optional: true
1863 |
1864 | '@esbuild/sunos-x64@0.19.12':
1865 | optional: true
1866 |
1867 | '@esbuild/sunos-x64@0.23.1':
1868 | optional: true
1869 |
1870 | '@esbuild/win32-arm64@0.19.12':
1871 | optional: true
1872 |
1873 | '@esbuild/win32-arm64@0.23.1':
1874 | optional: true
1875 |
1876 | '@esbuild/win32-ia32@0.19.12':
1877 | optional: true
1878 |
1879 | '@esbuild/win32-ia32@0.23.1':
1880 | optional: true
1881 |
1882 | '@esbuild/win32-x64@0.19.12':
1883 | optional: true
1884 |
1885 | '@esbuild/win32-x64@0.23.1':
1886 | optional: true
1887 |
1888 | '@isaacs/cliui@8.0.2':
1889 | dependencies:
1890 | string-width: 5.1.2
1891 | string-width-cjs: string-width@4.2.3
1892 | strip-ansi: 7.1.0
1893 | strip-ansi-cjs: strip-ansi@6.0.1
1894 | wrap-ansi: 8.1.0
1895 | wrap-ansi-cjs: wrap-ansi@7.0.0
1896 |
1897 | '@jridgewell/gen-mapping@0.3.3':
1898 | dependencies:
1899 | '@jridgewell/set-array': 1.1.2
1900 | '@jridgewell/sourcemap-codec': 1.4.15
1901 | '@jridgewell/trace-mapping': 0.3.22
1902 |
1903 | '@jridgewell/resolve-uri@3.1.2': {}
1904 |
1905 | '@jridgewell/set-array@1.1.2': {}
1906 |
1907 | '@jridgewell/sourcemap-codec@1.4.15': {}
1908 |
1909 | '@jridgewell/sourcemap-codec@1.5.0': {}
1910 |
1911 | '@jridgewell/trace-mapping@0.3.22':
1912 | dependencies:
1913 | '@jridgewell/resolve-uri': 3.1.2
1914 | '@jridgewell/sourcemap-codec': 1.4.15
1915 |
1916 | '@jsonjoy.com/base64@1.1.2(tslib@2.7.0)':
1917 | dependencies:
1918 | tslib: 2.7.0
1919 |
1920 | '@jsonjoy.com/json-pack@1.1.0(tslib@2.7.0)':
1921 | dependencies:
1922 | '@jsonjoy.com/base64': 1.1.2(tslib@2.7.0)
1923 | '@jsonjoy.com/util': 1.3.0(tslib@2.7.0)
1924 | hyperdyperid: 1.2.0
1925 | thingies: 1.21.0(tslib@2.7.0)
1926 | tslib: 2.7.0
1927 |
1928 | '@jsonjoy.com/util@1.3.0(tslib@2.7.0)':
1929 | dependencies:
1930 | tslib: 2.7.0
1931 |
1932 | '@manypkg/find-root@1.1.0':
1933 | dependencies:
1934 | '@babel/runtime': 7.23.9
1935 | '@types/node': 12.20.55
1936 | find-up: 4.1.0
1937 | fs-extra: 8.1.0
1938 |
1939 | '@manypkg/get-packages@1.1.3':
1940 | dependencies:
1941 | '@babel/runtime': 7.23.9
1942 | '@changesets/types': 4.1.0
1943 | '@manypkg/find-root': 1.1.0
1944 | fs-extra: 8.1.0
1945 | globby: 11.1.0
1946 | read-yaml-file: 1.1.0
1947 |
1948 | '@nodelib/fs.scandir@2.1.5':
1949 | dependencies:
1950 | '@nodelib/fs.stat': 2.0.5
1951 | run-parallel: 1.2.0
1952 |
1953 | '@nodelib/fs.stat@2.0.5': {}
1954 |
1955 | '@nodelib/fs.walk@1.2.8':
1956 | dependencies:
1957 | '@nodelib/fs.scandir': 2.1.5
1958 | fastq: 1.17.1
1959 |
1960 | '@pkgjs/parseargs@0.11.0':
1961 | optional: true
1962 |
1963 | '@rollup/rollup-android-arm-eabi@4.23.0':
1964 | optional: true
1965 |
1966 | '@rollup/rollup-android-arm64@4.23.0':
1967 | optional: true
1968 |
1969 | '@rollup/rollup-darwin-arm64@4.23.0':
1970 | optional: true
1971 |
1972 | '@rollup/rollup-darwin-x64@4.23.0':
1973 | optional: true
1974 |
1975 | '@rollup/rollup-linux-arm-gnueabihf@4.23.0':
1976 | optional: true
1977 |
1978 | '@rollup/rollup-linux-arm-musleabihf@4.23.0':
1979 | optional: true
1980 |
1981 | '@rollup/rollup-linux-arm64-gnu@4.23.0':
1982 | optional: true
1983 |
1984 | '@rollup/rollup-linux-arm64-musl@4.23.0':
1985 | optional: true
1986 |
1987 | '@rollup/rollup-linux-powerpc64le-gnu@4.23.0':
1988 | optional: true
1989 |
1990 | '@rollup/rollup-linux-riscv64-gnu@4.23.0':
1991 | optional: true
1992 |
1993 | '@rollup/rollup-linux-s390x-gnu@4.23.0':
1994 | optional: true
1995 |
1996 | '@rollup/rollup-linux-x64-gnu@4.23.0':
1997 | optional: true
1998 |
1999 | '@rollup/rollup-linux-x64-musl@4.23.0':
2000 | optional: true
2001 |
2002 | '@rollup/rollup-win32-arm64-msvc@4.23.0':
2003 | optional: true
2004 |
2005 | '@rollup/rollup-win32-ia32-msvc@4.23.0':
2006 | optional: true
2007 |
2008 | '@rollup/rollup-win32-x64-msvc@4.23.0':
2009 | optional: true
2010 |
2011 | '@tsconfig/node14@14.1.2': {}
2012 |
2013 | '@types/estree@1.0.6': {}
2014 |
2015 | '@types/mock-fs@4.13.4':
2016 | dependencies:
2017 | '@types/node': 16.18.82
2018 |
2019 | '@types/node@12.20.55': {}
2020 |
2021 | '@types/node@16.18.82': {}
2022 |
2023 | '@types/picomatch@2.3.4': {}
2024 |
2025 | '@types/semver@7.5.7': {}
2026 |
2027 | '@types/supports-color@8.1.3': {}
2028 |
2029 | '@vitest/expect@2.1.1':
2030 | dependencies:
2031 | '@vitest/spy': 2.1.1
2032 | '@vitest/utils': 2.1.1
2033 | chai: 5.1.1
2034 | tinyrainbow: 1.2.0
2035 |
2036 | '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.1.3(@types/node@16.18.82))':
2037 | dependencies:
2038 | '@vitest/spy': 2.1.1
2039 | estree-walker: 3.0.3
2040 | magic-string: 0.30.11
2041 | optionalDependencies:
2042 | vite: 5.1.3(@types/node@16.18.82)
2043 |
2044 | '@vitest/pretty-format@2.1.1':
2045 | dependencies:
2046 | tinyrainbow: 1.2.0
2047 |
2048 | '@vitest/runner@2.1.1':
2049 | dependencies:
2050 | '@vitest/utils': 2.1.1
2051 | pathe: 1.1.2
2052 |
2053 | '@vitest/snapshot@2.1.1':
2054 | dependencies:
2055 | '@vitest/pretty-format': 2.1.1
2056 | magic-string: 0.30.11
2057 | pathe: 1.1.2
2058 |
2059 | '@vitest/spy@2.1.1':
2060 | dependencies:
2061 | tinyspy: 3.0.2
2062 |
2063 | '@vitest/utils@2.1.1':
2064 | dependencies:
2065 | '@vitest/pretty-format': 2.1.1
2066 | loupe: 3.1.1
2067 | tinyrainbow: 1.2.0
2068 |
2069 | ansi-colors@4.1.3: {}
2070 |
2071 | ansi-regex@5.0.1: {}
2072 |
2073 | ansi-regex@6.0.1: {}
2074 |
2075 | ansi-styles@4.3.0:
2076 | dependencies:
2077 | color-convert: 2.0.1
2078 |
2079 | ansi-styles@6.2.1: {}
2080 |
2081 | any-promise@1.3.0: {}
2082 |
2083 | anymatch@3.1.3:
2084 | dependencies:
2085 | normalize-path: 3.0.0
2086 | picomatch: 2.3.1
2087 |
2088 | argparse@1.0.10:
2089 | dependencies:
2090 | sprintf-js: 1.0.3
2091 |
2092 | array-union@2.1.0: {}
2093 |
2094 | assertion-error@2.0.1: {}
2095 |
2096 | balanced-match@1.0.2: {}
2097 |
2098 | better-path-resolve@1.0.0:
2099 | dependencies:
2100 | is-windows: 1.0.2
2101 |
2102 | binary-extensions@2.2.0: {}
2103 |
2104 | brace-expansion@2.0.1:
2105 | dependencies:
2106 | balanced-match: 1.0.2
2107 |
2108 | braces@3.0.2:
2109 | dependencies:
2110 | fill-range: 7.0.1
2111 |
2112 | bundle-require@5.0.0(esbuild@0.23.1):
2113 | dependencies:
2114 | esbuild: 0.23.1
2115 | load-tsconfig: 0.2.5
2116 |
2117 | cac@6.7.14: {}
2118 |
2119 | chai@5.1.1:
2120 | dependencies:
2121 | assertion-error: 2.0.1
2122 | check-error: 2.1.1
2123 | deep-eql: 5.0.2
2124 | loupe: 3.1.1
2125 | pathval: 2.0.0
2126 |
2127 | changesets-changelog-clean@1.3.0:
2128 | dependencies:
2129 | '@changesets/get-github-info': 0.6.0
2130 | '@changesets/types': 6.0.0
2131 | transitivePeerDependencies:
2132 | - encoding
2133 |
2134 | chardet@0.7.0: {}
2135 |
2136 | check-error@2.1.1: {}
2137 |
2138 | chokidar@3.6.0:
2139 | dependencies:
2140 | anymatch: 3.1.3
2141 | braces: 3.0.2
2142 | glob-parent: 5.1.2
2143 | is-binary-path: 2.1.0
2144 | is-glob: 4.0.3
2145 | normalize-path: 3.0.0
2146 | readdirp: 3.6.0
2147 | optionalDependencies:
2148 | fsevents: 2.3.3
2149 |
2150 | ci-info@3.9.0: {}
2151 |
2152 | clipanion@3.2.1(typanion@3.14.0):
2153 | dependencies:
2154 | typanion: 3.14.0
2155 |
2156 | color-convert@2.0.1:
2157 | dependencies:
2158 | color-name: 1.1.4
2159 |
2160 | color-name@1.1.4: {}
2161 |
2162 | commander@4.1.1: {}
2163 |
2164 | consola@3.2.3: {}
2165 |
2166 | cross-spawn@5.1.0:
2167 | dependencies:
2168 | lru-cache: 4.1.5
2169 | shebang-command: 1.2.0
2170 | which: 1.3.1
2171 |
2172 | cross-spawn@7.0.3:
2173 | dependencies:
2174 | path-key: 3.1.1
2175 | shebang-command: 2.0.0
2176 | which: 2.0.2
2177 |
2178 | dataloader@1.4.0: {}
2179 |
2180 | debug@4.3.7(supports-color@9.4.0):
2181 | dependencies:
2182 | ms: 2.1.3
2183 | optionalDependencies:
2184 | supports-color: 9.4.0
2185 |
2186 | deep-eql@5.0.2: {}
2187 |
2188 | detect-indent@6.1.0: {}
2189 |
2190 | dir-glob@3.0.1:
2191 | dependencies:
2192 | path-type: 4.0.0
2193 |
2194 | eastasianwidth@0.2.0: {}
2195 |
2196 | emoji-regex@8.0.0: {}
2197 |
2198 | emoji-regex@9.2.2: {}
2199 |
2200 | enquirer@2.4.1:
2201 | dependencies:
2202 | ansi-colors: 4.1.3
2203 | strip-ansi: 6.0.1
2204 |
2205 | esbuild@0.19.12:
2206 | optionalDependencies:
2207 | '@esbuild/aix-ppc64': 0.19.12
2208 | '@esbuild/android-arm': 0.19.12
2209 | '@esbuild/android-arm64': 0.19.12
2210 | '@esbuild/android-x64': 0.19.12
2211 | '@esbuild/darwin-arm64': 0.19.12
2212 | '@esbuild/darwin-x64': 0.19.12
2213 | '@esbuild/freebsd-arm64': 0.19.12
2214 | '@esbuild/freebsd-x64': 0.19.12
2215 | '@esbuild/linux-arm': 0.19.12
2216 | '@esbuild/linux-arm64': 0.19.12
2217 | '@esbuild/linux-ia32': 0.19.12
2218 | '@esbuild/linux-loong64': 0.19.12
2219 | '@esbuild/linux-mips64el': 0.19.12
2220 | '@esbuild/linux-ppc64': 0.19.12
2221 | '@esbuild/linux-riscv64': 0.19.12
2222 | '@esbuild/linux-s390x': 0.19.12
2223 | '@esbuild/linux-x64': 0.19.12
2224 | '@esbuild/netbsd-x64': 0.19.12
2225 | '@esbuild/openbsd-x64': 0.19.12
2226 | '@esbuild/sunos-x64': 0.19.12
2227 | '@esbuild/win32-arm64': 0.19.12
2228 | '@esbuild/win32-ia32': 0.19.12
2229 | '@esbuild/win32-x64': 0.19.12
2230 |
2231 | esbuild@0.23.1:
2232 | optionalDependencies:
2233 | '@esbuild/aix-ppc64': 0.23.1
2234 | '@esbuild/android-arm': 0.23.1
2235 | '@esbuild/android-arm64': 0.23.1
2236 | '@esbuild/android-x64': 0.23.1
2237 | '@esbuild/darwin-arm64': 0.23.1
2238 | '@esbuild/darwin-x64': 0.23.1
2239 | '@esbuild/freebsd-arm64': 0.23.1
2240 | '@esbuild/freebsd-x64': 0.23.1
2241 | '@esbuild/linux-arm': 0.23.1
2242 | '@esbuild/linux-arm64': 0.23.1
2243 | '@esbuild/linux-ia32': 0.23.1
2244 | '@esbuild/linux-loong64': 0.23.1
2245 | '@esbuild/linux-mips64el': 0.23.1
2246 | '@esbuild/linux-ppc64': 0.23.1
2247 | '@esbuild/linux-riscv64': 0.23.1
2248 | '@esbuild/linux-s390x': 0.23.1
2249 | '@esbuild/linux-x64': 0.23.1
2250 | '@esbuild/netbsd-x64': 0.23.1
2251 | '@esbuild/openbsd-arm64': 0.23.1
2252 | '@esbuild/openbsd-x64': 0.23.1
2253 | '@esbuild/sunos-x64': 0.23.1
2254 | '@esbuild/win32-arm64': 0.23.1
2255 | '@esbuild/win32-ia32': 0.23.1
2256 | '@esbuild/win32-x64': 0.23.1
2257 |
2258 | esprima@4.0.1: {}
2259 |
2260 | estree-walker@3.0.3:
2261 | dependencies:
2262 | '@types/estree': 1.0.6
2263 |
2264 | execa@5.1.1:
2265 | dependencies:
2266 | cross-spawn: 7.0.3
2267 | get-stream: 6.0.1
2268 | human-signals: 2.1.0
2269 | is-stream: 2.0.1
2270 | merge-stream: 2.0.0
2271 | npm-run-path: 4.0.1
2272 | onetime: 5.1.2
2273 | signal-exit: 3.0.7
2274 | strip-final-newline: 2.0.0
2275 |
2276 | extendable-error@0.1.7: {}
2277 |
2278 | external-editor@3.1.0:
2279 | dependencies:
2280 | chardet: 0.7.0
2281 | iconv-lite: 0.4.24
2282 | tmp: 0.0.33
2283 |
2284 | fast-glob@3.3.2:
2285 | dependencies:
2286 | '@nodelib/fs.stat': 2.0.5
2287 | '@nodelib/fs.walk': 1.2.8
2288 | glob-parent: 5.1.2
2289 | merge2: 1.4.1
2290 | micromatch: 4.0.5
2291 |
2292 | fastq@1.17.1:
2293 | dependencies:
2294 | reusify: 1.0.4
2295 |
2296 | fdir@6.4.0(picomatch@4.0.2):
2297 | optionalDependencies:
2298 | picomatch: 4.0.2
2299 |
2300 | fill-range@7.0.1:
2301 | dependencies:
2302 | to-regex-range: 5.0.1
2303 |
2304 | find-up@4.1.0:
2305 | dependencies:
2306 | locate-path: 5.0.0
2307 | path-exists: 4.0.0
2308 |
2309 | foreground-child@3.1.1:
2310 | dependencies:
2311 | cross-spawn: 7.0.3
2312 | signal-exit: 4.1.0
2313 |
2314 | fs-extra@7.0.1:
2315 | dependencies:
2316 | graceful-fs: 4.2.11
2317 | jsonfile: 4.0.0
2318 | universalify: 0.1.2
2319 |
2320 | fs-extra@8.1.0:
2321 | dependencies:
2322 | graceful-fs: 4.2.11
2323 | jsonfile: 4.0.0
2324 | universalify: 0.1.2
2325 |
2326 | fsevents@2.3.3:
2327 | optional: true
2328 |
2329 | get-func-name@2.0.2: {}
2330 |
2331 | get-stream@6.0.1: {}
2332 |
2333 | get-tsconfig@4.8.1:
2334 | dependencies:
2335 | resolve-pkg-maps: 1.0.0
2336 |
2337 | glob-parent@5.1.2:
2338 | dependencies:
2339 | is-glob: 4.0.3
2340 |
2341 | glob@10.3.10:
2342 | dependencies:
2343 | foreground-child: 3.1.1
2344 | jackspeak: 2.3.6
2345 | minimatch: 9.0.3
2346 | minipass: 7.0.4
2347 | path-scurry: 1.10.1
2348 |
2349 | globby@11.1.0:
2350 | dependencies:
2351 | array-union: 2.1.0
2352 | dir-glob: 3.0.1
2353 | fast-glob: 3.3.2
2354 | ignore: 5.3.1
2355 | merge2: 1.4.1
2356 | slash: 3.0.0
2357 |
2358 | graceful-fs@4.2.11: {}
2359 |
2360 | human-id@1.0.2: {}
2361 |
2362 | human-signals@2.1.0: {}
2363 |
2364 | hyperdyperid@1.2.0: {}
2365 |
2366 | iconv-lite@0.4.24:
2367 | dependencies:
2368 | safer-buffer: 2.1.2
2369 |
2370 | ignore@5.3.1: {}
2371 |
2372 | is-binary-path@2.1.0:
2373 | dependencies:
2374 | binary-extensions: 2.2.0
2375 |
2376 | is-extglob@2.1.1: {}
2377 |
2378 | is-fullwidth-code-point@3.0.0: {}
2379 |
2380 | is-glob@4.0.3:
2381 | dependencies:
2382 | is-extglob: 2.1.1
2383 |
2384 | is-number@7.0.0: {}
2385 |
2386 | is-stream@2.0.1: {}
2387 |
2388 | is-subdir@1.2.0:
2389 | dependencies:
2390 | better-path-resolve: 1.0.0
2391 |
2392 | is-windows@1.0.2: {}
2393 |
2394 | isexe@2.0.0: {}
2395 |
2396 | jackspeak@2.3.6:
2397 | dependencies:
2398 | '@isaacs/cliui': 8.0.2
2399 | optionalDependencies:
2400 | '@pkgjs/parseargs': 0.11.0
2401 |
2402 | joycon@3.1.1: {}
2403 |
2404 | js-yaml@3.14.1:
2405 | dependencies:
2406 | argparse: 1.0.10
2407 | esprima: 4.0.1
2408 |
2409 | jsonfile@4.0.0:
2410 | optionalDependencies:
2411 | graceful-fs: 4.2.11
2412 |
2413 | lilconfig@3.1.2: {}
2414 |
2415 | lines-and-columns@1.2.4: {}
2416 |
2417 | load-tsconfig@0.2.5: {}
2418 |
2419 | locate-path@5.0.0:
2420 | dependencies:
2421 | p-locate: 4.1.0
2422 |
2423 | lodash.sortby@4.7.0: {}
2424 |
2425 | lodash.startcase@4.4.0: {}
2426 |
2427 | loupe@3.1.1:
2428 | dependencies:
2429 | get-func-name: 2.0.2
2430 |
2431 | lru-cache@10.2.0: {}
2432 |
2433 | lru-cache@4.1.5:
2434 | dependencies:
2435 | pseudomap: 1.0.2
2436 | yallist: 2.1.2
2437 |
2438 | lru-cache@6.0.0:
2439 | dependencies:
2440 | yallist: 4.0.0
2441 |
2442 | magic-string@0.30.11:
2443 | dependencies:
2444 | '@jridgewell/sourcemap-codec': 1.5.0
2445 |
2446 | memfs@4.12.0:
2447 | dependencies:
2448 | '@jsonjoy.com/json-pack': 1.1.0(tslib@2.7.0)
2449 | '@jsonjoy.com/util': 1.3.0(tslib@2.7.0)
2450 | tree-dump: 1.0.2(tslib@2.7.0)
2451 | tslib: 2.7.0
2452 |
2453 | merge-stream@2.0.0: {}
2454 |
2455 | merge2@1.4.1: {}
2456 |
2457 | micromatch@4.0.5:
2458 | dependencies:
2459 | braces: 3.0.2
2460 | picomatch: 2.3.1
2461 |
2462 | mimic-fn@2.1.0: {}
2463 |
2464 | minimatch@9.0.3:
2465 | dependencies:
2466 | brace-expansion: 2.0.1
2467 |
2468 | minipass@7.0.4: {}
2469 |
2470 | mri@1.2.0: {}
2471 |
2472 | ms@2.1.3: {}
2473 |
2474 | mz@2.7.0:
2475 | dependencies:
2476 | any-promise: 1.3.0
2477 | object-assign: 4.1.1
2478 | thenify-all: 1.6.0
2479 |
2480 | nanoid@3.3.7: {}
2481 |
2482 | node-fetch@2.7.0:
2483 | dependencies:
2484 | whatwg-url: 5.0.0
2485 |
2486 | normalize-path@3.0.0: {}
2487 |
2488 | npm-run-path@4.0.1:
2489 | dependencies:
2490 | path-key: 3.1.1
2491 |
2492 | object-assign@4.1.1: {}
2493 |
2494 | onetime@5.1.2:
2495 | dependencies:
2496 | mimic-fn: 2.1.0
2497 |
2498 | os-tmpdir@1.0.2: {}
2499 |
2500 | outdent@0.5.0: {}
2501 |
2502 | p-filter@2.1.0:
2503 | dependencies:
2504 | p-map: 2.1.0
2505 |
2506 | p-limit@2.3.0:
2507 | dependencies:
2508 | p-try: 2.2.0
2509 |
2510 | p-locate@4.1.0:
2511 | dependencies:
2512 | p-limit: 2.3.0
2513 |
2514 | p-map@2.1.0: {}
2515 |
2516 | p-try@2.2.0: {}
2517 |
2518 | package-manager-detector@0.2.0: {}
2519 |
2520 | parse-ms@3.0.0: {}
2521 |
2522 | path-exists@4.0.0: {}
2523 |
2524 | path-key@3.1.1: {}
2525 |
2526 | path-scurry@1.10.1:
2527 | dependencies:
2528 | lru-cache: 10.2.0
2529 | minipass: 7.0.4
2530 |
2531 | path-type@4.0.0: {}
2532 |
2533 | pathe@1.1.2: {}
2534 |
2535 | pathval@2.0.0: {}
2536 |
2537 | picocolors@1.1.0: {}
2538 |
2539 | picomatch@2.3.1: {}
2540 |
2541 | picomatch@4.0.2: {}
2542 |
2543 | pify@4.0.1: {}
2544 |
2545 | pirates@4.0.6: {}
2546 |
2547 | postcss-load-config@6.0.1(postcss@8.4.35)(tsx@4.19.1):
2548 | dependencies:
2549 | lilconfig: 3.1.2
2550 | optionalDependencies:
2551 | postcss: 8.4.35
2552 | tsx: 4.19.1
2553 |
2554 | postcss@8.4.35:
2555 | dependencies:
2556 | nanoid: 3.3.7
2557 | picocolors: 1.1.0
2558 | source-map-js: 1.0.2
2559 |
2560 | prettier-plugin-organize-imports@4.1.0(prettier@3.3.3)(typescript@5.6.2):
2561 | dependencies:
2562 | prettier: 3.3.3
2563 | typescript: 5.6.2
2564 |
2565 | prettier@2.8.8: {}
2566 |
2567 | prettier@3.3.3: {}
2568 |
2569 | pretty-bytes@6.1.1: {}
2570 |
2571 | pretty-ms@8.0.0:
2572 | dependencies:
2573 | parse-ms: 3.0.0
2574 |
2575 | pseudomap@1.0.2: {}
2576 |
2577 | punycode@2.3.1: {}
2578 |
2579 | queue-microtask@1.2.3: {}
2580 |
2581 | read-yaml-file@1.1.0:
2582 | dependencies:
2583 | graceful-fs: 4.2.11
2584 | js-yaml: 3.14.1
2585 | pify: 4.0.1
2586 | strip-bom: 3.0.0
2587 |
2588 | readdirp@3.6.0:
2589 | dependencies:
2590 | picomatch: 2.3.1
2591 |
2592 | regenerator-runtime@0.14.1: {}
2593 |
2594 | resolve-from@5.0.0: {}
2595 |
2596 | resolve-pkg-maps@1.0.0: {}
2597 |
2598 | reusify@1.0.4: {}
2599 |
2600 | rollup@4.23.0:
2601 | dependencies:
2602 | '@types/estree': 1.0.6
2603 | optionalDependencies:
2604 | '@rollup/rollup-android-arm-eabi': 4.23.0
2605 | '@rollup/rollup-android-arm64': 4.23.0
2606 | '@rollup/rollup-darwin-arm64': 4.23.0
2607 | '@rollup/rollup-darwin-x64': 4.23.0
2608 | '@rollup/rollup-linux-arm-gnueabihf': 4.23.0
2609 | '@rollup/rollup-linux-arm-musleabihf': 4.23.0
2610 | '@rollup/rollup-linux-arm64-gnu': 4.23.0
2611 | '@rollup/rollup-linux-arm64-musl': 4.23.0
2612 | '@rollup/rollup-linux-powerpc64le-gnu': 4.23.0
2613 | '@rollup/rollup-linux-riscv64-gnu': 4.23.0
2614 | '@rollup/rollup-linux-s390x-gnu': 4.23.0
2615 | '@rollup/rollup-linux-x64-gnu': 4.23.0
2616 | '@rollup/rollup-linux-x64-musl': 4.23.0
2617 | '@rollup/rollup-win32-arm64-msvc': 4.23.0
2618 | '@rollup/rollup-win32-ia32-msvc': 4.23.0
2619 | '@rollup/rollup-win32-x64-msvc': 4.23.0
2620 | fsevents: 2.3.3
2621 |
2622 | run-parallel@1.2.0:
2623 | dependencies:
2624 | queue-microtask: 1.2.3
2625 |
2626 | safer-buffer@2.1.2: {}
2627 |
2628 | semver@7.6.0:
2629 | dependencies:
2630 | lru-cache: 6.0.0
2631 |
2632 | shebang-command@1.2.0:
2633 | dependencies:
2634 | shebang-regex: 1.0.0
2635 |
2636 | shebang-command@2.0.0:
2637 | dependencies:
2638 | shebang-regex: 3.0.0
2639 |
2640 | shebang-regex@1.0.0: {}
2641 |
2642 | shebang-regex@3.0.0: {}
2643 |
2644 | siginfo@2.0.0: {}
2645 |
2646 | signal-exit@3.0.7: {}
2647 |
2648 | signal-exit@4.1.0: {}
2649 |
2650 | slash@3.0.0: {}
2651 |
2652 | source-map-js@1.0.2: {}
2653 |
2654 | source-map@0.8.0-beta.0:
2655 | dependencies:
2656 | whatwg-url: 7.1.0
2657 |
2658 | spawndamnit@2.0.0:
2659 | dependencies:
2660 | cross-spawn: 5.1.0
2661 | signal-exit: 3.0.7
2662 |
2663 | sprintf-js@1.0.3: {}
2664 |
2665 | stackback@0.0.2: {}
2666 |
2667 | std-env@3.7.0: {}
2668 |
2669 | string-width@4.2.3:
2670 | dependencies:
2671 | emoji-regex: 8.0.0
2672 | is-fullwidth-code-point: 3.0.0
2673 | strip-ansi: 6.0.1
2674 |
2675 | string-width@5.1.2:
2676 | dependencies:
2677 | eastasianwidth: 0.2.0
2678 | emoji-regex: 9.2.2
2679 | strip-ansi: 7.1.0
2680 |
2681 | strip-ansi@6.0.1:
2682 | dependencies:
2683 | ansi-regex: 5.0.1
2684 |
2685 | strip-ansi@7.1.0:
2686 | dependencies:
2687 | ansi-regex: 6.0.1
2688 |
2689 | strip-bom@3.0.0: {}
2690 |
2691 | strip-final-newline@2.0.0: {}
2692 |
2693 | sucrase@3.35.0:
2694 | dependencies:
2695 | '@jridgewell/gen-mapping': 0.3.3
2696 | commander: 4.1.1
2697 | glob: 10.3.10
2698 | lines-and-columns: 1.2.4
2699 | mz: 2.7.0
2700 | pirates: 4.0.6
2701 | ts-interface-checker: 0.1.13
2702 |
2703 | supports-color@9.4.0: {}
2704 |
2705 | term-size@2.2.1: {}
2706 |
2707 | thenify-all@1.6.0:
2708 | dependencies:
2709 | thenify: 3.3.1
2710 |
2711 | thenify@3.3.1:
2712 | dependencies:
2713 | any-promise: 1.3.0
2714 |
2715 | thingies@1.21.0(tslib@2.7.0):
2716 | dependencies:
2717 | tslib: 2.7.0
2718 |
2719 | tinybench@2.9.0: {}
2720 |
2721 | tinyexec@0.3.0: {}
2722 |
2723 | tinyglobby@0.2.9:
2724 | dependencies:
2725 | fdir: 6.4.0(picomatch@4.0.2)
2726 | picomatch: 4.0.2
2727 |
2728 | tinypool@1.0.1: {}
2729 |
2730 | tinyrainbow@1.2.0: {}
2731 |
2732 | tinyspy@3.0.2: {}
2733 |
2734 | tmp@0.0.33:
2735 | dependencies:
2736 | os-tmpdir: 1.0.2
2737 |
2738 | to-regex-range@5.0.1:
2739 | dependencies:
2740 | is-number: 7.0.0
2741 |
2742 | tr46@0.0.3: {}
2743 |
2744 | tr46@1.0.1:
2745 | dependencies:
2746 | punycode: 2.3.1
2747 |
2748 | tree-dump@1.0.2(tslib@2.7.0):
2749 | dependencies:
2750 | tslib: 2.7.0
2751 |
2752 | tree-kill@1.2.2: {}
2753 |
2754 | ts-interface-checker@0.1.13: {}
2755 |
2756 | tslib@2.7.0: {}
2757 |
2758 | tsup@8.3.0(postcss@8.4.35)(supports-color@9.4.0)(tsx@4.19.1)(typescript@5.6.2):
2759 | dependencies:
2760 | bundle-require: 5.0.0(esbuild@0.23.1)
2761 | cac: 6.7.14
2762 | chokidar: 3.6.0
2763 | consola: 3.2.3
2764 | debug: 4.3.7(supports-color@9.4.0)
2765 | esbuild: 0.23.1
2766 | execa: 5.1.1
2767 | joycon: 3.1.1
2768 | picocolors: 1.1.0
2769 | postcss-load-config: 6.0.1(postcss@8.4.35)(tsx@4.19.1)
2770 | resolve-from: 5.0.0
2771 | rollup: 4.23.0
2772 | source-map: 0.8.0-beta.0
2773 | sucrase: 3.35.0
2774 | tinyglobby: 0.2.9
2775 | tree-kill: 1.2.2
2776 | optionalDependencies:
2777 | postcss: 8.4.35
2778 | typescript: 5.6.2
2779 | transitivePeerDependencies:
2780 | - jiti
2781 | - supports-color
2782 | - tsx
2783 | - yaml
2784 |
2785 | tsx@4.19.1:
2786 | dependencies:
2787 | esbuild: 0.23.1
2788 | get-tsconfig: 4.8.1
2789 | optionalDependencies:
2790 | fsevents: 2.3.3
2791 |
2792 | typanion@3.14.0: {}
2793 |
2794 | typescript@5.6.2: {}
2795 |
2796 | universalify@0.1.2: {}
2797 |
2798 | vite-node@2.1.1(@types/node@16.18.82)(supports-color@9.4.0):
2799 | dependencies:
2800 | cac: 6.7.14
2801 | debug: 4.3.7(supports-color@9.4.0)
2802 | pathe: 1.1.2
2803 | vite: 5.1.3(@types/node@16.18.82)
2804 | transitivePeerDependencies:
2805 | - '@types/node'
2806 | - less
2807 | - lightningcss
2808 | - sass
2809 | - stylus
2810 | - sugarss
2811 | - supports-color
2812 | - terser
2813 |
2814 | vite@5.1.3(@types/node@16.18.82):
2815 | dependencies:
2816 | esbuild: 0.19.12
2817 | postcss: 8.4.35
2818 | rollup: 4.23.0
2819 | optionalDependencies:
2820 | '@types/node': 16.18.82
2821 | fsevents: 2.3.3
2822 |
2823 | vitest@2.1.1(@types/node@16.18.82)(supports-color@9.4.0):
2824 | dependencies:
2825 | '@vitest/expect': 2.1.1
2826 | '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.1.3(@types/node@16.18.82))
2827 | '@vitest/pretty-format': 2.1.1
2828 | '@vitest/runner': 2.1.1
2829 | '@vitest/snapshot': 2.1.1
2830 | '@vitest/spy': 2.1.1
2831 | '@vitest/utils': 2.1.1
2832 | chai: 5.1.1
2833 | debug: 4.3.7(supports-color@9.4.0)
2834 | magic-string: 0.30.11
2835 | pathe: 1.1.2
2836 | std-env: 3.7.0
2837 | tinybench: 2.9.0
2838 | tinyexec: 0.3.0
2839 | tinypool: 1.0.1
2840 | tinyrainbow: 1.2.0
2841 | vite: 5.1.3(@types/node@16.18.82)
2842 | vite-node: 2.1.1(@types/node@16.18.82)(supports-color@9.4.0)
2843 | why-is-node-running: 2.3.0
2844 | optionalDependencies:
2845 | '@types/node': 16.18.82
2846 | transitivePeerDependencies:
2847 | - less
2848 | - lightningcss
2849 | - msw
2850 | - sass
2851 | - stylus
2852 | - sugarss
2853 | - supports-color
2854 | - terser
2855 |
2856 | webidl-conversions@3.0.1: {}
2857 |
2858 | webidl-conversions@4.0.2: {}
2859 |
2860 | whatwg-url@5.0.0:
2861 | dependencies:
2862 | tr46: 0.0.3
2863 | webidl-conversions: 3.0.1
2864 |
2865 | whatwg-url@7.1.0:
2866 | dependencies:
2867 | lodash.sortby: 4.7.0
2868 | tr46: 1.0.1
2869 | webidl-conversions: 4.0.2
2870 |
2871 | which@1.3.1:
2872 | dependencies:
2873 | isexe: 2.0.0
2874 |
2875 | which@2.0.2:
2876 | dependencies:
2877 | isexe: 2.0.0
2878 |
2879 | why-is-node-running@2.3.0:
2880 | dependencies:
2881 | siginfo: 2.0.0
2882 | stackback: 0.0.2
2883 |
2884 | wrap-ansi@7.0.0:
2885 | dependencies:
2886 | ansi-styles: 4.3.0
2887 | string-width: 4.2.3
2888 | strip-ansi: 6.0.1
2889 |
2890 | wrap-ansi@8.1.0:
2891 | dependencies:
2892 | ansi-styles: 6.2.1
2893 | string-width: 5.1.2
2894 | strip-ansi: 7.1.0
2895 |
2896 | yallist@2.1.2: {}
2897 |
2898 | yallist@4.0.0: {}
2899 |
--------------------------------------------------------------------------------
/src/__test__/getMockedFileStructure.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import { vi } from 'vitest';
3 | import { DEFAULT_GLOBS_FILE_PATH } from '../shared.js';
4 |
5 | export async function getMockedFileStructure(): Promise> {
6 | const actualFs = await vi.importActual('fs/promises');
7 | const defaultGlobs = (await actualFs.readFile(DEFAULT_GLOBS_FILE_PATH)).toString();
8 |
9 | return {
10 | [DEFAULT_GLOBS_FILE_PATH]: defaultGlobs,
11 | node_modules: {
12 | dep1: {
13 | __tests__: {
14 | 'test1.js': '.',
15 | 'test2.js': '.',
16 | },
17 | 'a-dir': {
18 | 'doc.md': '.',
19 | },
20 | '.npmrc': '.',
21 | },
22 | dep2: {
23 | 'CHANGELOG.md': '.',
24 | 'file.js': '.',
25 | },
26 | dep3: {
27 | deeply: {
28 | nested: {
29 | 'file.ext': '.',
30 | },
31 | },
32 | },
33 | dep4: {
34 | 'nonDefaultFile.ext': '.',
35 | },
36 | },
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/src/__test__/path.serializer.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'vitest';
2 |
3 | function normalizePathPart(str: string) {
4 | return str.replace(/\\/g, '/'); // replace windows backslashes
5 | }
6 |
7 | function normalizePath(str: string) {
8 | const normalizedCwd = normalizePathPart(process.cwd());
9 | const normalizedStr = normalizePathPart(str);
10 | return normalizedStr.replace(normalizedCwd, '');
11 | }
12 |
13 | function shouldNormalizePath(val: any) {
14 | if (typeof val === 'string') {
15 | return normalizePath(val) !== val;
16 | }
17 |
18 | return false;
19 | }
20 |
21 | type Serializer = Parameters[0];
22 |
23 | export const pathSerializer: Serializer = {
24 | serialize(val, config, indentation, depth, refs, printer) {
25 | if (typeof val === 'string') {
26 | const normalizedVal = normalizePath(val);
27 | return printer(normalizedVal, config, indentation, depth, refs);
28 | }
29 |
30 | if (typeof val === 'object') {
31 | const normalizedVal = Object.fromEntries(
32 | Object.entries(val).map(([key, value]) => [
33 | key,
34 | typeof value === 'string' ? normalizePath(value) : value,
35 | ])
36 | );
37 |
38 | return printer(normalizedVal, config, indentation, depth, refs);
39 | }
40 |
41 | return val;
42 | },
43 | test(val) {
44 | return shouldNormalizePath(val);
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/src/analyze.test.ts:
--------------------------------------------------------------------------------
1 | import { vol } from 'memfs';
2 | import { beforeEach, describe, expect, it } from 'vitest';
3 | import { getMockedFileStructure } from './__test__/getMockedFileStructure.js';
4 | import { analyze } from './analyze.js';
5 |
6 | const fileStructure = await getMockedFileStructure();
7 |
8 | beforeEach(async () => {
9 | vol.fromNestedJSON(fileStructure);
10 | });
11 |
12 | describe(analyze.name, () => {
13 | it('returns information about the files that would be removed', async () => {
14 | const result = await analyze();
15 | expect(result).toMatchInlineSnapshot(`
16 | [
17 | {
18 | "filePath": "/node_modules/dep1/.npmrc",
19 | "includedByDefault": true,
20 | "includedByGlobs": [
21 | {
22 | "derived": "/node_modules/**/.npmrc",
23 | "original": ".npmrc",
24 | },
25 | {
26 | "derived": "/node_modules/**/.npmrc",
27 | "original": ".npmrc",
28 | },
29 | ],
30 | },
31 | {
32 | "filePath": "/node_modules/dep2/CHANGELOG.md",
33 | "includedByDefault": true,
34 | "includedByGlobs": [
35 | {
36 | "derived": "/node_modules/**/*.@(md|mkd|markdown|mdown)",
37 | "original": "*.@(md|mkd|markdown|mdown)",
38 | },
39 | {
40 | "derived": "/node_modules/**/changelog*(.*)",
41 | "original": "changelog*(.*)",
42 | },
43 | ],
44 | },
45 | {
46 | "filePath": "/node_modules/dep1/__tests__/test1.js",
47 | "includedByDefault": true,
48 | "includedByGlobs": [
49 | {
50 | "derived": "/node_modules/**/__tests__/**",
51 | "original": "__tests__/",
52 | },
53 | ],
54 | },
55 | {
56 | "filePath": "/node_modules/dep1/__tests__/test2.js",
57 | "includedByDefault": true,
58 | "includedByGlobs": [
59 | {
60 | "derived": "/node_modules/**/__tests__/**",
61 | "original": "__tests__/",
62 | },
63 | ],
64 | },
65 | {
66 | "filePath": "/node_modules/dep1/a-dir/doc.md",
67 | "includedByDefault": true,
68 | "includedByGlobs": [
69 | {
70 | "derived": "/node_modules/**/*.@(md|mkd|markdown|mdown)",
71 | "original": "*.@(md|mkd|markdown|mdown)",
72 | },
73 | ],
74 | },
75 | ]
76 | `);
77 | });
78 |
79 | it('accepts custom globs', async () => {
80 | const result = await analyze({ globs: ['**/nonDefaultFile.ext'] });
81 | expect(result).toMatchInlineSnapshot(`
82 | [
83 | {
84 | "filePath": "/node_modules/dep1/.npmrc",
85 | "includedByDefault": true,
86 | "includedByGlobs": [
87 | {
88 | "derived": "/node_modules/**/.npmrc",
89 | "original": ".npmrc",
90 | },
91 | {
92 | "derived": "/node_modules/**/.npmrc",
93 | "original": ".npmrc",
94 | },
95 | ],
96 | },
97 | {
98 | "filePath": "/node_modules/dep2/CHANGELOG.md",
99 | "includedByDefault": true,
100 | "includedByGlobs": [
101 | {
102 | "derived": "/node_modules/**/*.@(md|mkd|markdown|mdown)",
103 | "original": "*.@(md|mkd|markdown|mdown)",
104 | },
105 | {
106 | "derived": "/node_modules/**/changelog*(.*)",
107 | "original": "changelog*(.*)",
108 | },
109 | ],
110 | },
111 | {
112 | "filePath": "/node_modules/dep4/nonDefaultFile.ext",
113 | "includedByDefault": false,
114 | "includedByGlobs": [
115 | {
116 | "derived": "/node_modules/**/**/nonDefaultFile.ext",
117 | "original": "**/nonDefaultFile.ext",
118 | },
119 | ],
120 | },
121 | {
122 | "filePath": "/node_modules/dep1/__tests__/test1.js",
123 | "includedByDefault": true,
124 | "includedByGlobs": [
125 | {
126 | "derived": "/node_modules/**/__tests__/**",
127 | "original": "__tests__/",
128 | },
129 | ],
130 | },
131 | {
132 | "filePath": "/node_modules/dep1/__tests__/test2.js",
133 | "includedByDefault": true,
134 | "includedByGlobs": [
135 | {
136 | "derived": "/node_modules/**/__tests__/**",
137 | "original": "__tests__/",
138 | },
139 | ],
140 | },
141 | {
142 | "filePath": "/node_modules/dep1/a-dir/doc.md",
143 | "includedByDefault": true,
144 | "includedByGlobs": [
145 | {
146 | "derived": "/node_modules/**/*.@(md|mkd|markdown|mdown)",
147 | "original": "*.@(md|mkd|markdown|mdown)",
148 | },
149 | ],
150 | },
151 | ]
152 | `);
153 | });
154 |
155 | it('allows skipping default globs', async () => {
156 | const result = await analyze({ noDefaults: true, globs: ['**/nonDefaultFile.ext'] });
157 | expect(result).toMatchInlineSnapshot(`
158 | [
159 | {
160 | "filePath": "/node_modules/dep4/nonDefaultFile.ext",
161 | "includedByDefault": false,
162 | "includedByGlobs": [
163 | {
164 | "derived": "/node_modules/**/**/nonDefaultFile.ext",
165 | "original": "**/nonDefaultFile.ext",
166 | },
167 | ],
168 | },
169 | ]
170 | `);
171 | });
172 |
173 | it('uses custom glob file if provided', async () => {
174 | const customGlobFile = '.custom-glob-file';
175 | vol.fromNestedJSON({ ...fileStructure, [customGlobFile]: '**.md\n**/nonDefaultFile.ext' });
176 |
177 | const result = await analyze({ noDefaults: true, globFile: customGlobFile });
178 | expect(result).toMatchInlineSnapshot(`
179 | [
180 | {
181 | "filePath": "/node_modules/dep2/CHANGELOG.md",
182 | "includedByDefault": true,
183 | "includedByGlobs": [
184 | {
185 | "derived": "/node_modules/**/**.md",
186 | "original": "**.md",
187 | },
188 | ],
189 | },
190 | {
191 | "filePath": "/node_modules/dep4/nonDefaultFile.ext",
192 | "includedByDefault": false,
193 | "includedByGlobs": [
194 | {
195 | "derived": "/node_modules/**/**/nonDefaultFile.ext",
196 | "original": "**/nonDefaultFile.ext",
197 | },
198 | ],
199 | },
200 | {
201 | "filePath": "/node_modules/dep1/a-dir/doc.md",
202 | "includedByDefault": true,
203 | "includedByGlobs": [
204 | {
205 | "derived": "/node_modules/**/**.md",
206 | "original": "**.md",
207 | },
208 | ],
209 | },
210 | ]
211 | `);
212 | });
213 | });
214 |
--------------------------------------------------------------------------------
/src/analyze.ts:
--------------------------------------------------------------------------------
1 | import { SharedOptions, sharedDefaultOptions } from './shared.js';
2 | import {
3 | findFilesByGlobLists,
4 | getGlobLists,
5 | makeGlobMatcher,
6 | optimizeGlobLists,
7 | parseDefaultGlobsFile,
8 | toAbsoluteGlobLists,
9 | toPosixPath,
10 | } from './utils/glob.js';
11 |
12 | export interface GlobVersions {
13 | /** The original glob, as provided by the glob file or user. */
14 | original: string;
15 | /** The glob as it was derived by clean-modules and passed to picomatch. */
16 | derived: string;
17 | }
18 |
19 | export interface AnalyzeResult {
20 | /** The absolute path to the file. */
21 | filePath: string;
22 | /** Whether the file was included by clean-modules' default globs. */
23 | includedByDefault: boolean;
24 | /** List of globs that included the file. */
25 | includedByGlobs: GlobVersions[];
26 | }
27 |
28 | export type AnalyzeOptions = SharedOptions;
29 |
30 | /**
31 | * Helps determining why a file is included by the `clean` operation without removing any files. Extra globs can be passed as positional args.
32 | * @param options analyze options
33 | * @returns list of files that were included by the clean operation and what globs they were included by
34 | */
35 | export async function analyze(options: AnalyzeOptions = {}): Promise {
36 | const mergedOptions = { ...sharedDefaultOptions, ...options };
37 | const { globs, noDefaults, globFile, directory } = mergedOptions;
38 | const nodeModulesPath = directory || sharedDefaultOptions.directory;
39 |
40 | const globLists = await getGlobLists({ globs, noDefaults, globFile });
41 | const includedFiles = await findFilesByGlobLists(nodeModulesPath, globLists);
42 |
43 | const defaultGlobs = toAbsoluteGlobLists(
44 | optimizeGlobLists(await parseDefaultGlobsFile()),
45 | nodeModulesPath
46 | );
47 |
48 | const includedByDefaultMatcher = makeGlobMatcher(defaultGlobs.included, {
49 | ignore: defaultGlobs.excluded,
50 | });
51 |
52 | const globMatchers = globLists.included.map((glob, index) => {
53 | const absoluteGlob = toPosixPath(nodeModulesPath) + '/' + glob;
54 | const matcher = makeGlobMatcher(absoluteGlob);
55 | return { original: globLists.originalIncluded[index], derived: absoluteGlob, matcher };
56 | });
57 |
58 | const analyzedResults = includedFiles.map(filePath => {
59 | const includedByDefault = includedByDefaultMatcher(filePath);
60 | const includedByGlobs: { original: string; derived: string }[] = [];
61 |
62 | for (const { original, derived, matcher } of globMatchers) {
63 | if (matcher(filePath)) {
64 | includedByGlobs.push({ original, derived });
65 | }
66 | }
67 |
68 | return { filePath, includedByDefault, includedByGlobs };
69 | });
70 |
71 | return analyzedResults;
72 | }
73 |
--------------------------------------------------------------------------------
/src/clean.test.ts:
--------------------------------------------------------------------------------
1 | import { vol } from 'memfs';
2 | import { beforeEach, describe, expect, it } from 'vitest';
3 | import { getMockedFileStructure } from './__test__/getMockedFileStructure.js';
4 | import { clean } from './clean.js';
5 |
6 | const fileStructure = await getMockedFileStructure();
7 |
8 | beforeEach(async () => {
9 | vol.fromNestedJSON(fileStructure);
10 | });
11 |
12 | describe(clean.name, () => {
13 | it('cleans up expected files by default', async () => {
14 | const result = await clean();
15 | expect(result).toMatchInlineSnapshot(`
16 | {
17 | "files": [
18 | "/node_modules/dep1/.npmrc",
19 | "/node_modules/dep2/CHANGELOG.md",
20 | "/node_modules/dep1/__tests__/test1.js",
21 | "/node_modules/dep1/__tests__/test2.js",
22 | "/node_modules/dep1/a-dir/doc.md",
23 | ],
24 | "reducedSize": 5,
25 | "removedEmptyDirs": 3,
26 | }
27 | `);
28 | });
29 |
30 | it('accepts custom globs', async () => {
31 | const result = await clean({ globs: ['**/nonDefaultFile.ext'] });
32 | expect(result).toMatchInlineSnapshot(`
33 | {
34 | "files": [
35 | "/node_modules/dep1/.npmrc",
36 | "/node_modules/dep2/CHANGELOG.md",
37 | "/node_modules/dep4/nonDefaultFile.ext",
38 | "/node_modules/dep1/__tests__/test1.js",
39 | "/node_modules/dep1/__tests__/test2.js",
40 | "/node_modules/dep1/a-dir/doc.md",
41 | ],
42 | "reducedSize": 6,
43 | "removedEmptyDirs": 4,
44 | }
45 | `);
46 | });
47 |
48 | it('allows skipping default globs', async () => {
49 | const result = await clean({ noDefaults: true, globs: ['**/nonDefaultFile.ext'] });
50 | expect(result).toMatchInlineSnapshot(`
51 | {
52 | "files": [
53 | "/node_modules/dep4/nonDefaultFile.ext",
54 | ],
55 | "reducedSize": 1,
56 | "removedEmptyDirs": 1,
57 | }
58 | `);
59 | });
60 |
61 | it('uses custom glob file if provided', async () => {
62 | const customGlobFile = '.custom-glob-file';
63 | vol.fromNestedJSON({ ...fileStructure, [customGlobFile]: '**.md\n**/nonDefaultFile.ext' });
64 |
65 | const result = await clean({ noDefaults: true, globFile: customGlobFile });
66 | expect(result).toMatchInlineSnapshot(`
67 | {
68 | "files": [
69 | "/node_modules/dep2/CHANGELOG.md",
70 | "/node_modules/dep4/nonDefaultFile.ext",
71 | "/node_modules/dep1/a-dir/doc.md",
72 | ],
73 | "reducedSize": 3,
74 | "removedEmptyDirs": 2,
75 | }
76 | `);
77 | });
78 |
79 | it('keeps empty directories if specified', async () => {
80 | const result = await clean({ keepEmpty: true });
81 | expect(result.removedEmptyDirs).toBe(0);
82 | });
83 | });
84 |
--------------------------------------------------------------------------------
/src/clean.ts:
--------------------------------------------------------------------------------
1 | import { SharedOptions, sharedDefaultOptions } from './shared.js';
2 | import { removeEmptyDirs, removeFiles } from './utils/filesystem.js';
3 | import { findFilesByGlobLists, getGlobLists } from './utils/glob.js';
4 |
5 | export const defaultCleanOptions: Required = {
6 | ...sharedDefaultOptions,
7 | dryRun: false,
8 | keepEmpty: false,
9 | };
10 |
11 | export interface CleanResult {
12 | /** List of all files that were cleaned up. */
13 | files: string[];
14 | /** How many bytes of data that was removed when cleaning. */
15 | reducedSize: number;
16 | /** The number of empty directories that were cleaned up after the operation. */
17 | removedEmptyDirs: number;
18 | }
19 |
20 | export interface CleanOptions extends SharedOptions {
21 | /** Whether to skip actually deleting any files and just perform a dry run of the cleaning operation. */
22 | dryRun?: boolean;
23 | /** Whether to keep empty directories around after cleaning. */
24 | keepEmpty?: boolean;
25 | }
26 |
27 | /**
28 | * Removes unnecessary files to reduce the size of a node_modules directory.
29 | * @param options clean options
30 | * @returns summary of the clean operation
31 | */
32 | export async function clean(options: CleanOptions = {}): Promise {
33 | const mergedOptions = { ...defaultCleanOptions, ...options };
34 | const { globs, noDefaults, globFile, directory, dryRun, keepEmpty } = mergedOptions;
35 |
36 | const globLists = await getGlobLists({ globs, noDefaults, globFile });
37 | const files = await findFilesByGlobLists(directory, globLists);
38 | const reducedSize = await removeFiles(files, { dryRun });
39 | const removedEmptyDirs = dryRun || keepEmpty ? 0 : await removeEmptyDirs(files);
40 |
41 | return { files, reducedSize, removedEmptyDirs };
42 | }
43 |
--------------------------------------------------------------------------------
/src/cli/cli.ts:
--------------------------------------------------------------------------------
1 | import { Builtins, Cli } from 'clipanion';
2 | import { createRequire } from 'node:module';
3 | import path from 'node:path';
4 | import { fileDir } from '../utils/filesystem.js';
5 | import { AnalyzeCommand } from './commands/analyze.command.js';
6 | import { CleanCommand } from './commands/clean.command.js';
7 |
8 | const [_node, _app, ...args] = process.argv;
9 | const esmRequire = createRequire(import.meta.url);
10 | const cliDir = fileDir(import.meta.url);
11 | const { name, version } = esmRequire(path.resolve(cliDir, '..', '..', 'package.json'));
12 |
13 | const cli = new Cli({
14 | binaryLabel: name,
15 | binaryVersion: version,
16 | binaryName: name,
17 | });
18 |
19 | cli.register(Builtins.HelpCommand);
20 | cli.register(Builtins.VersionCommand);
21 | cli.register(CleanCommand);
22 | cli.register(AnalyzeCommand);
23 |
24 | cli.runExit(args);
25 |
--------------------------------------------------------------------------------
/src/cli/commands/analyze.command.ts:
--------------------------------------------------------------------------------
1 | import { analyze } from '../../analyze.js';
2 | import { BaseCommand } from '../helpers/base.command.js';
3 |
4 | export class AnalyzeCommand extends BaseCommand {
5 | static override paths = [['analyze']];
6 | static override usage = {
7 | description:
8 | 'Helps determining why a file is included by the clean command without removing any files. Extra globs can be passed as positional args.',
9 | };
10 |
11 | async execute(): Promise {
12 | const analyzeResults = await analyze({
13 | directory: this.directory,
14 | globs: this.globs,
15 | noDefaults: this.noDefaults,
16 | globFile: this.globFile,
17 | });
18 |
19 | console.log(JSON.stringify(analyzeResults, null, 2));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/cli/commands/clean.command.ts:
--------------------------------------------------------------------------------
1 | import { Command, Option } from 'clipanion';
2 | import prettyBytes from 'pretty-bytes';
3 | import prettyMs from 'pretty-ms';
4 | import { clean } from '../../clean.js';
5 | import { BaseCommand } from '../helpers/base.command.js';
6 | import { bold, green, makeLogger, yellow, yesOrNo } from '../utils/terminal.js';
7 |
8 | export class CleanCommand extends BaseCommand {
9 | static override paths = [['clean'], Command.Default];
10 | static override usage = {
11 | description:
12 | 'Default command. Removes unnecessary files to reduce the size of your node_modules directory. Extra globs can be passed as positional args.',
13 | };
14 |
15 | keepEmpty = Option.Boolean('-k,--keep-empty', false, {
16 | description: 'Skips removing empty folders after removing contents',
17 | });
18 |
19 | dryRun = Option.Boolean('-d,--dry-run', false, {
20 | description: 'Logs files that would be removed without removing any files',
21 | });
22 |
23 | silent = Option.Boolean('-s,--silent', false, {
24 | description: 'Does not log anything to console (unless --json is enabled)',
25 | });
26 |
27 | yes = Option.Boolean('-y,--yes', false, {
28 | description: 'Skips the confirmation prompt at the start of the script',
29 | });
30 |
31 | json = Option.Boolean('-j,--json', false, {
32 | description: 'Output results as JSON',
33 | });
34 |
35 | async execute(): Promise {
36 | const logger = makeLogger({ disabled: this.json || this.silent });
37 |
38 | logger.log(bold('clean-modules'), this.dryRun ? yellow('(dry run)') : '');
39 |
40 | if (!this.yes && !this.dryRun) {
41 | const warning = `\nPreparing to clean node_modules at: ${this.directory}\nAre you sure you want to continue? (Y/N) `;
42 | const confirmed = await yesOrNo(yellow(warning));
43 |
44 | if (!confirmed) {
45 | process.exit(0);
46 | }
47 | }
48 |
49 | logger.log('\nCleaning up node_modules...');
50 |
51 | const cleanupStart = new Date().getTime();
52 |
53 | const { files, reducedSize, removedEmptyDirs } = await clean({
54 | globs: this.globs,
55 | noDefaults: this.noDefaults,
56 | globFile: this.globFile,
57 | directory: this.directory,
58 | dryRun: this.dryRun,
59 | });
60 |
61 | const cleanupDuration = new Date().getTime() - cleanupStart;
62 | logger.log(green(`Done in ${prettyMs(cleanupDuration)}!`));
63 |
64 | if (this.json) {
65 | const output: Record = {
66 | removedFiles: files.length,
67 | reducedSize,
68 | removedEmptyDirs,
69 | duration: cleanupDuration,
70 | dryRun: this.dryRun,
71 | };
72 |
73 | console.log(JSON.stringify(output, null, 2));
74 | } else {
75 | logger.log(bold('\nResults:'));
76 | logger.log(
77 | '- size reduced:',
78 | green(
79 | prettyBytes(reducedSize || 0, {
80 | space: true,
81 | minimumFractionDigits: 1,
82 | maximumFractionDigits: 2,
83 | })
84 | )
85 | );
86 | logger.log('- files removed:', green(files.length));
87 | logger.log('- empty dirs removed:', green(removedEmptyDirs || 0));
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/cli/helpers/base.command.ts:
--------------------------------------------------------------------------------
1 | import { Command, Option } from 'clipanion';
2 | import { sharedDefaultOptions } from '../../shared.js';
3 |
4 | /**
5 | * Shared options for all commands.
6 | */
7 | export abstract class BaseCommand extends Command {
8 | directory = Option.String('-D,--directory', sharedDefaultOptions.directory, {
9 | description: 'Path to node_modules',
10 | });
11 |
12 | globFile = Option.String('-f,--glob-file', sharedDefaultOptions.globFile, {
13 | description: 'Path to a custom glob file',
14 | });
15 |
16 | noDefaults = Option.Boolean('-n,--no-defaults', sharedDefaultOptions.noDefaults, {
17 | description: 'Only includes/excludes globs specified by a custom glob file or CLI arguments',
18 | });
19 |
20 | globs = Option.Rest({ name: 'globs' });
21 | }
22 |
--------------------------------------------------------------------------------
/src/cli/utils/terminal.ts:
--------------------------------------------------------------------------------
1 | import readline from 'readline';
2 | import supportsColor from 'supports-color';
3 |
4 | type DisabledConsole = Console;
5 |
6 | /**
7 | * Creates a conditional console logger.
8 | */
9 | export function makeLogger({ disabled }: { disabled: boolean }): Console | DisabledConsole {
10 | if (disabled) {
11 | const noop = () => undefined;
12 | return Object.keys(console).reduce((disabledConsole, key) => {
13 | disabledConsole[key as keyof Console] = noop as any;
14 | return disabledConsole;
15 | }, {} as DisabledConsole);
16 | }
17 |
18 | return console;
19 | }
20 |
21 | /**
22 | * Prompts the user with a yes/no question and waits for the answer.
23 | */
24 | export async function yesOrNo(query: string): Promise {
25 | const rl = readline.createInterface({
26 | input: process.stdin,
27 | output: process.stdout,
28 | });
29 |
30 | return new Promise(resolve =>
31 | rl.question(query, (answer: string) => {
32 | rl.close();
33 | resolve(/ye?s?/i.test(answer));
34 | })
35 | );
36 | }
37 |
38 | /**
39 | * Simple string colorizer factory.
40 | */
41 | function colorizer(colorCode: string) {
42 | if (!supportsColor.stdout) {
43 | return (text: string | number) => String(text);
44 | }
45 |
46 | return (text: string | number) => `\x1b[${colorCode}m${text}\x1b[0m`;
47 | }
48 |
49 | export const bold = colorizer('1');
50 | export const green = colorizer('32');
51 | export const yellow = colorizer('33');
52 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './analyze.js';
2 | export * from './clean.js';
3 | export { type SharedOptions } from './shared.js';
4 |
--------------------------------------------------------------------------------
/src/shared.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { fileDir } from './utils/filesystem.js';
3 |
4 | export const DEFAULT_GLOBS_FILE_PATH = path.resolve(
5 | fileDir(import.meta.url),
6 | '..',
7 | '.cleanmodules-default'
8 | );
9 |
10 | export interface SharedOptions {
11 | /** The directory to clean, usually node_modules. */
12 | directory?: string;
13 | /** Path to a custom glob file. Uses `.cleanmodules` by default. */
14 | globFile?: string;
15 | /** Whether or not to include clean-modules' default globs. */
16 | noDefaults?: boolean;
17 | /** List of custom globs to include or exclude. */
18 | globs?: string[] | undefined;
19 | }
20 |
21 | export const sharedDefaultOptions: Required = {
22 | directory: path.resolve(process.cwd(), 'node_modules'),
23 | globFile: '.cleanmodules',
24 | noDefaults: false,
25 | globs: [],
26 | };
27 |
--------------------------------------------------------------------------------
/src/utils/filesystem.test.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import { vol } from 'memfs';
3 | import path from 'path';
4 | import { afterEach, beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest';
5 | import { getMockedFileStructure } from '../__test__/getMockedFileStructure.js';
6 | import {
7 | crawlDirFast,
8 | crawlDirWithChecks,
9 | fileExists,
10 | forEachDirentAsync,
11 | readDirectory,
12 | removeEmptyDirs,
13 | removeEmptyDirsUp,
14 | removeFiles,
15 | } from './filesystem.js';
16 |
17 | describe('file exists', () => {
18 | beforeEach(() => {
19 | vol.fromNestedJSON({
20 | testdir: {
21 | foo: '.',
22 | bar: '.',
23 | },
24 | });
25 | });
26 |
27 | it('returns true if the file exists', async () => {
28 | const result = await fileExists('testdir/foo');
29 | expect(result).toBe(true);
30 | });
31 |
32 | it('returns false if the file does not exists', async () => {
33 | const result = await fileExists('testdir/foo');
34 | expect(result).toBe(true);
35 | });
36 |
37 | it("throws any error that isn't ENOENT", async () => {
38 | const statSpy = vi.spyOn(fs.promises, 'stat').mockImplementation(() => {
39 | throw new Error('not an ENOENT!');
40 | });
41 |
42 | await expect(fileExists('testdir/foo')).rejects.toThrow('not an ENOENT!');
43 |
44 | statSpy.mockRestore();
45 | });
46 | });
47 |
48 | describe('forEachDirentAsync', () => {
49 | beforeEach(() => {
50 | vol.fromNestedJSON({
51 | testdir: {
52 | foo: { 'foo-bar': '' },
53 | bar: '',
54 | baz: '',
55 | },
56 | });
57 | });
58 |
59 | it('runs action with dirents for each item in a directory', async () => {
60 | const action = vi.fn();
61 | await forEachDirentAsync('testdir', action);
62 |
63 | expect(action).toHaveBeenCalledTimes(3);
64 | expect(action).toHaveBeenCalledWith(
65 | expect.objectContaining({ name: 'foo' }),
66 | expect.anything(),
67 | expect.anything()
68 | );
69 |
70 | expect(action).toHaveBeenCalledWith(
71 | expect.objectContaining({ name: 'bar' }),
72 | expect.anything(),
73 | expect.anything()
74 | );
75 |
76 | expect(action).toHaveBeenCalledWith(
77 | expect.objectContaining({ name: 'baz' }),
78 | expect.anything(),
79 | expect.anything()
80 | );
81 | });
82 | });
83 |
84 | describe('readDirectory', () => {
85 | beforeEach(() => {
86 | vol.fromNestedJSON({ 'parent/empty': { 'foo.txt': '', 'bar.txt': '' } });
87 | });
88 |
89 | it('returns list of files in directory', async () => {
90 | expect(await readDirectory('parent/empty')).toEqual(
91 | expect.arrayContaining(['foo.txt', 'bar.txt'])
92 | );
93 | });
94 |
95 | it('returns empty array if directory does not exist', async () => {
96 | expect(await readDirectory('parent/invalid')).toEqual([]);
97 | });
98 | });
99 |
100 | describe('removeEmptyDirsUp', () => {
101 | beforeEach(() => {
102 | vol.fromNestedJSON({
103 | a0: {
104 | b0: {
105 | c0: {
106 | d0: {
107 | e0: {},
108 | },
109 | },
110 | c1: 'its a file',
111 | },
112 | },
113 | });
114 | });
115 |
116 | it('recursively removes empty directories up in the file tree', async () => {
117 | const checkedDirs = new Set();
118 | await removeEmptyDirsUp(checkedDirs, 'a0/b0/c0/d0/e0');
119 |
120 | expect(Array.from(checkedDirs)).toEqual(['a0/b0/c0/d0/e0', 'a0/b0/c0/d0', 'a0/b0/c0', 'a0/b0']);
121 |
122 | // dirs no longer exist
123 | expect(fs.existsSync('a0/b0/c0/d0/e0')).toEqual(false);
124 | expect(fs.existsSync('a0/b0/c0/d0')).toEqual(false);
125 | expect(fs.existsSync('a0/b0/c0')).toEqual(false);
126 | expect(fs.existsSync('a0/b0')).toEqual(true);
127 | expect(fs.existsSync('a0')).toEqual(true);
128 | });
129 |
130 | it('does not throw if path is invalid', async () => {
131 | const checkedDirs = new Set();
132 | expect(async () => await removeEmptyDirsUp(checkedDirs, 'invalid/path')).not.toThrow();
133 | });
134 | });
135 |
136 | describe('removeEmptyDirs', () => {
137 | beforeEach(async () => {
138 | const fileStructure = await getMockedFileStructure();
139 | vol.fromNestedJSON(fileStructure);
140 | });
141 |
142 | it('cleans up empty parent dirs for provided files', async () => {
143 | const filePaths = [
144 | 'node_modules/dep1/__tests__/test1.js',
145 | 'node_modules/dep1/a-dir/doc.md',
146 | 'node_modules/dep2/CHANGELOG.md',
147 | 'node_modules/dep2/file.js',
148 | ];
149 |
150 | // remove files before testing
151 | for (const filePath of filePaths) {
152 | fs.unlinkSync(filePath);
153 | }
154 |
155 | await removeEmptyDirs(filePaths);
156 |
157 | expect(fs.existsSync('node_modules/dep1/__tests__')).toBe(true); // not empty and not removed
158 | expect(fs.existsSync('node_modules/dep1/a-dir')).toBe(false); // empty and removed
159 | expect(fs.existsSync('node_modules/dep2')).toBe(false); // empty and removed
160 | });
161 |
162 | it('does not throw if path is invalid', async () => {
163 | const filePaths = ['invalid/path/2', 'invalid/path/2'];
164 | expect(async () => await removeEmptyDirs(filePaths)).not.toThrow();
165 | });
166 | });
167 |
168 | describe('crawlDirFast', () => {
169 | beforeEach(() => {
170 | vol.fromNestedJSON({
171 | a0: {
172 | b0: {
173 | c0: {
174 | d0: {
175 | e0: {},
176 | },
177 | d1: {
178 | e0: {
179 | f0: 'f0',
180 | },
181 | },
182 | d2: 'd2',
183 | },
184 | c1: 'c1',
185 | c2: 'c2',
186 | },
187 | },
188 | a1: 'a1',
189 | a2: 'a2',
190 | });
191 | });
192 |
193 | it('appends all nested file paths to the provided array', async () => {
194 | const filePaths: string[] = [];
195 | await crawlDirFast(filePaths, 'a0');
196 | expect(filePaths).toEqual([
197 | path.join('a0', 'b0', 'c1'),
198 | path.join('a0', 'b0', 'c2'),
199 | path.join('a0', 'b0', 'c0', 'd2'),
200 | path.join('a0', 'b0', 'c0', 'd1', 'e0', 'f0'),
201 | ]);
202 | });
203 |
204 | it('does not throw if path is invalid', async () => {
205 | const filePaths: string[] = [];
206 | expect(async () => await crawlDirFast(filePaths, 'invalid/path')).not.toThrow();
207 | });
208 | });
209 |
210 | describe('crawlDirWithChecks', () => {
211 | beforeEach(() => {
212 | vol.fromNestedJSON({
213 | a0: {
214 | b0: {
215 | c0: {
216 | d0: {
217 | e0: {},
218 | },
219 | d1: {
220 | e0: {
221 | f0: 'f0',
222 | },
223 | },
224 | d2: 'd2',
225 | },
226 | c1: 'c1',
227 | c2: 'c2',
228 | },
229 | },
230 | a1: 'a1',
231 | a2: 'a2',
232 | });
233 | });
234 |
235 | it('runs check functions on each nested item', async () => {
236 | const filePaths: string[] = [];
237 | const checkDir = vi.fn(() => false);
238 | const checkFile = vi.fn(() => true);
239 |
240 | await crawlDirWithChecks(filePaths, 'a0', checkDir, checkFile);
241 | expect(checkDir).toHaveBeenCalledTimes(6);
242 | expect(checkFile).toHaveBeenCalledTimes(4);
243 | });
244 |
245 | it('includes full dir without checking remaining items if checkDir returns true', async () => {
246 | const filePaths: string[] = [];
247 | const checkDir = vi.fn(() => true);
248 | const checkFile = vi.fn(() => true);
249 |
250 | await crawlDirWithChecks(filePaths, 'a0', checkDir, checkFile);
251 |
252 | expect(filePaths).toEqual([
253 | path.join('a0', 'b0', 'c1'),
254 | path.join('a0', 'b0', 'c2'),
255 | path.join('a0', 'b0', 'c0', 'd2'),
256 | path.join('a0', 'b0', 'c0', 'd1', 'e0', 'f0'),
257 | ]);
258 | expect(checkDir).toHaveBeenCalledTimes(1);
259 | expect(checkFile).toHaveBeenCalledTimes(0);
260 | });
261 |
262 | it('skips file if checkFile function returns false', async () => {
263 | const filePaths: string[] = [];
264 | const checkDir = vi.fn(() => false);
265 | const checkFile = vi.fn(() => false);
266 |
267 | await crawlDirWithChecks(filePaths, 'a0', checkDir, checkFile);
268 |
269 | expect(filePaths).toEqual([]);
270 | expect(checkFile).toHaveBeenCalledTimes(4);
271 | });
272 |
273 | it('does not throw if path is invalid', async () => {
274 | const filePaths: string[] = [];
275 | const checkDir = vi.fn(() => false);
276 | const checkFile = vi.fn(() => false);
277 |
278 | expect(
279 | async () => await crawlDirWithChecks(filePaths, 'invalid/path', checkDir, checkFile)
280 | ).not.toThrow();
281 | });
282 | });
283 |
284 | describe('removeFiles', () => {
285 | beforeEach(async () => {
286 | const fileStructure = await getMockedFileStructure();
287 | vol.fromNestedJSON(fileStructure);
288 | });
289 |
290 | it('removes files at provided file paths', async () => {
291 | const filePaths = ['node_modules/dep1/__tests__/test1.js', 'node_modules/dep1/a-dir/doc.md'];
292 |
293 | // files are initially there
294 | expect(fs.existsSync(filePaths[0])).toBe(true);
295 | expect(fs.existsSync(filePaths[1])).toBe(true);
296 |
297 | await removeFiles(filePaths);
298 |
299 | // then they are not
300 | expect(fs.existsSync(filePaths[0])).toBe(false);
301 | expect(fs.existsSync(filePaths[1])).toBe(false);
302 | });
303 |
304 | it('does not remove files during dry runs', async () => {
305 | const filePaths = ['node_modules/dep1/__tests__/test1.js', 'node_modules/dep1/a-dir/doc.md'];
306 |
307 | await removeFiles(filePaths, { dryRun: true });
308 |
309 | expect(fs.existsSync(filePaths[0])).toBe(true);
310 | expect(fs.existsSync(filePaths[1])).toBe(true);
311 | });
312 |
313 | it('does not throw if path is invalid', async () => {
314 | const filePaths = ['/invalid/path/2', '/invalid/path/2'];
315 | expect(async () => await removeFiles(filePaths)).not.toThrow();
316 | });
317 | });
318 |
--------------------------------------------------------------------------------
/src/utils/filesystem.ts:
--------------------------------------------------------------------------------
1 | import fs, { Dirent } from 'fs';
2 | import path from 'path';
3 | import { fileURLToPath } from 'url';
4 |
5 | export type DirentAction = (dirent: Dirent) => void;
6 | export type CheckPathFunc = (nextPath: string) => boolean;
7 |
8 | function hasErrorCode(error: any, code: string): boolean {
9 | return error?.code === code;
10 | }
11 |
12 | /**
13 | * Check if a file exists without throwing.
14 | */
15 | export async function fileExists(filePath: string): Promise {
16 | try {
17 | await fs.promises.stat(filePath);
18 |
19 | return true;
20 | } catch (error: unknown) {
21 | if (hasErrorCode(error, 'ENOENT')) {
22 | return false;
23 | }
24 |
25 | throw error;
26 | }
27 | }
28 |
29 | /**
30 | * Asynchronously loop through each file in a directory, passing the dirents for each file to the provided action.
31 | */
32 | export async function forEachDirentAsync(dirPath: string, action: DirentAction): Promise {
33 | let dirFiles: Dirent[] = [];
34 |
35 | try {
36 | dirFiles = await fs.promises.readdir(dirPath, { withFileTypes: true });
37 | } catch (error) {
38 | // do nothing
39 | }
40 |
41 | await Promise.all(dirFiles.map(action));
42 | }
43 |
44 | /**
45 | * Get the file paths inside a directory without throwing.
46 | */
47 | export async function readDirectory(dirPath: string): Promise {
48 | try {
49 | const files = await fs.promises.readdir(dirPath);
50 | return files;
51 | } catch (error: unknown) {
52 | if (hasErrorCode(error, 'ENOENT') || hasErrorCode(error, 'ENOTDIR')) {
53 | return [];
54 | }
55 |
56 | throw error;
57 | }
58 | }
59 |
60 | /**
61 | * Remove empty directories, recursively travelling up in the file until the first non-empty directory is reached.
62 | */
63 | export async function removeEmptyDirsUp(
64 | checkedDirs: Set,
65 | dirPath: string,
66 | count = 0
67 | ): Promise {
68 | if (!checkedDirs.has(dirPath)) {
69 | const files = await readDirectory(dirPath);
70 | const emptyDir = files.length === 0;
71 | checkedDirs.add(dirPath);
72 |
73 | if (emptyDir) {
74 | try {
75 | await fs.promises.rmdir(dirPath);
76 | // biome-ignore lint/style/noParameterAssign: recursive function
77 | count++;
78 | } catch (error) {
79 | // do nothing
80 | }
81 |
82 | const parentDir = path.dirname(dirPath);
83 | // biome-ignore lint/style/noParameterAssign: recursive function
84 | count = await removeEmptyDirsUp(checkedDirs, parentDir, count);
85 | }
86 | }
87 |
88 | return count;
89 | }
90 |
91 | /**
92 | * Deeply removes empty directories for each file path.
93 | * @param filePaths the file paths to remove empty directories for
94 | * @returns the number of empty directories removed
95 | */
96 | export async function removeEmptyDirs(filePaths: string[]): Promise {
97 | let removedEmptyDirs = 0;
98 |
99 | await Promise.all(
100 | filePaths.map(async filePath => {
101 | const removedParentDirs = await removeEmptyDirsUp(new Set(), path.dirname(filePath));
102 | removedEmptyDirs += removedParentDirs;
103 | })
104 | );
105 |
106 | return removedEmptyDirs;
107 | }
108 |
109 | /**
110 | * Find all files in a directory as fast as possible, without any extra checks or validations.
111 | */
112 | export async function crawlDirFast(filePaths: string[], dirPath: string): Promise {
113 | await forEachDirentAsync(dirPath, async dirent => {
114 | const nextPath = dirPath + path.sep + dirent.name;
115 |
116 | if (dirent.isDirectory()) {
117 | await crawlDirFast(filePaths, nextPath);
118 | } else {
119 | filePaths.push(nextPath);
120 | }
121 | });
122 | }
123 |
124 | /**
125 | * Crawl files and validate them against glob patterns.
126 | */
127 | export async function crawlDirWithChecks(
128 | filePaths: string[], // Mutate array to avoid losing speed on spreading
129 | dirPath: string,
130 | checkDir: CheckPathFunc,
131 | checkFile: CheckPathFunc
132 | ): Promise {
133 | await forEachDirentAsync(dirPath, async nextPathDirent => {
134 | const nextPath = dirPath + path.sep + nextPathDirent.name;
135 |
136 | if (nextPathDirent.isDirectory()) {
137 | if (checkDir(nextPath)) {
138 | // If a full directory matches, include all of it.
139 | await crawlDirFast(filePaths, nextPath);
140 | } else {
141 | // Keep recursively checking each directory
142 | await crawlDirWithChecks(filePaths, nextPath, checkDir, checkFile);
143 | }
144 | } else if (checkFile(nextPath)) {
145 | filePaths.push(nextPath);
146 | }
147 | });
148 |
149 | return filePaths;
150 | }
151 |
152 | export type RemoveFilesOptions = {
153 | dryRun?: boolean;
154 | };
155 |
156 | /**
157 | * Removes files and returns the total size of the removed files.
158 | * @param filePaths the file paths to remove
159 | * @param options dryRun: if true, don't actually remove the files
160 | * @returns the total size of the removed files
161 | */
162 | export async function removeFiles(
163 | filePaths: string[],
164 | options: RemoveFilesOptions = {}
165 | ): Promise {
166 | let reducedSize = 0;
167 |
168 | await Promise.all(
169 | filePaths.map(async filePath => {
170 | try {
171 | const fileStats = await fs.promises.stat(filePath);
172 |
173 | if (!options.dryRun) {
174 | await fs.promises.unlink(filePath);
175 | }
176 |
177 | reducedSize += fileStats.size;
178 | } catch (error) {
179 | // do nothing
180 | }
181 | })
182 | );
183 |
184 | return reducedSize;
185 | }
186 |
187 | /**
188 | * Get directory of the file directory, like CommonJS `__dirname`.
189 | * @example const thisFilesDir = fileDir(import.meta.url);
190 | */
191 | export function fileDir(importMetaUrl: string) {
192 | return path.dirname(fileURLToPath(importMetaUrl));
193 | }
194 |
--------------------------------------------------------------------------------
/src/utils/glob.test.ts:
--------------------------------------------------------------------------------
1 | import { vol } from 'memfs';
2 | import path from 'path';
3 | import pm from 'picomatch';
4 | import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
5 | import {
6 | DEFAULT_PICO_OPTIONS,
7 | findFilesByGlobLists,
8 | formatGlob,
9 | GlobLists,
10 | initGlobLists,
11 | makeGlobMatcher,
12 | mergeGlobLists,
13 | optimizeGlobLists,
14 | optimizeGlobs,
15 | parseGlobsFile,
16 | processGlobs,
17 | toAbsoluteGlobLists,
18 | updateGlobLists,
19 | wrapGlobs,
20 | } from './glob.js';
21 | import { getMockedFileStructure } from '../__test__/getMockedFileStructure.js';
22 |
23 | describe('makeGlobMatcher', () => {
24 | it('creates a picomatch globber with default options', () => {
25 | const pattern = '**/**';
26 |
27 | const globber = makeGlobMatcher(pattern);
28 |
29 | expect(globber).toBeInstanceOf(Function);
30 | expect(globber).toHaveProperty('name', 'matcher');
31 | });
32 | });
33 |
34 | describe('updateGlobLists', () => {
35 | const mockGlobLists: GlobLists = {
36 | ...initGlobLists(),
37 | included: ['foo'],
38 | includedDirs: ['bar'],
39 | excluded: ['baz'],
40 | };
41 |
42 | it('runs passed function for correct files', () => {
43 | const mockFn = vi.fn();
44 |
45 | updateGlobLists(mockGlobLists, mockFn);
46 |
47 | expect(mockFn).toHaveBeenCalledWith(mockGlobLists.included, 'included');
48 | expect(mockFn).toHaveBeenCalledWith(mockGlobLists.includedDirs, 'includedDirs');
49 | expect(mockFn).toHaveBeenCalledWith(mockGlobLists.excluded, 'excluded');
50 | });
51 |
52 | it('applies result of passed function to each field', () => {
53 | const result = updateGlobLists(mockGlobLists, (globs, key) => [...globs, key]);
54 | const expectedResult: GlobLists = {
55 | ...mockGlobLists,
56 | included: [...mockGlobLists.included, 'included'],
57 | includedDirs: [...(mockGlobLists.includedDirs || []), 'includedDirs'],
58 | excluded: [...mockGlobLists.excluded, 'excluded'],
59 | };
60 |
61 | expect(result).toEqual(expectedResult);
62 | });
63 | });
64 |
65 | describe('mergeGlobLists', () => {
66 | it('merges glob lists', () => {
67 | const result = mergeGlobLists(
68 | {
69 | ...initGlobLists(),
70 | included: ['foo'],
71 | includedDirs: ['foo'],
72 | excluded: ['foo'],
73 | },
74 | {
75 | ...initGlobLists(),
76 | included: ['bar'],
77 | includedDirs: ['bar'],
78 | excluded: ['bar'],
79 | }
80 | );
81 |
82 | expect(result).toEqual({
83 | ...initGlobLists(),
84 | included: ['foo', 'bar'],
85 | includedDirs: ['foo', 'bar'],
86 | excluded: ['foo', 'bar'],
87 | });
88 | });
89 | });
90 |
91 | describe('toAbsoluteGlobLists', () => {
92 | it('prepends globs with absolute paths on all platforms', () => {
93 | const result = toAbsoluteGlobLists(
94 | {
95 | ...initGlobLists(),
96 | included: ['bar'],
97 | includedDirs: ['bar'],
98 | excluded: ['bar'],
99 | },
100 | '/foo'
101 | );
102 |
103 | expect(result).toEqual({
104 | ...initGlobLists(),
105 | included: ['/foo/bar'],
106 | includedDirs: ['/foo/bar'],
107 | excluded: ['/foo/bar'],
108 | });
109 | });
110 | });
111 |
112 | describe('wrapGlobs', () => {
113 | it('wraps globs into a single glob', () => {
114 | const result = wrapGlobs(['**/foo', '**/bar', '*/baz']);
115 | expect(result).toEqual('@((**/foo)|(**/bar)|(*/baz))');
116 | });
117 |
118 | it('prepends an optional prefix to the result', () => {
119 | const result = wrapGlobs(['**/foo', '**/bar', '*/baz'], 'hello');
120 | expect(result).toEqual('hello@((**/foo)|(**/bar)|(*/baz))');
121 | });
122 | });
123 |
124 | describe('optimizeGlobs', () => {
125 | it('splits globs by leading characters and merges into two globs', () => {
126 | const result = optimizeGlobs(['**/some', '*/where', 'over', '**/the', '/rainbow']);
127 | expect(result).toEqual(['**/@((some)|(the))', '@((*/where)|(over)|(/rainbow))']);
128 | });
129 |
130 | it('normalizes leading globstars', () => {
131 | const result = optimizeGlobs(['**/**/**/one', '**/**/two', '**/three', '/**/four']);
132 | expect(result).toEqual(['**/@((one)|(two)|(three)|(four))']);
133 | });
134 | });
135 |
136 | describe('optimizeGlobLists', () => {
137 | it('splits globs by leading characters and merges into two globs', () => {
138 | const result = optimizeGlobLists({
139 | ...initGlobLists(),
140 | included: ['**/wrapMe/**', '**/andMe/**', 'notMe/**', '*/andNotMe.js', '/andNotMeEither.ts'],
141 | includedDirs: ['**/wrapMe', '**/andMe', 'notMe'],
142 | excluded: ['**/wrapMe/**', '**/andMe/**', 'notMe/**'],
143 | });
144 |
145 | expect(result).toMatchInlineSnapshot(`
146 | {
147 | "excluded": [
148 | "**/@((wrapMe/**)|(andMe/**))",
149 | "@((notMe/**))",
150 | ],
151 | "included": [
152 | "**/@((wrapMe/**)|(andMe/**))",
153 | "@((notMe/**)|(*/andNotMe.js)|(/andNotMeEither.ts))",
154 | ],
155 | "includedDirs": [
156 | "**/@((wrapMe)|(andMe))",
157 | "@((notMe))",
158 | ],
159 | "originalIncluded": [],
160 | }
161 | `);
162 | });
163 | });
164 |
165 | describe('formatGlob', () => {
166 | it('trims globs', () => {
167 | const result = formatGlob(' foo/** ');
168 | expect(result).toEqual('**/foo/**');
169 | });
170 |
171 | it('adds globstars to globs not starting with a slash', () => {
172 | const result = formatGlob('test.ts');
173 | expect(result).toEqual('**/test.ts');
174 | });
175 |
176 | it('replaces escaped leading exclamation marks', () => {
177 | const result = formatGlob('\\!(*.d).ts');
178 | expect(result).toEqual('**/!(*.d).ts');
179 | });
180 |
181 | it('removes leading slashes', () => {
182 | const result = formatGlob('/path/to/file');
183 | expect(result).toEqual('path/to/file');
184 | });
185 |
186 | it('appends globstars to directory globs', () => {
187 | const result = formatGlob('/path/to/directory/');
188 | expect(result).toEqual('path/to/directory/**');
189 | });
190 | });
191 |
192 | describe('processGlobs', () => {
193 | it('formats globs and splits them into include/exclude glob lists', () => {
194 | const result = processGlobs(['**/test', '!test.js', '**/path/to/directory/', '*.ext']);
195 | expect(result).toMatchInlineSnapshot(`
196 | {
197 | "excluded": [
198 | "**/test.js",
199 | ],
200 | "included": [
201 | "**/**/test",
202 | "**/**/path/to/directory/**",
203 | "**/*.ext",
204 | ],
205 | "includedDirs": [
206 | "**/**/path/to/directory",
207 | ],
208 | "originalIncluded": [
209 | "**/test",
210 | "**/path/to/directory/",
211 | "*.ext",
212 | ],
213 | }
214 | `);
215 | });
216 |
217 | it('removes trailing globstars from dir globs', () => {
218 | const result = processGlobs(['**/foo/**', '/bar/**']);
219 | expect(result.includedDirs).toEqual(['**/**/foo', 'bar']);
220 | });
221 |
222 | it('filters empty strings', () => {
223 | const result = processGlobs(['foo', '', '', '', 'bar']);
224 | expect(result.included).toEqual(['**/foo', '**/bar']);
225 | });
226 |
227 | it('keeps original inclusion globs', () => {
228 | const original = ['**/test', '**/path/to/directory/', '*.ext'];
229 | const result = processGlobs(original);
230 | expect(result.originalIncluded).toEqual(original);
231 | });
232 | });
233 |
234 | describe('parseGlobsFile', () => {
235 | const globFilePath = process.cwd() + '/.cleanmodules';
236 |
237 | it('loads globs from a glob file', async () => {
238 | const globFile = `
239 | # this is a comment
240 | __test__/
241 | !goodstuff/
242 |
243 | */dep/Makefile
244 |
245 | *.ts
246 | !*.d.ts
247 | *.ext
248 | `;
249 |
250 | vol.fromNestedJSON({ [globFilePath]: globFile });
251 | const result = await parseGlobsFile(globFilePath);
252 |
253 | expect(result).toMatchInlineSnapshot(`
254 | {
255 | "excluded": [
256 | "**/goodstuff/**",
257 | "**/*.d.ts",
258 | ],
259 | "included": [
260 | "**/__test__/**",
261 | "**/*/dep/Makefile",
262 | "**/*.ts",
263 | "**/*.ext",
264 | ],
265 | "includedDirs": [
266 | "**/__test__",
267 | ],
268 | "originalIncluded": [
269 | "__test__/",
270 | "*/dep/Makefile",
271 | "*.ts",
272 | "*.ext",
273 | ],
274 | }
275 | `);
276 | });
277 |
278 | it('removes comments', async () => {
279 | const globFile = `
280 | # this is a comment
281 | # this too
282 | # and this
283 | path/to/something
284 | `;
285 |
286 | vol.fromNestedJSON({ [globFilePath]: globFile });
287 | const result = await parseGlobsFile(globFilePath);
288 | expect(result.included).toEqual(['**/path/to/something']);
289 | expect(result.excluded).toEqual([]);
290 | });
291 |
292 | it('removes empty lines', async () => {
293 | const globFile = `
294 |
295 | path/to/something
296 |
297 | `;
298 |
299 | vol.fromNestedJSON({ [globFilePath]: globFile });
300 | const result = await parseGlobsFile(globFilePath);
301 | expect(result.included).toEqual(['**/path/to/something']);
302 | expect(result.excluded).toEqual([]);
303 | });
304 |
305 | it('adds lines starting with an exclamation point to excluded globs', async () => {
306 | const globFile = `
307 | !excludeMe
308 | `;
309 |
310 | vol.fromNestedJSON({ [globFilePath]: globFile });
311 | const result = await parseGlobsFile(globFilePath);
312 | expect(result.included).toEqual([]);
313 | expect(result.excluded).toEqual(['**/excludeMe']);
314 | });
315 | });
316 |
317 | describe('findFilesByGlobLists', async () => {
318 | const fileStructure = await getMockedFileStructure();
319 | const nodeModulesPath = 'node_modules';
320 |
321 | beforeEach(async () => {
322 | vol.fromNestedJSON(fileStructure);
323 | });
324 |
325 | it('includes dirs', async () => {
326 | const result = await findFilesByGlobLists(nodeModulesPath, {
327 | ...initGlobLists(),
328 | includedDirs: ['**/__tests__', '**/dep3'],
329 | });
330 |
331 | expect(result).toEqual([
332 | path.join('node_modules', 'dep1', '__tests__', 'test1.js'),
333 | path.join('node_modules', 'dep1', '__tests__', 'test2.js'),
334 | path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
335 | ]);
336 | });
337 |
338 | it('includes files', async () => {
339 | const result = await findFilesByGlobLists(nodeModulesPath, {
340 | ...initGlobLists(),
341 | included: ['**/deeply/nested/file.ext', '**/dep4/**'],
342 | });
343 |
344 | expect(result).toEqual([
345 | path.join('node_modules', 'dep4', 'nonDefaultFile.ext'),
346 | path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
347 | ]);
348 | });
349 |
350 | it('can exclude files and dirs by glob patterns', async () => {
351 | const result = await findFilesByGlobLists(nodeModulesPath, {
352 | ...initGlobLists(),
353 | included: ['**/*.js'],
354 | excluded: ['**/test*.js'],
355 | });
356 |
357 | expect(result).toEqual([path.join('node_modules', 'dep2', 'file.js')]);
358 | });
359 | });
360 |
--------------------------------------------------------------------------------
/src/utils/glob.ts:
--------------------------------------------------------------------------------
1 | import { promises as fsAsync } from 'fs';
2 | import path from 'path';
3 | import pm, { PicomatchOptions } from 'picomatch';
4 | import { DEFAULT_GLOBS_FILE_PATH } from '../shared.js';
5 | import { crawlDirWithChecks, fileExists } from './filesystem.js';
6 |
7 | export function initGlobLists(): GlobLists {
8 | return { excluded: [], included: [], includedDirs: [], originalIncluded: [] };
9 | }
10 |
11 | export const DEFAULT_PICO_OPTIONS: Partial = {
12 | dot: true,
13 | nocase: true,
14 | strictSlashes: true,
15 | };
16 |
17 | export interface GlobberPicoOptions {
18 | dot?: boolean;
19 | regex?: boolean;
20 | nocase?: boolean;
21 | ignore?: string | string[];
22 | cwd?: string;
23 | }
24 |
25 | export type GlobFunc = (filePath: string, test?: boolean) => boolean;
26 |
27 | /**
28 | * Creates a picomatch matcher from a set of globs.
29 | */
30 | export function makeGlobMatcher(
31 | globs: string | string[],
32 | picoOptions?: GlobberPicoOptions
33 | ): GlobFunc {
34 | return pm(globs, { ...DEFAULT_PICO_OPTIONS, ...picoOptions });
35 | }
36 |
37 | export interface GlobLists {
38 | excluded: string[];
39 | included: string[];
40 | includedDirs: string[];
41 | originalIncluded: string[];
42 | }
43 |
44 | /**
45 | * Runs an action on all editable lists in a GlobLists object, and returns the updated object.
46 | */
47 | export function updateGlobLists(
48 | globLists: GlobLists,
49 | updateFunc: (globs: string[], key: keyof GlobLists) => string[]
50 | ): GlobLists {
51 | const { included, includedDirs, excluded } = globLists;
52 |
53 | return {
54 | ...globLists,
55 | included: updateFunc(included, 'included'),
56 | includedDirs: includedDirs ? updateFunc(includedDirs, 'includedDirs') : includedDirs,
57 | excluded: updateFunc(excluded, 'excluded'),
58 | };
59 | }
60 |
61 | /**
62 | * Merges all arrays of two GlobLists objects.
63 | */
64 | export function mergeGlobLists(globListsA: GlobLists, globListsB: GlobLists): GlobLists {
65 | return {
66 | ...updateGlobLists(globListsA, (globs, key) => [...globs, ...(globListsB[key] || [])]),
67 | originalIncluded: [...globListsA.originalIncluded, ...globListsB.originalIncluded],
68 | };
69 | }
70 |
71 | /** Replaces path with forward slashes as separators if necessary. Globs should always have POSIX separators, even on Windows. */
72 | export function toPosixPath(pathStr: string): string {
73 | return path.sep === '/' ? pathStr : pathStr.replace(/\\/g, '/');
74 | }
75 |
76 | /**
77 | * Prepends an absolute path to all editable lists in a GlobLists object.
78 | */
79 | export function toAbsoluteGlobLists(
80 | globLists: GlobLists,
81 | absoluteNodeModulesPath: string
82 | ): GlobLists {
83 | const absolutePathWithPosixSeparator = toPosixPath(absoluteNodeModulesPath);
84 |
85 | return updateGlobLists(globLists, globs =>
86 | globs.map(glob => absolutePathWithPosixSeparator + '/' + glob)
87 | );
88 | }
89 |
90 | /**
91 | * Wraps globs into one conditional glob (like `@((one/glob/path)|(another/glob/path))`).
92 | */
93 | export function wrapGlobs(globs: string[], prefix?: string): string {
94 | return `${prefix || ''}@(${globs.map(glob => '(' + glob + ')').join('|')})`;
95 | }
96 |
97 | const GLOBSTAR_START_REGEX = /^(\/?\*\*\/)+/;
98 |
99 | /**
100 | * Optimizes globs by merging them into groups and removing unnecessary globstars.
101 | */
102 | export function optimizeGlobs(globs: string[]): string[] {
103 | const globstarStartGlobs: string[] = [];
104 | const fixedPathGlobs: string[] = [];
105 |
106 | for (const glob of globs) {
107 | if (glob.match(GLOBSTAR_START_REGEX)) {
108 | globstarStartGlobs.push(glob);
109 | } else {
110 | fixedPathGlobs.push(glob);
111 | }
112 | }
113 |
114 | const result: string[] = [];
115 |
116 | if (globstarStartGlobs.length) {
117 | const withoutGlobstar = globstarStartGlobs.map(glob => glob.replace(GLOBSTAR_START_REGEX, ''));
118 | result.push(wrapGlobs(withoutGlobstar, '**/'));
119 | }
120 |
121 | if (fixedPathGlobs.length) {
122 | result.push(wrapGlobs(fixedPathGlobs));
123 | }
124 |
125 | return result;
126 | }
127 |
128 | /**
129 | * Runs optimizeGlobs() on all editable lists in a GlobLists object.
130 | */
131 | export function optimizeGlobLists(globLists: GlobLists): GlobLists {
132 | return updateGlobLists(globLists, optimizeGlobs);
133 | }
134 |
135 | const EXCLAMATION_START = /^\s*!/; // Globs starting with !
136 | const DIR_GLOB_REGEX = /\/\**$/; // Globs ending with /, /* or /**
137 | const EXCLUDED_GLOB_REGEX = /^!/; // Globs starting with !
138 | const ESCAPED_NEGATIVE_GLOB_REGEX = /^\\!/; // Globs starting with \!
139 | const NOT_FIXED_START_GLOB_REGEX = /^([^/])/; // Globs not starting with /
140 | const FIXED_START_GLOB_REGEX = /^\//; // Globs starting with /
141 |
142 | /**
143 | * Formats and standardizes globs to make them suitable for picomatch.
144 | */
145 | export function formatGlob(glob: string): string {
146 | return glob
147 | .trim()
148 | .replace(EXCLUDED_GLOB_REGEX, '') // remove leading exclamation marks
149 | .replace(ESCAPED_NEGATIVE_GLOB_REGEX, '!') // replace escaped leading exclamation mark with real one
150 | .replace(DIR_GLOB_REGEX, '/**') // normalize dir globs to all end with /**
151 | .replace(NOT_FIXED_START_GLOB_REGEX, '**/$1') // add globstars to globs not starting with /
152 | .replace(FIXED_START_GLOB_REGEX, ''); // remove fixed path indicators
153 | }
154 |
155 | /**
156 | * Parses clean-modules/gitignore-like globs and converts them into picomatch compatible globs.
157 | */
158 | export function processGlobs(globs: string[]): GlobLists {
159 | const globLists = initGlobLists();
160 |
161 | for (const glob of globs) {
162 | const isExcluded = !!glob.match(EXCLAMATION_START);
163 | const formattedGlob = formatGlob(glob);
164 |
165 | if (!formattedGlob) {
166 | continue;
167 | }
168 |
169 | if (isExcluded) {
170 | globLists.excluded.push(formattedGlob);
171 | } else {
172 | if (formattedGlob.endsWith('/**')) {
173 | globLists.includedDirs.push(formattedGlob.replace(DIR_GLOB_REGEX, ''));
174 | }
175 |
176 | globLists.included.push(formattedGlob);
177 | globLists.originalIncluded.push(glob.trim());
178 | }
179 | }
180 |
181 | return globLists;
182 | }
183 |
184 | const COMMENT_OR_EMPTY_REGEX = /^\s*(#|$)/;
185 |
186 | /**
187 | * Parses a clean-modules glob file, filtering comments and separating globs that should be included or excluded.
188 | */
189 | export async function parseGlobsFile(filePath: string): Promise {
190 | let fileContents: string;
191 |
192 | try {
193 | fileContents = (await fsAsync.readFile(filePath, { encoding: 'utf-8' })).toString() || '';
194 | } catch (error) {
195 | console.error(`Failed to read glob file (${filePath})`);
196 | throw error;
197 | }
198 |
199 | const fileGlobs =
200 | fileContents.split(/\r?\n/).filter(line => !line.match(COMMENT_OR_EMPTY_REGEX)) || [];
201 |
202 | return processGlobs(fileGlobs);
203 | }
204 |
205 | /**
206 | * Parses clean-modules' default glob file.
207 | */
208 | export async function parseDefaultGlobsFile(): Promise {
209 | return parseGlobsFile(DEFAULT_GLOBS_FILE_PATH);
210 | }
211 |
212 | export interface GetGlobListsOptions {
213 | noDefaults?: boolean | undefined;
214 | globFile?: string | undefined;
215 | globs?: string[] | undefined;
216 | }
217 |
218 | /**
219 | * Parses and combines globs from all possible sources.
220 | */
221 | export async function getGlobLists({
222 | noDefaults,
223 | globFile,
224 | globs,
225 | }: GetGlobListsOptions): Promise {
226 | const globListsToMerge: GlobLists[] = [];
227 |
228 | if (!noDefaults) {
229 | const defaultGlobLists = await parseDefaultGlobsFile();
230 | globListsToMerge.push(defaultGlobLists);
231 | }
232 |
233 | if (globFile && (await fileExists(globFile))) {
234 | const userFileGlobLists = await parseGlobsFile(globFile);
235 | globListsToMerge.push(userFileGlobLists);
236 | }
237 |
238 | if (globs?.length) {
239 | const argGlobsLists = processGlobs(globs);
240 | globListsToMerge.push(argGlobsLists);
241 | }
242 |
243 | return globListsToMerge.reduce(
244 | (mergedGlobLists, globLists) => mergeGlobLists(mergedGlobLists, globLists),
245 | initGlobLists()
246 | );
247 | }
248 |
249 | /**
250 | * Finds all files matching the given glob lists in the given directory.
251 | * @param directory the directory to search in
252 | * @param globLists the glob lists to match against
253 | * @returns a promise that resolves to an array of matching file paths
254 | */
255 | export async function findFilesByGlobLists(
256 | directory: string,
257 | globLists: GlobLists
258 | ): Promise {
259 | const { included, includedDirs, excluded } = toAbsoluteGlobLists(
260 | optimizeGlobLists(globLists),
261 | directory
262 | );
263 |
264 | const picoOptions = { ignore: excluded };
265 | const checkDir = includedDirs?.length ? makeGlobMatcher(includedDirs, picoOptions) : () => false;
266 | const checkFile = makeGlobMatcher(included, picoOptions);
267 |
268 | let filesToRemove = await crawlDirWithChecks([], directory, checkDir, checkFile);
269 |
270 | if (excluded.length) {
271 | // make another pass to ensure that files included by dir globs are
272 | // matched with excluded globs too
273 | filesToRemove = filesToRemove.filter(file => checkFile(file));
274 | }
275 |
276 | return filesToRemove;
277 | }
278 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "extends": ["@tsconfig/node14/tsconfig.json"],
4 | "compilerOptions": {
5 | "outDir": "dist",
6 | "strict": true,
7 | "allowSyntheticDefaultImports": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "exactOptionalPropertyTypes": true,
10 | "noFallthroughCasesInSwitch": true,
11 | "noImplicitReturns": true,
12 | "noImplicitOverride": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup';
2 |
3 | export default defineConfig({
4 | format: ['cjs', 'esm'],
5 | entry: ['src/index.ts', 'src/cli/cli.ts'],
6 | outDir: 'dist',
7 | target: 'node14',
8 | splitting: true,
9 | sourcemap: false,
10 | clean: true,
11 | shims: true,
12 | dts: true,
13 | });
14 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitest/config';
2 |
3 | export default defineConfig({
4 | test: {
5 | clearMocks: true,
6 | setupFiles: ['vitest.setup.ts'],
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/vitest.setup.ts:
--------------------------------------------------------------------------------
1 | import { vol } from 'memfs';
2 | import { afterEach, expect, vi } from 'vitest';
3 | import { pathSerializer } from './src/__test__/path.serializer.js';
4 |
5 | vi.mock('fs');
6 | vi.mock('fs/promises');
7 |
8 | expect.addSnapshotSerializer(pathSerializer);
9 |
10 | afterEach(() => {
11 | vol.reset();
12 | });
13 |
--------------------------------------------------------------------------------