/**", "**/node_modules/**"],
+ "smartStep": true,
+ "type": "node"
+ }
+ ],
+ "version": "2.0.0"
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 2cd1c9e51..b8153ef35 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,11 +1,18 @@
{
- "files.exclude": {
- "**/*.d.ts": true,
- "**/*.js.map": true,
- "**/*.js": { "when": "$(basename).ts" }
- },
- "editor.defaultFormatter": "esbenp.prettier-vscode",
- "editor.formatOnSave": true,
- "eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
- "typescript.tsdk": "node_modules/typescript/lib"
+ "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" },
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true,
+ "editor.rulers": [80],
+ "eslint.probe": [
+ "javascript",
+ "javascriptreact",
+ "json",
+ "jsonc",
+ "markdown",
+ "typescript",
+ "typescriptreact",
+ "yaml"
+ ],
+ "eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
+ "typescript.tsdk": "node_modules/typescript/lib"
}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 2b80fe2e1..4f72f7a1a 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,11 +1,11 @@
{
- "version": "2.0.0",
- "command": "tsc",
- "args": ["-w"],
- "isBackground": true,
- "presentation": {
- "reveal": "silent"
- },
- "problemMatcher": "$tsc-watch",
- "type": "shell"
+ "args": ["-w"],
+ "command": "tsc",
+ "isBackground": true,
+ "presentation": {
+ "reveal": "silent"
+ },
+ "problemMatcher": "$tsc-watch",
+ "type": "shell",
+ "version": "2.0.0"
}
diff --git a/LICENSE.md b/LICENSE.md
index f7f743864..08520a1e2 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,7 +1,20 @@
-MIT License
+# MIT License
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 3d1a1d08e..a7a4dca80 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,20 @@
TypeStat
-Converts JavaScript to TypeScript and TypeScript to better TypeScript.
+Converts JavaScript to TypeScript and TypeScript to better TypeScript. ๐งซ
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
## Usage
TypeStat is a CLI utility that modifies TypeScript types in existing code.
@@ -55,4 +55,40 @@ To get a deeper understanding of TypeStat, read the following docs pages in orde
## Development
-See [Development.md](./docs/Development.md). ๐
+See [`.github/CONTRIBUTING.md`](./.github/CONTRIBUTING.md), then [`.github/DEVELOPMENT.md`](./.github/DEVELOPMENT.md) for general tooling documentation.
+For understanding the project, see `./docs` in general, and especially [`./docs/Architecture.md`](./docs/Architecture.md).
+Thanks! ๐
+
+## Contributors
+
+
+
+
+
+
+
+
+
+
+
+
+
+> ๐ This package is based on [@JoshuaKGoldberg](https://github.com/JoshuaKGoldberg)'s [TypeStat](https://github.com/JoshuaKGoldberg/TypeStat).
diff --git a/babel.config.js b/babel.config.js
deleted file mode 100644
index 6cac2cc99..000000000
--- a/babel.config.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = {
- plugins: ["@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-optional-chaining"],
- presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"],
-};
diff --git a/bin/typestat b/bin/typestat
index 2c8aba371..ccae6c59d 100644
--- a/bin/typestat
+++ b/bin/typestat
@@ -3,12 +3,12 @@
const { runCli } = require("../src/cli/runCli");
runCli(process.argv)
- .then((resultStatus) => {
- if (resultStatus !== 0) {
- process.exitCode = 1;
- }
- })
- .catch((error) => {
- console.error("Error in TypeStat: " + error);
- process.exitCode = 1;
- });
+ .then((resultStatus) => {
+ if (resultStatus !== 0) {
+ process.exitCode = 1;
+ }
+ })
+ .catch((error) => {
+ console.error("Error in TypeStat: " + error);
+ process.exitCode = 1;
+ });
diff --git a/cspell.json b/cspell.json
new file mode 100644
index 000000000..5a42eb395
--- /dev/null
+++ b/cspell.json
@@ -0,0 +1,38 @@
+{
+ "dictionaries": ["typescript"],
+ "ignorePaths": [
+ ".github",
+ "CHANGELOG.md",
+ "coverage",
+ "lib",
+ "node_modules",
+ "pnpm-lock.yaml"
+ ],
+ "words": [
+ "arrayify",
+ "automerge",
+ "automutate",
+ "automutator",
+ "endlines",
+ "execa",
+ "extensionless",
+ "hackily",
+ "globbed",
+ "IIFE",
+ "inferables",
+ "intrinsic",
+ "jscodeshift",
+ "knip",
+ "logfile",
+ "nodenext",
+ "packagejson",
+ "phenomnomnominal",
+ "predeclared",
+ "slashify",
+ "tsquery",
+ "tsup",
+ "typestat",
+ "undefineds",
+ "uniquify"
+ ]
+}
diff --git a/dependabot.yml b/dependabot.yml
deleted file mode 100644
index 9b580b8ca..000000000
--- a/dependabot.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-version: 2
-updates:
- - package-ecosystem: "npm"
- directory: "/"
- schedule:
- interval: "daily"
diff --git a/docs/Architecture.md b/docs/Architecture.md
index ebb85a336..ea351683e 100644
--- a/docs/Architecture.md
+++ b/docs/Architecture.md
@@ -3,10 +3,10 @@
This document goes over how TypeStart runs and generates fixes.
Before reading this, you should read:
-* TypeStat's [README.md](../README.md)
-* Documentation on the types of [fixes](./Fixes.md)
-* Recommended TypeStat [usage](./Usage.md)
-* [automutate](https://github.com/automutate/automutate) and [automutate-tests](https://github.com/automutate/automutate)
+- TypeStat's [README.md](../README.md)
+- Documentation on the types of [fixes](./Fixes.md)
+- Recommended TypeStat [usage](./Usage.md)
+- [automutate](https://github.com/automutate/automutate) and [automutate-tests](https://github.com/automutate/automutate)
## Runtime
@@ -40,8 +40,8 @@ Each round of mutations in the core mutation provider roughly:
1. Records the starting time
2. Creates a set of TypeScript language services
3. For each file to be visited:
- 1. Retrieves file mutations for that file
- 2. If more than 100 mutations have been collected, or mutations have been collected and it's been more than 10 seconds since the round started, stops the round
+ 1. Retrieves file mutations for that file
+ 2. If more than 100 mutations have been collected, or mutations have been collected and it's been more than 10 seconds since the round started, stops the round
Subsequent rounds will pick up where the previous round left off.
For example, given files `a.ts`, `b.ts`, and `c.ts` in order,
@@ -52,19 +52,19 @@ TypeStat crashing before a round is complete shouldn't lose all accumulated muta
Once TypeStat has visited each file, it will either:
-* Stop if no file had mutations applied
-* Restart _(and reload language services)_ if any file had mutations applied
+- Stop if no file had mutations applied
+- Restart _(and reload language services)_ if any file had mutations applied
#### File Mutations
For each file it visits, [`findMutationsInFile`](../src/runtime/findMutationsInFile.ts)
will attempt to apply [built-in file mutators](../src/mutators/builtIn/index.ts):
-* [`fixIncompleteTypes`](../src/mutators/builtIn/fixIncompleteTypes/README.md)
-* [`fixMissingProperties`](../src/mutators/builtIn/fixMissingProperties/README.md)
-* [`fixNoImplicitAny`](../src/mutators/builtIn/fixNoImplicitAny/README.md)
-* [`fixNoImplicitThis`](../src/mutators/builtIn/fixNoImplicitThis/README.md)
-* [`fixStrictNonNullAssertions`](../src/mutators/builtIn/fixStrictNonNullAssertions/README.md)
+- [`fixIncompleteTypes`](../src/mutators/builtIn/fixIncompleteTypes/README.md)
+- [`fixMissingProperties`](../src/mutators/builtIn/fixMissingProperties/README.md)
+- [`fixNoImplicitAny`](../src/mutators/builtIn/fixNoImplicitAny/README.md)
+- [`fixNoImplicitThis`](../src/mutators/builtIn/fixNoImplicitThis/README.md)
+- [`fixStrictNonNullAssertions`](../src/mutators/builtIn/fixStrictNonNullAssertions/README.md)
Each fixer targets a general range of potential type improvements and contains a series of sub-fixers that target individual improvements.
For example, `fixIncompleteTypes` contains a `fixIncompleteParameterTypes` fixer that fills in incomplete types for parameters.
@@ -97,8 +97,8 @@ The `mutators` directory figures out which types should be modified, then `mutat
We should note two common pieces of terminology used in this directory:
-* **"Flags"** refers to type nodes for primitive types, such as `boolean`
-* **"Types"** refers to rich (non-primitive) types, such as `MyClass`
+- **"Flags"** refers to type nodes for primitive types, such as `boolean`
+- **"Types"** refers to rich (non-primitive) types, such as `MyClass`
### `options`
diff --git a/docs/Cleanups.md b/docs/Cleanups.md
index 9af1c97f5..b0410f19b 100644
--- a/docs/Cleanups.md
+++ b/docs/Cleanups.md
@@ -8,9 +8,9 @@ These all default to `false` but can be enabled by being set to `true`.
```json
{
- "cleanups": {
- "suppressTypeErrors": true
- }
+ "cleanups": {
+ "suppressTypeErrors": true
+ }
}
```
diff --git a/docs/Custom Mutators.md b/docs/Custom Mutators.md
index fbb214c45..3fcd1b688 100644
--- a/docs/Custom Mutators.md
+++ b/docs/Custom Mutators.md
@@ -9,9 +9,7 @@ Use the `-m`/`--mutators` CLI flag and/or `mutators` configuration setting to ad
```json
{
- "mutators": [
- "my-mutator-module"
- ]
+ "mutators": ["my-mutator-module"]
}
```
@@ -31,8 +29,8 @@ import { Mutation } from "automutate";
import { FileMutationsRequest } from "typestat";
export const mutator = (request: FileMutationsRequest): Mutation[] => {
- // TODO: Implement!
- return [];
+ // TODO: Implement!
+ return [];
};
```
@@ -44,14 +42,16 @@ For example, this mutator will add a `/* foo */` mutation at the beginning of ea
const prefix = "/* foo */ ";
module.exports.fileMutator = (request) => {
- return request.sourceFile.getFullText().startsWith(prefix)
- ? []
- : [{
- insertion: prefix,
- range: {
- begin: 0,
- },
- type: "text-insert",
- }];
+ return request.sourceFile.getFullText().startsWith(prefix)
+ ? []
+ : [
+ {
+ insertion: prefix,
+ range: {
+ begin: 0,
+ },
+ type: "text-insert",
+ },
+ ];
};
```
diff --git a/docs/Development.md b/docs/Development.md
deleted file mode 100644
index af8c97146..000000000
--- a/docs/Development.md
+++ /dev/null
@@ -1,75 +0,0 @@
-# Development
-
-Thanks for looking at TypeStat!
-It's very new and I very much would appreciate your help.
-
-Any issue marked as [accepting prs](https://github.com/JoshuaKGoldberg/TypeStat/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+accepting+prs%22+) on the issue tracker is fair game to take on.
-Please do file issues if you find bugs or lacking features!
-
-## Local Setup
-
-After installing [Node >=10](https://nodejs.org/en/download) and [yarn](https://yarnpkg.com), clone and install packages locally with:
-
-```shell
-git clone https://github.com/joshuakgoldberg/typestat
-cd typestat
-yarn
-```
-
-Compile with `yarn run tsc`, lint with `yarn run lint`, and run tests with `yarn run test`.
-Do all three with `yarn run verify`.
-
-## Mutation Tests
-
-Most TypeStat tests run TypeStat on checked-in files and are built on [`automutate-tests`](https://github.com/automutate/automutate-tests).
-These tests are located under `test/cases`.
-
-`yarn run test:mutation` may take in two parameters:
-
-### `--accept`
-
-Whether to override existing expected test results instead of asserting equality.
-Tests can still fail if TypeStat throws an error, but not if the contents aren't equal.
-
-```shell
-yarn run test:mutation --accept
-```
-
-### `--include`
-
-Regular expression filter(s) to include only some tests.
-If not provided (the default), all tests are run.
-If provided, only tests whose name matches one or more include filter will run.
-
-Include filters are always prefixed and suffixed with `(.*)`, so you don't need to explicitly provide full test names.
-
-For example, to run all tests with `variable` in their name:
-
-```shell
-yarn run test:mutation --include "noImplicitAny"
-```
-
-To run the `noImplicitAny/variableDeclarations` tests, either would work:
-
-```shell
-yarn run test:mutation --accept --include "noImplicitAny/variableDeclarations"
-yarn run test:mutation --accept --include "mplicitAn.*variableDeclar"
-```
-
-### Debugging
-
-VS Code tasks to debug test files is shipped that allows directly placing breakpoints in source TypeScript code.
-
-* `Accept Current Mutation Test` runs with `--accept` on the test folder of a currently opened test file, such as an `original.ts` or `typestat.json`.
-* `Debug Current Mutation Test` does not run with `--accept`, and thus logs any differences as errors.
-
-#### Performance Debugging Tips
-
-You can use the debugger in Chrome to debug TypeStat on the CLI.
-Run it with `node --inspect` then visit `chrome://inspect` to use the browser debugger.
-
-For example:
-
-```shell
-node --inspect typestat --config typestat.json
-```
diff --git a/docs/Files.md b/docs/Files.md
index f17358528..7a4de594b 100644
--- a/docs/Files.md
+++ b/docs/Files.md
@@ -4,11 +4,11 @@ An optional set of configuration fields containing file-level changes to make ou
```json
{
- "files": {
- "above": "/* Above file */",
- "below": "/* Below file */",
- "renameExtensions": true
- }
+ "files": {
+ "above": "/* Above file */",
+ "below": "/* Below file */",
+ "renameExtensions": true
+ }
}
```
@@ -16,9 +16,9 @@ An optional set of configuration fields containing file-level changes to make ou
```json
{
- "files": {
- "above": "/* Above file */"
- }
+ "files": {
+ "above": "/* Above file */"
+ }
}
```
@@ -32,9 +32,9 @@ If a value is provided on the CLI, it will override a configuration file value (
```json
{
- "files": {
- "below": "/* Below file */"
- }
+ "files": {
+ "below": "/* Below file */"
+ }
}
```
@@ -48,9 +48,9 @@ If a value is provided on the CLI, it will override a configuration file value (
```json
{
- "files": {
- "renameExtensions": true
- }
+ "files": {
+ "renameExtensions": true
+ }
}
```
@@ -62,41 +62,41 @@ regardless of whether mutations are added, will be renamed to the equivalent Typ
This field has four potential allowed configurations:
-* `false` _(default)_: skip renaming file extensions
-* `true`: auto-detect whether a file should be `.ts` or `.tsx`
-
- ```json
- {
- "files": {
- "renameExtensions": true
- }
- }
- ```
-
-* `"ts"`: always convert to `.ts`
-
- ```json
- {
- "files": {
- "renameExtensions": "ts"
- }
- }
- ```
-
-* `"tsx"`: always convert to `.tsx`
-
- ```json
- {
- "files": {
- "renameExtensions": "tsx"
- }
- }
- ```
+- `false` _(default)_: skip renaming file extensions
+- `true`: auto-detect whether a file should be `.ts` or `.tsx`
+
+ ```json
+ {
+ "files": {
+ "renameExtensions": true
+ }
+ }
+ ```
+
+- `"ts"`: always convert to `.ts`
+
+ ```json
+ {
+ "files": {
+ "renameExtensions": "ts"
+ }
+ }
+ ```
+
+- `"tsx"`: always convert to `.tsx`
+
+ ```json
+ {
+ "files": {
+ "renameExtensions": "tsx"
+ }
+ }
+ ```
When auto-detection is enabled, a file will be converted to `.tsx` if either of the following is true:
-* It `import`s or `require`s from the `"react"` module
-* Its original file extension is `.jsx`
+- It `import`s or `require`s from the `"react"` module
+- Its original file extension is `.jsx`
### Handling `require`s
diff --git a/docs/Filters.md b/docs/Filters.md
index 0385965f1..867e1a085 100644
--- a/docs/Filters.md
+++ b/docs/Filters.md
@@ -3,8 +3,8 @@
TypeStat ships with built-in support for using [tsquery](https://github.com/phenomnomnominal/tsquery) to ignore sections of source files.
This is useful for...
-* ...when sections of source files can be safely excluded from type coverage
-* ...when you want to only touch up certain parts of source files
+- ...when sections of source files can be safely excluded from type coverage
+- ...when you want to only touch up certain parts of source files
`filter` will _exclude_ any portions of source code that match them.
Sub-sections (child nodes) of those portions will not be visited.
@@ -16,8 +16,6 @@ You can use filter to exclude these `null`s from type calculations.
```json
{
- "filter": [
- "MethodDeclaration[name.text=dispose]"
- ]
+ "filter": ["MethodDeclaration[name.text=dispose]"]
}
```
diff --git a/docs/Fixes.md b/docs/Fixes.md
index ad5178d50..450e5067b 100644
--- a/docs/Fixes.md
+++ b/docs/Fixes.md
@@ -3,20 +3,20 @@
TypeStat will apply mutations ("fixes") to files as it finds them.
These mutations are all purely additive and limited to the type system, meaning they will _not_ change your JavaScript output.
-Each classifiation of fix can be individually configured in your `typestat.json` file.
+Each classification of fix can be individually configured in your `typestat.json` file.
These all default to `false` but can be enabled by being set to `true`.
```json
{
- "fixes": {
- "importExtensions": true,
- "incompleteTypes": true,
- "missingProperties": true,
- "noImplicitAny": true,
- "noImplicitThis": true,
- "noInferableTypes": true,
- "strictNonNullAssertions": true
- }
+ "fixes": {
+ "importExtensions": true,
+ "incompleteTypes": true,
+ "missingProperties": true,
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "noInferableTypes": true,
+ "strictNonNullAssertions": true
+ }
}
```
@@ -38,7 +38,7 @@ See [fixIncompleteTypes/README.md](../src/mutators/builtIn/fixIncompleteTypes/RE
Whether to apply TypeScript's fixer for missing properties on classes.
-See [fixMisingProperties/README.md](../src/mutators/builtIn/fixMissingProperties/README.md).
+See [fixMissingProperties/README.md](../src/mutators/builtIn/fixMissingProperties/README.md).
### `noImplicitAny`
diff --git a/docs/Package.md b/docs/Package.md
index dfc480ad9..5696776d0 100644
--- a/docs/Package.md
+++ b/docs/Package.md
@@ -4,11 +4,11 @@ An optional set of configuration fields containing package-level changes to make
```json
{
- "package": {
- "directory": "../MyRepo",
- "file": "./node/package.json",
- "missingTypes": "yarn"
- }
+ "package": {
+ "directory": "../MyRepo",
+ "file": "./node/package.json",
+ "missingTypes": "yarn"
+ }
}
```
@@ -16,9 +16,9 @@ An optional set of configuration fields containing package-level changes to make
```json
{
- "package": {
- "directory": "../MyRepo"
- }
+ "package": {
+ "directory": "../MyRepo"
+ }
}
```
@@ -29,9 +29,9 @@ All non-absolute paths within all settings except `-c`/`--config` will be resolv
```json
{
- "package": {
- "file": "./node/package.json"
- }
+ "package": {
+ "file": "./node/package.json"
+ }
}
```
@@ -44,9 +44,9 @@ If `package.file` is relative, `package.directory` will be used as a root path t
```json
{
- "package": {
- "missingTypes": true
- }
+ "package": {
+ "missingTypes": true
+ }
}
```
@@ -66,41 +66,41 @@ TypeStat will attempt to install `@types/lodash` unless it's already any form of
This field has four potential allowed configurations:
-* `false` _(default)_: skip installing missing packages
-* `true`: auto-detect whether to use Yarn _(if a `yarn.lock` exists)_ or npm _(default)_
-
- ```json
- {
- "package": {
- "missingTypes": true
- }
- }
- ```
-
-* `"npm"`: install using npm
-
- ```json
- {
- "package": {
- "missingTypes": "npm"
- }
- }
- ```
-
-* `"yarn"`: install using Yarn
-
- ```json
- {
- "package": {
- "missingTypes": "yarn"
- }
- }
- ```
+- `false` _(default)_: skip installing missing packages
+- `true`: auto-detect whether to use Yarn _(if a `yarn.lock` exists)_ or npm _(default)_
+
+ ```json
+ {
+ "package": {
+ "missingTypes": true
+ }
+ }
+ ```
+
+- `"npm"`: install using npm
+
+ ```json
+ {
+ "package": {
+ "missingTypes": "npm"
+ }
+ }
+ ```
+
+- `"yarn"`: install using Yarn
+
+ ```json
+ {
+ "package": {
+ "missingTypes": "yarn"
+ }
+ }
+ ```
### Node types
`@types/node` will be installed in any of the following cases:
-* `module =`, `module.exports =`, or `module.exports.*` = statement(s) exist
-* [Built-in modules](https://www.npmjs.com/package/builtin-modules) are imported from
-* A global [`process` object](https://nodejs.org/api/process.html#process_process) is referenced
+- `module =`, `module.exports =`, or `module.exports.*` = statement(s) exist
+- [Built-in modules](https://www.npmjs.com/package/builtin-modules) are imported from
+- A global [`process` object](https://nodejs.org/api/process.html#process_process) is referenced
diff --git a/docs/Types.md b/docs/Types.md
index af0c9aa07..9982fa55c 100644
--- a/docs/Types.md
+++ b/docs/Types.md
@@ -7,13 +7,13 @@ If true, TypeStat will set `strictNullChecks` to `true` regardless of your `tsco
```json
{
- "types": {
- "strictNullChecks": true
- }
+ "types": {
+ "strictNullChecks": true
+ }
}
```
This interacts with fixers in a few ways:
-* Type additions will now include `null` and/or `undefined`
-* [Property Accesses](./Nodes.md#Strict%20Property%20Accesses) will have `!`s added as needeed
+- Type additions will now include `null` and/or `undefined`
+- [Property Accesses](./Nodes.md#Strict%20Property%20Accesses) will have `!`s added as needed
diff --git a/docs/Usage.md b/docs/Usage.md
index ed6de3d42..96c22e93c 100644
--- a/docs/Usage.md
+++ b/docs/Usage.md
@@ -20,9 +20,9 @@ For example, the following `typestat.json` will add auto-fixes for missing type
```json
{
- "fixes": {
- "noImplicitAny": true,
- }
+ "fixes": {
+ "noImplicitAny": true
+ }
}
```
@@ -37,16 +37,16 @@ For example, the following `typestat.json` will:
```json
[
- {
- "fixes": {
- "noImplicitAny": true
- }
- },
- {
- "fixes": {
- "noInferableTypes": true
- }
- }
+ {
+ "fixes": {
+ "noImplicitAny": true
+ }
+ },
+ {
+ "fixes": {
+ "noInferableTypes": true
+ }
+ }
]
```
@@ -62,7 +62,6 @@ npx typestat --logfile typestat.log
## More Examples
Use these examples as more granular references of how to perform targeted changes with TypeStat.
-Reach out on [Gitter](https://gitter.im/TypeStat/community) or [Twitter](https://twitter.com/JoshuaKGoldberg) if you want help!
-* [Converting Classes from JavaScript to TypeScript.md](./Usage/Converting%20Classes%20from%20JavaScript%20to%20TypeScript.md)
-* [Enabling Strict Null Checks](./Usage/Enabling%20Strict%20Null%20Checks.md)
+- [Converting Classes from JavaScript to TypeScript.md](./Usage/Converting%20Classes%20from%20JavaScript%20to%20TypeScript.md)
+- [Enabling Strict Null Checks](./Usage/Enabling%20Strict%20Null%20Checks.md)
diff --git a/docs/Usage/Converting Classes from JavaScript to TypeScript.md b/docs/Usage/Converting Classes from JavaScript to TypeScript.md
index c4a1cc79c..c1ef1d918 100644
--- a/docs/Usage/Converting Classes from JavaScript to TypeScript.md
+++ b/docs/Usage/Converting Classes from JavaScript to TypeScript.md
@@ -8,8 +8,8 @@ Use `fixes.missingProperties` to apply those mutations across all files:
```json
{
- "fixes": {
- "missingProperties": true
- }
+ "fixes": {
+ "missingProperties": true
+ }
}
-```
\ No newline at end of file
+```
diff --git a/docs/Usage/Enabling Strict Null Checks.md b/docs/Usage/Enabling Strict Null Checks.md
index 0195b3c6b..bf8db1784 100644
--- a/docs/Usage/Enabling Strict Null Checks.md
+++ b/docs/Usage/Enabling Strict Null Checks.md
@@ -9,15 +9,13 @@ For example, this configuration will add `!`s only to `*.test.ts` test files, su
```json
{
- "fixes": {
- "strictNonNullAssertions": true
- },
- "include": [
- "./src/**/*.test.ts"
- ],
- "types": {
- "strictNullChecks": true
- }
+ "fixes": {
+ "strictNonNullAssertions": true
+ },
+ "include": ["./src/**/*.test.ts"],
+ "types": {
+ "strictNullChecks": true
+ }
}
```
@@ -26,27 +24,25 @@ For example, this configuration will add `!`s only to `*.test.ts` test files, su
Alternately, you can enable the `incompleteTypes` fix, which will prefer adding `| null` and `| undefined` to types as properties, parameters, and so on.
This configuration will add those with:
-* `filters` to ignore class and test disposal methods, as they might assign `null` or `undefined` unnecessarily
-* `types.matching` to only add `null` and `undefined` as types
-* `types.onlyPrimitives` to skip computing advanced types as a performance improvement
+- `filters` to ignore class and test disposal methods, as they might assign `null` or `undefined` unnecessarily
+- `types.matching` to only add `null` and `undefined` as types
+- `types.onlyPrimitives` to skip computing advanced types as a performance improvement
```json
{
- "filters": [
- "CallExpression[expression.text=suiteTeardown]",
- "CallExpression[expression.text=teardown]",
- "MethodDeclaration[name.text=dispose]"
- ],
- "fixes": {
- "incompleteTypes": true
- },
- "types": {
- "matching": [
- "^(null|undefined)$"
- ],
- "onlyPrimitives": true,
- "strictNullChecks": true
- }
+ "filters": [
+ "CallExpression[expression.text=suiteTeardown]",
+ "CallExpression[expression.text=teardown]",
+ "MethodDeclaration[name.text=dispose]"
+ ],
+ "fixes": {
+ "incompleteTypes": true
+ },
+ "types": {
+ "matching": ["^(null|undefined)$"],
+ "onlyPrimitives": true,
+ "strictNullChecks": true
+ }
}
```
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index ab38da47b..000000000
--- a/jest.config.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
- moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
- roots: ["/src"],
- testRegex: "src(.*)\\.test\\.tsx?$",
-};
diff --git a/knip.json b/knip.json
new file mode 100644
index 000000000..f681ce25b
--- /dev/null
+++ b/knip.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://unpkg.com/knip@latest/schema.json",
+ "entry": ["src/index.ts!", "test/**/*.ts!", "test/**/*.tsx!"],
+ "ignore": ["test/cases/fixes/importExtensions/*"],
+ "ignoreExportsUsedInFile": { "interface": true, "type": true },
+ "project": ["src/**/*.ts!", "test/**/*.ts!", "test/**/*.tsx!"]
+}
diff --git a/package.json b/package.json
index 9a2fc7003..74bc19d02 100644
--- a/package.json
+++ b/package.json
@@ -1,80 +1,95 @@
{
- "author": "josh Goldberg",
- "bin": {
- "typestat": "bin/typestat"
- },
- "dependencies": {
- "@phenomnomnominal/tsquery": "^6.0.0",
- "automutate": "^0.9.0",
- "builtin-modules": "^3.2.0",
- "chalk": "^4.1.1",
- "commander": "^11.0.0",
- "enquirer": "^2.3.6",
- "glob": "^10.0.0",
- "minimatch": "^8.0.0",
- "mz": "^2.7.0",
- "strip-ansi": "^6.0.0",
- "ts-api-utils": "^1.0.3",
- "typescript": "^5.1.6"
- },
- "description": "Converts JavaScript to TypeScript and TypeScript to better TypeScript.",
- "devDependencies": {
- "@babel/core": "7.23.5",
- "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
- "@babel/plugin-proposal-optional-chaining": "7.21.0",
- "@babel/preset-env": "7.23.5",
- "@babel/preset-typescript": "7.23.3",
- "@types/glob": "8.1.0",
- "@types/jest": "29.5.11",
- "@types/minimatch": "^5.0.0",
- "@types/mz": "2.7.8",
- "@types/node": "20.10.3",
- "@types/prop-types": "15.7.11",
- "@types/react": "18.2.69",
- "@typescript-eslint/eslint-plugin": "^6.4.0",
- "@typescript-eslint/parser": "^6.4.0",
- "automutate-tests": "0.5.0",
- "babel-jest": "29.7.0",
- "chai": "4.3.10",
- "eslint": "8.55.0",
- "eslint-config-prettier": "9.1.0",
- "eslint-plugin-deprecation": "2.0.0",
- "eslint-plugin-no-only-tests": "3.1.0",
- "husky": "8.0.3",
- "jest": "29.7.0",
- "lint-staged": "14.0.1",
- "markdownlint": "0.32.1",
- "markdownlint-cli": "0.37.0",
- "mocha": "10.2.0",
- "npm-run-all": "4.1.5",
- "prettier": "3.1.0",
- "sentences-per-line": "0.2.1"
- },
- "license": "MIT",
- "lint-staged": {
- "**/*.{js,json,md,ts,xml,yaml}": [
- "prettier --write"
- ]
- },
- "main": "src/index.js",
- "name": "typestat",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/JoshuaKGoldberg/TypeStat.git"
- },
- "scripts": {
- "compile": "tsc",
- "format": "yarn prettier --write",
- "format:verify": "yarn prettier --list-different \"**/*.{js,json,md,ts,yml}\"",
- "format:write": "yarn format:verify --write",
- "lint": "run-p lint:*",
- "lint:eslint": "eslint ./src/**/*.ts",
- "lint:markdownlint": "markdownlint --config .markdownlint.json --rules ./node_modules/sentences-per-line/index.js README.md",
- "precommit": "lint-staged",
- "test": "yarn run test:unit && yarn run test:mutation",
- "test:mutation": "mocha src/tests/runTests.js --timeout 50000",
- "test:unit": "jest --config=jest.config.js",
- "verify": "yarn run tsc && yarn run lint && yarn run test"
- },
- "version": "0.7.3"
+ "name": "typestat",
+ "version": "0.7.3",
+ "description": "Converts JavaScript to TypeScript and TypeScript to better TypeScript. ๐งซ",
+ "repository": "JoshuaKGoldberg/TypeStat",
+ "license": "MIT",
+ "author": {
+ "name": "JoshuaKGoldberg",
+ "email": "npm@joshuakgoldberg.com"
+ },
+ "type": "module",
+ "main": "./lib/index.js",
+ "files": [
+ "lib/",
+ "package.json",
+ "LICENSE.md",
+ "README.md"
+ ],
+ "scripts": {
+ "build": "NODE_OPTIONS='--max-old-space-size=16384' tsup",
+ "format": "prettier .",
+ "lint": "eslint . .*js --max-warnings 0",
+ "lint:knip": "knip",
+ "lint:md": "markdownlint \"**/*.md\" \".github/**/*.md\" --rules sentences-per-line",
+ "lint:packages": "pnpm dedupe --check",
+ "lint:spelling": "cspell \"**\" \".github/**/*\"",
+ "prepare": "husky",
+ "test": "vitest",
+ "test:mutation": "mocha lib/tests/runTests.js --timeout 50000",
+ "tsc": "tsc"
+ },
+ "lint-staged": {
+ "*": "prettier --ignore-unknown --write"
+ },
+ "dependencies": {
+ "@phenomnomnominal/tsquery": "^6.1.3",
+ "automutate": "^0.9.0",
+ "builtin-modules": "^3.3.0",
+ "chalk": "^5.3.0",
+ "commander": "^12.0.0",
+ "enquirer": "^2.4.1",
+ "glob": "^10.3.10",
+ "minimatch": "^9.0.3",
+ "strip-ansi": "^7.1.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "devDependencies": {
+ "@types/eslint": "^8.56.6",
+ "@types/glob": "8.1.0",
+ "@types/minimatch": "^5.1.2",
+ "@types/node": "^20.11.30",
+ "@types/prop-types": "15.7.12",
+ "@types/react": "18.2.69",
+ "@typescript-eslint/eslint-plugin": "^7.3.1",
+ "@typescript-eslint/parser": "^7.3.1",
+ "@vitest/coverage-v8": "^1.4.0",
+ "automutate-tests": "0.5.0",
+ "console-fail-test": "^0.2.3",
+ "cspell": "^8.6.0",
+ "eslint": "8.57.0",
+ "eslint-plugin-deprecation": "2.0.0",
+ "eslint-plugin-eslint-comments": "^3.2.0",
+ "eslint-plugin-jsdoc": "^48.2.1",
+ "eslint-plugin-jsonc": "^2.14.1",
+ "eslint-plugin-markdown": "^4.0.1",
+ "eslint-plugin-n": "^16.6.2",
+ "eslint-plugin-package-json": "^0.10.4",
+ "eslint-plugin-perfectionist": "^2.7.0",
+ "eslint-plugin-regexp": "^2.3.0",
+ "eslint-plugin-vitest": "^0.3.26",
+ "eslint-plugin-yml": "^1.13.2",
+ "husky": "9.0.11",
+ "jsonc-eslint-parser": "^2.4.0",
+ "knip": "^5.2.2",
+ "lint-staged": "15.2.2",
+ "markdownlint": "0.34.0",
+ "markdownlint-cli": "0.39.0",
+ "mocha": "^10.3.0",
+ "prettier": "3.2.5",
+ "prettier-plugin-curly": "^0.2.1",
+ "prettier-plugin-packagejson": "^2.4.12",
+ "sentences-per-line": "0.2.1",
+ "tsup": "^8.0.2",
+ "typescript": "^5.4.3",
+ "vitest": "^1.4.0",
+ "yaml-eslint-parser": "^1.2.2"
+ },
+ "packageManager": "pnpm@8.9.2",
+ "engines": {
+ "node": ">=18"
+ },
+ "publishConfig": {
+ "provenance": true
+ }
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 000000000..f7adf1496
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,5709 @@
+lockfileVersion: '6.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+dependencies:
+ '@phenomnomnominal/tsquery':
+ specifier: ^6.1.3
+ version: 6.1.3(typescript@5.4.3)
+ automutate:
+ specifier: ^0.9.0
+ version: 0.9.0
+ builtin-modules:
+ specifier: ^3.3.0
+ version: 3.3.0
+ chalk:
+ specifier: ^5.3.0
+ version: 5.3.0
+ commander:
+ specifier: ^12.0.0
+ version: 12.0.0
+ enquirer:
+ specifier: ^2.4.1
+ version: 2.4.1
+ glob:
+ specifier: ^10.3.10
+ version: 10.3.10
+ minimatch:
+ specifier: ^9.0.3
+ version: 9.0.3
+ strip-ansi:
+ specifier: ^7.1.0
+ version: 7.1.0
+ ts-api-utils:
+ specifier: ^1.3.0
+ version: 1.3.0(typescript@5.4.3)
+
+devDependencies:
+ '@types/eslint':
+ specifier: ^8.56.6
+ version: 8.56.6
+ '@types/glob':
+ specifier: 8.1.0
+ version: 8.1.0
+ '@types/minimatch':
+ specifier: ^5.1.2
+ version: 5.1.2
+ '@types/node':
+ specifier: ^20.11.30
+ version: 20.11.30
+ '@types/prop-types':
+ specifier: 15.7.12
+ version: 15.7.12
+ '@types/react':
+ specifier: 18.2.69
+ version: 18.2.69
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^7.3.1
+ version: 7.3.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/parser':
+ specifier: ^7.3.1
+ version: 7.3.1(eslint@8.57.0)(typescript@5.4.3)
+ '@vitest/coverage-v8':
+ specifier: ^1.4.0
+ version: 1.4.0(vitest@1.4.0)
+ automutate-tests:
+ specifier: 0.5.0
+ version: 0.5.0
+ console-fail-test:
+ specifier: ^0.2.3
+ version: 0.2.3
+ cspell:
+ specifier: ^8.6.0
+ version: 8.6.0
+ eslint:
+ specifier: 8.57.0
+ version: 8.57.0
+ eslint-plugin-deprecation:
+ specifier: 2.0.0
+ version: 2.0.0(eslint@8.57.0)(typescript@5.4.3)
+ eslint-plugin-eslint-comments:
+ specifier: ^3.2.0
+ version: 3.2.0(eslint@8.57.0)
+ eslint-plugin-jsdoc:
+ specifier: ^48.2.1
+ version: 48.2.1(eslint@8.57.0)
+ eslint-plugin-jsonc:
+ specifier: ^2.14.1
+ version: 2.14.1(eslint@8.57.0)
+ eslint-plugin-markdown:
+ specifier: ^4.0.1
+ version: 4.0.1(eslint@8.57.0)
+ eslint-plugin-n:
+ specifier: ^16.6.2
+ version: 16.6.2(eslint@8.57.0)
+ eslint-plugin-package-json:
+ specifier: ^0.10.4
+ version: 0.10.4(eslint@8.57.0)(jsonc-eslint-parser@2.4.0)
+ eslint-plugin-perfectionist:
+ specifier: ^2.7.0
+ version: 2.7.0(eslint@8.57.0)(typescript@5.4.3)
+ eslint-plugin-regexp:
+ specifier: ^2.3.0
+ version: 2.3.0(eslint@8.57.0)
+ eslint-plugin-vitest:
+ specifier: ^0.3.26
+ version: 0.3.26(@typescript-eslint/eslint-plugin@7.3.1)(eslint@8.57.0)(typescript@5.4.3)(vitest@1.4.0)
+ eslint-plugin-yml:
+ specifier: ^1.13.2
+ version: 1.13.2(eslint@8.57.0)
+ husky:
+ specifier: 9.0.11
+ version: 9.0.11
+ jsonc-eslint-parser:
+ specifier: ^2.4.0
+ version: 2.4.0
+ knip:
+ specifier: ^5.2.2
+ version: 5.2.2(@types/node@20.11.30)(typescript@5.4.3)
+ lint-staged:
+ specifier: 15.2.2
+ version: 15.2.2
+ markdownlint:
+ specifier: 0.34.0
+ version: 0.34.0
+ markdownlint-cli:
+ specifier: 0.39.0
+ version: 0.39.0
+ mocha:
+ specifier: ^10.3.0
+ version: 10.3.0
+ prettier:
+ specifier: 3.2.5
+ version: 3.2.5
+ prettier-plugin-curly:
+ specifier: ^0.2.1
+ version: 0.2.1(prettier@3.2.5)
+ prettier-plugin-packagejson:
+ specifier: ^2.4.12
+ version: 2.4.12(prettier@3.2.5)
+ sentences-per-line:
+ specifier: 0.2.1
+ version: 0.2.1
+ tsup:
+ specifier: ^8.0.2
+ version: 8.0.2(typescript@5.4.3)
+ typescript:
+ specifier: ^5.4.3
+ version: 5.4.3
+ vitest:
+ specifier: ^1.4.0
+ version: 1.4.0(@types/node@20.11.30)
+ yaml-eslint-parser:
+ specifier: ^1.2.2
+ version: 1.2.2
+
+packages:
+
+ /@aashutoshrathi/word-wrap@1.2.6:
+ resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /@ampproject/remapping@2.3.0:
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+ dev: true
+
+ /@babel/code-frame@7.24.2:
+ resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/highlight': 7.24.2
+ picocolors: 1.0.0
+ dev: true
+
+ /@babel/generator@7.24.1:
+ resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 2.5.2
+ dev: true
+
+ /@babel/helper-environment-visitor@7.22.20:
+ resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-function-name@7.23.0:
+ resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.24.0
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-hoist-variables@7.22.5:
+ resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-split-export-declaration@7.22.6:
+ resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-string-parser@7.24.1:
+ resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-validator-identifier@7.22.20:
+ resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/highlight@7.24.2:
+ resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': 7.22.20
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+ picocolors: 1.0.0
+ dev: true
+
+ /@babel/parser@7.24.1:
+ resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/template@7.24.0:
+ resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.24.2
+ '@babel/parser': 7.24.1
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/traverse@7.24.1:
+ resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.24.2
+ '@babel/generator': 7.24.1
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-function-name': 7.23.0
+ '@babel/helper-hoist-variables': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/parser': 7.24.1
+ '@babel/types': 7.24.0
+ debug: 4.3.4(supports-color@8.1.1)
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/types@7.24.0:
+ resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': 7.24.1
+ '@babel/helper-validator-identifier': 7.22.20
+ to-fast-properties: 2.0.0
+ dev: true
+
+ /@bcoe/v8-coverage@0.2.3:
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ dev: true
+
+ /@cspell/cspell-bundled-dicts@8.6.0:
+ resolution: {integrity: sha512-hRVvir4G4276Kz/Cru34AJg1FObIw5MrzezAwHkD3obNMwZkof8aX3MEN6AzWusJSVG2ZxZxZAEnYbgqvGr2Fg==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/dict-ada': 4.0.2
+ '@cspell/dict-aws': 4.0.1
+ '@cspell/dict-bash': 4.1.3
+ '@cspell/dict-companies': 3.0.31
+ '@cspell/dict-cpp': 5.1.3
+ '@cspell/dict-cryptocurrencies': 5.0.0
+ '@cspell/dict-csharp': 4.0.2
+ '@cspell/dict-css': 4.0.12
+ '@cspell/dict-dart': 2.0.3
+ '@cspell/dict-django': 4.1.0
+ '@cspell/dict-docker': 1.1.7
+ '@cspell/dict-dotnet': 5.0.0
+ '@cspell/dict-elixir': 4.0.3
+ '@cspell/dict-en-common-misspellings': 2.0.0
+ '@cspell/dict-en-gb': 1.1.33
+ '@cspell/dict-en_us': 4.3.17
+ '@cspell/dict-filetypes': 3.0.3
+ '@cspell/dict-fonts': 4.0.0
+ '@cspell/dict-fsharp': 1.0.1
+ '@cspell/dict-fullstack': 3.1.5
+ '@cspell/dict-gaming-terms': 1.0.5
+ '@cspell/dict-git': 3.0.0
+ '@cspell/dict-golang': 6.0.5
+ '@cspell/dict-haskell': 4.0.1
+ '@cspell/dict-html': 4.0.5
+ '@cspell/dict-html-symbol-entities': 4.0.0
+ '@cspell/dict-java': 5.0.6
+ '@cspell/dict-k8s': 1.0.2
+ '@cspell/dict-latex': 4.0.0
+ '@cspell/dict-lorem-ipsum': 4.0.0
+ '@cspell/dict-lua': 4.0.3
+ '@cspell/dict-makefile': 1.0.0
+ '@cspell/dict-node': 4.0.3
+ '@cspell/dict-npm': 5.0.15
+ '@cspell/dict-php': 4.0.6
+ '@cspell/dict-powershell': 5.0.3
+ '@cspell/dict-public-licenses': 2.0.6
+ '@cspell/dict-python': 4.1.11
+ '@cspell/dict-r': 2.0.1
+ '@cspell/dict-ruby': 5.0.2
+ '@cspell/dict-rust': 4.0.2
+ '@cspell/dict-scala': 5.0.0
+ '@cspell/dict-software-terms': 3.3.18
+ '@cspell/dict-sql': 2.1.3
+ '@cspell/dict-svelte': 1.0.2
+ '@cspell/dict-swift': 2.0.1
+ '@cspell/dict-typescript': 3.1.2
+ '@cspell/dict-vue': 3.0.0
+ dev: true
+
+ /@cspell/cspell-json-reporter@8.6.0:
+ resolution: {integrity: sha512-fPpE4a3zpdfwgTyfLgCmxZn4owkZ4IP6A/oL4XLW22IxW5xBIbXEveOSY+uiWAnVfEnqfrMNRLAGj7JoXnJ1Vg==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/cspell-types': 8.6.0
+ dev: true
+
+ /@cspell/cspell-pipe@8.6.0:
+ resolution: {integrity: sha512-gbAZksz38OHaN8s4fOmmgtgQfie1K8dRGlo9z/uxSx5FIELV48GWTbHn9t1TY2yBXBwJ7+4NF2+r624rtlPoHQ==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /@cspell/cspell-resolver@8.6.0:
+ resolution: {integrity: sha512-ARwO6TWKy8fLHNhC/ls5Wo/AK86E1oLVChwWtHdq7eVyEUIykQaXGLqoRThkIT2jyLfGDrhSvaU+yqcXVLE48Q==}
+ engines: {node: '>=18'}
+ dependencies:
+ global-directory: 4.0.1
+ dev: true
+
+ /@cspell/cspell-service-bus@8.6.0:
+ resolution: {integrity: sha512-veCGlhlNGmYMgzX/rMiDp8j7ndLxFHIZq3h6DNlIsIoSjP1v5Rk6UcCwEoWYexwKmNXo7c2VooB0GM9LSBcPAQ==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /@cspell/cspell-types@8.6.0:
+ resolution: {integrity: sha512-+CU/nuFOpswJAA3IS2TcKGskfM/o/4aNG1IMUVaOEQi1Sc5qZQ4Wj1qDIWJArSHFYW1Q4XFa4U8K1jnVHkAhZQ==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /@cspell/dict-ada@4.0.2:
+ resolution: {integrity: sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA==}
+ dev: true
+
+ /@cspell/dict-aws@4.0.1:
+ resolution: {integrity: sha512-NXO+kTPQGqaaJKa4kO92NAXoqS+i99dQzf3/L1BxxWVSBS3/k1f3uhmqIh7Crb/n22W793lOm0D9x952BFga3Q==}
+ dev: true
+
+ /@cspell/dict-bash@4.1.3:
+ resolution: {integrity: sha512-tOdI3QVJDbQSwPjUkOiQFhYcu2eedmX/PtEpVWg0aFps/r6AyjUQINtTgpqMYnYuq8O1QUIQqnpx21aovcgZCw==}
+ dev: true
+
+ /@cspell/dict-companies@3.0.31:
+ resolution: {integrity: sha512-hKVpV/lcGKP4/DpEPS8P4osPvFH/YVLJaDn9cBIOH6/HSmL5LbFgJNKpMGaYRbhm2FEX56MKE3yn/MNeNYuesQ==}
+ dev: true
+
+ /@cspell/dict-cpp@5.1.3:
+ resolution: {integrity: sha512-sqnriXRAInZH9W75C+APBh6dtben9filPqVbIsiRMUXGg+s02ekz0z6LbS7kXeJ5mD2qXoMLBrv13qH2eIwutQ==}
+ dev: true
+
+ /@cspell/dict-cryptocurrencies@5.0.0:
+ resolution: {integrity: sha512-Z4ARIw5+bvmShL+4ZrhDzGhnc9znaAGHOEMaB/GURdS/jdoreEDY34wdN0NtdLHDO5KO7GduZnZyqGdRoiSmYA==}
+ dev: true
+
+ /@cspell/dict-csharp@4.0.2:
+ resolution: {integrity: sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==}
+ dev: true
+
+ /@cspell/dict-css@4.0.12:
+ resolution: {integrity: sha512-vGBgPM92MkHQF5/2jsWcnaahOZ+C6OE/fPvd5ScBP72oFY9tn5GLuomcyO0z8vWCr2e0nUSX1OGimPtcQAlvSw==}
+ dev: true
+
+ /@cspell/dict-dart@2.0.3:
+ resolution: {integrity: sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw==}
+ dev: true
+
+ /@cspell/dict-data-science@1.0.11:
+ resolution: {integrity: sha512-TaHAZRVe0Zlcc3C23StZqqbzC0NrodRwoSAc8dis+5qLeLLnOCtagYQeROQvDlcDg3X/VVEO9Whh4W/z4PAmYQ==}
+ dev: true
+
+ /@cspell/dict-django@4.1.0:
+ resolution: {integrity: sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w==}
+ dev: true
+
+ /@cspell/dict-docker@1.1.7:
+ resolution: {integrity: sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A==}
+ dev: true
+
+ /@cspell/dict-dotnet@5.0.0:
+ resolution: {integrity: sha512-EOwGd533v47aP5QYV8GlSSKkmM9Eq8P3G/eBzSpH3Nl2+IneDOYOBLEUraHuiCtnOkNsz0xtZHArYhAB2bHWAw==}
+ dev: true
+
+ /@cspell/dict-elixir@4.0.3:
+ resolution: {integrity: sha512-g+uKLWvOp9IEZvrIvBPTr/oaO6619uH/wyqypqvwpmnmpjcfi8+/hqZH8YNKt15oviK8k4CkINIqNhyndG9d9Q==}
+ dev: true
+
+ /@cspell/dict-en-common-misspellings@2.0.0:
+ resolution: {integrity: sha512-NOg8dlv37/YqLkCfBs5OXeJm/Wcfb/CzeOmOZJ2ZXRuxwsNuolb4TREUce0yAXRqMhawahY5TSDRJJBgKjBOdw==}
+ dev: true
+
+ /@cspell/dict-en-gb@1.1.33:
+ resolution: {integrity: sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==}
+ dev: true
+
+ /@cspell/dict-en_us@4.3.17:
+ resolution: {integrity: sha512-CS0Tb2f2YwQZ4VZ6+WLAO5uOzb0iO/iYSRl34kX4enq6quXxLYzwdfGAwv85wSYHPdga8tGiZFP+p8GPsi2JEg==}
+ dev: true
+
+ /@cspell/dict-filetypes@3.0.3:
+ resolution: {integrity: sha512-J9UP+qwwBLfOQ8Qg9tAsKtSY/WWmjj21uj6zXTI9hRLD1eG1uUOLcfVovAmtmVqUWziPSKMr87F6SXI3xmJXgw==}
+ dev: true
+
+ /@cspell/dict-fonts@4.0.0:
+ resolution: {integrity: sha512-t9V4GeN/m517UZn63kZPUYP3OQg5f0OBLSd3Md5CU3eH1IFogSvTzHHnz4Wqqbv8NNRiBZ3HfdY/pqREZ6br3Q==}
+ dev: true
+
+ /@cspell/dict-fsharp@1.0.1:
+ resolution: {integrity: sha512-23xyPcD+j+NnqOjRHgW3IU7Li912SX9wmeefcY0QxukbAxJ/vAN4rBpjSwwYZeQPAn3fxdfdNZs03fg+UM+4yQ==}
+ dev: true
+
+ /@cspell/dict-fullstack@3.1.5:
+ resolution: {integrity: sha512-6ppvo1dkXUZ3fbYn/wwzERxCa76RtDDl5Afzv2lijLoijGGUw5yYdLBKJnx8PJBGNLh829X352ftE7BElG4leA==}
+ dev: true
+
+ /@cspell/dict-gaming-terms@1.0.5:
+ resolution: {integrity: sha512-C3riccZDD3d9caJQQs1+MPfrUrQ+0KHdlj9iUR1QD92FgTOF6UxoBpvHUUZ9YSezslcmpFQK4xQQ5FUGS7uWfw==}
+ dev: true
+
+ /@cspell/dict-git@3.0.0:
+ resolution: {integrity: sha512-simGS/lIiXbEaqJu9E2VPoYW1OTC2xrwPPXNXFMa2uo/50av56qOuaxDrZ5eH1LidFXwoc8HROCHYeKoNrDLSw==}
+ dev: true
+
+ /@cspell/dict-golang@6.0.5:
+ resolution: {integrity: sha512-w4mEqGz4/wV+BBljLxduFNkMrd3rstBNDXmoX5kD4UTzIb4Sy0QybWCtg2iVT+R0KWiRRA56QKOvBsgXiddksA==}
+ dev: true
+
+ /@cspell/dict-haskell@4.0.1:
+ resolution: {integrity: sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ==}
+ dev: true
+
+ /@cspell/dict-html-symbol-entities@4.0.0:
+ resolution: {integrity: sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==}
+ dev: true
+
+ /@cspell/dict-html@4.0.5:
+ resolution: {integrity: sha512-p0brEnRybzSSWi8sGbuVEf7jSTDmXPx7XhQUb5bgG6b54uj+Z0Qf0V2n8b/LWwIPJNd1GygaO9l8k3HTCy1h4w==}
+ dev: true
+
+ /@cspell/dict-java@5.0.6:
+ resolution: {integrity: sha512-kdE4AHHHrixyZ5p6zyms1SLoYpaJarPxrz8Tveo6gddszBVVwIUZ+JkQE1bWNLK740GWzIXdkznpUfw1hP9nXw==}
+ dev: true
+
+ /@cspell/dict-k8s@1.0.2:
+ resolution: {integrity: sha512-tLT7gZpNPnGa+IIFvK9SP1LrSpPpJ94a/DulzAPOb1Q2UBFwdpFd82UWhio0RNShduvKG/WiMZf/wGl98pn+VQ==}
+ dev: true
+
+ /@cspell/dict-latex@4.0.0:
+ resolution: {integrity: sha512-LPY4y6D5oI7D3d+5JMJHK/wxYTQa2lJMSNxps2JtuF8hbAnBQb3igoWEjEbIbRRH1XBM0X8dQqemnjQNCiAtxQ==}
+ dev: true
+
+ /@cspell/dict-lorem-ipsum@4.0.0:
+ resolution: {integrity: sha512-1l3yjfNvMzZPibW8A7mQU4kTozwVZVw0AvFEdy+NcqtbxH+TvbSkNMqROOFWrkD2PjnKG0+Ea0tHI2Pi6Gchnw==}
+ dev: true
+
+ /@cspell/dict-lua@4.0.3:
+ resolution: {integrity: sha512-lDHKjsrrbqPaea13+G9s0rtXjMO06gPXPYRjRYawbNmo4E/e3XFfVzeci3OQDQNDmf2cPOwt9Ef5lu2lDmwfJg==}
+ dev: true
+
+ /@cspell/dict-makefile@1.0.0:
+ resolution: {integrity: sha512-3W9tHPcSbJa6s0bcqWo6VisEDTSN5zOtDbnPabF7rbyjRpNo0uHXHRJQF8gAbFzoTzBBhgkTmrfSiuyQm7vBUQ==}
+ dev: true
+
+ /@cspell/dict-node@4.0.3:
+ resolution: {integrity: sha512-sFlUNI5kOogy49KtPg8SMQYirDGIAoKBO3+cDLIwD4MLdsWy1q0upc7pzGht3mrjuyMiPRUV14Bb0rkVLrxOhg==}
+ dev: true
+
+ /@cspell/dict-npm@5.0.15:
+ resolution: {integrity: sha512-sX0X5YWNW54F4baW7b5JJB6705OCBIZtUqjOghlJNORS5No7QY1IX1zc5FxNNu4gsaCZITAmfMi4ityXEsEThA==}
+ dev: true
+
+ /@cspell/dict-php@4.0.6:
+ resolution: {integrity: sha512-ySAXisf7twoVFZqBV2o/DKiCLIDTHNqfnj0EfH9OoOUR7HL3rb6zJkm0viLUFDO2G/8SyIi6YrN/6KX+Scjjjg==}
+ dev: true
+
+ /@cspell/dict-powershell@5.0.3:
+ resolution: {integrity: sha512-lEdzrcyau6mgzu1ie98GjOEegwVHvoaWtzQnm1ie4DyZgMr+N6D0Iyj1lzvtmt0snvsDFa5F2bsYzf3IMKcpcA==}
+ dev: true
+
+ /@cspell/dict-public-licenses@2.0.6:
+ resolution: {integrity: sha512-bHqpSpJvLCUcWxj1ov/Ki8WjmESpYwRpQlqfdchekOTc93Huhvjm/RXVN1R4fVf4Hspyem1QVkCGqAmjJMj6sw==}
+ dev: true
+
+ /@cspell/dict-python@4.1.11:
+ resolution: {integrity: sha512-XG+v3PumfzUW38huSbfT15Vqt3ihNb462ulfXifpQllPok5OWynhszCLCRQjQReV+dgz784ST4ggRxW452/kVg==}
+ dependencies:
+ '@cspell/dict-data-science': 1.0.11
+ dev: true
+
+ /@cspell/dict-r@2.0.1:
+ resolution: {integrity: sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA==}
+ dev: true
+
+ /@cspell/dict-ruby@5.0.2:
+ resolution: {integrity: sha512-cIh8KTjpldzFzKGgrqUX4bFyav5lC52hXDKo4LbRuMVncs3zg4hcSf4HtURY+f2AfEZzN6ZKzXafQpThq3dl2g==}
+ dev: true
+
+ /@cspell/dict-rust@4.0.2:
+ resolution: {integrity: sha512-RhziKDrklzOntxAbY3AvNR58wnFGIo3YS8+dNeLY36GFuWOvXDHFStYw5Pod4f/VXbO/+1tXtywCC4zWfB2p1w==}
+ dev: true
+
+ /@cspell/dict-scala@5.0.0:
+ resolution: {integrity: sha512-ph0twaRoV+ylui022clEO1dZ35QbeEQaKTaV2sPOsdwIokABPIiK09oWwGK9qg7jRGQwVaRPEq0Vp+IG1GpqSQ==}
+ dev: true
+
+ /@cspell/dict-software-terms@3.3.18:
+ resolution: {integrity: sha512-LJZGGMGqS8KzgXJrSMs3T+6GoqHG9z8Bc+rqLzLzbtoR3FbsMasE9U8oP2PmS3q7jJLFjQkzmg508DrcuZuo2g==}
+ dev: true
+
+ /@cspell/dict-sql@2.1.3:
+ resolution: {integrity: sha512-SEyTNKJrjqD6PAzZ9WpdSu6P7wgdNtGV2RV8Kpuw1x6bV+YsSptuClYG+JSdRExBTE6LwIe1bTklejUp3ZP8TQ==}
+ dev: true
+
+ /@cspell/dict-svelte@1.0.2:
+ resolution: {integrity: sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q==}
+ dev: true
+
+ /@cspell/dict-swift@2.0.1:
+ resolution: {integrity: sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw==}
+ dev: true
+
+ /@cspell/dict-typescript@3.1.2:
+ resolution: {integrity: sha512-lcNOYWjLUvDZdLa0UMNd/LwfVdxhE9rKA+agZBGjL3lTA3uNvH7IUqSJM/IXhJoBpLLMVEOk8v1N9xi+vDuCdA==}
+ dev: true
+
+ /@cspell/dict-vue@3.0.0:
+ resolution: {integrity: sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==}
+ dev: true
+
+ /@cspell/dynamic-import@8.6.0:
+ resolution: {integrity: sha512-yDJZ/uXCpZcAkXwaWa0JcCZHZFxnF3qtiFiq2WG5cEw8tiJiNdawjSCd8/D35dT3QFNaInMP+H3sOf68dNueew==}
+ engines: {node: '>=18.0'}
+ dependencies:
+ import-meta-resolve: 4.0.0
+ dev: true
+
+ /@cspell/strong-weak-map@8.6.0:
+ resolution: {integrity: sha512-QenBOdIT1zRa0kF3Z1mwObcvmdhxn+rzQDdmkxwSyRB/9KsNnib6XXTUo8P+Z/ZKXOYbP9Wmf4FX+vKd3yVX0Q==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /@ericcornelissen/bash-parser@0.5.2:
+ resolution: {integrity: sha512-4pIMTa1nEFfMXitv7oaNEWOdM+zpOZavesa5GaiWTgda6Zk32CFGxjUp/iIaN0PwgUW1yTq/fztSjbpE8SLGZQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ array-last: 1.3.0
+ babylon: 6.18.0
+ compose-function: 3.0.3
+ deep-freeze: 0.0.1
+ filter-iterator: 0.0.1
+ filter-obj: 1.1.0
+ has-own-property: 0.1.0
+ identity-function: 1.0.0
+ is-iterable: 1.1.1
+ iterable-lookahead: 1.0.0
+ lodash.curry: 4.1.1
+ magic-string: 0.16.0
+ map-obj: 2.0.0
+ object-pairs: 0.1.0
+ object-values: 1.0.0
+ reverse-arguments: 1.0.0
+ shell-quote-word: 1.0.1
+ to-pascal-case: 1.0.0
+ unescape-js: 1.1.4
+ dev: true
+
+ /@es-joy/jsdoccomment@0.42.0:
+ resolution: {integrity: sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==}
+ engines: {node: '>=16'}
+ dependencies:
+ comment-parser: 1.4.1
+ esquery: 1.5.0
+ jsdoc-type-pratt-parser: 4.0.0
+ dev: true
+
+ /@esbuild/aix-ppc64@0.19.12:
+ resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/aix-ppc64@0.20.2:
+ resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm64@0.19.12:
+ resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm64@0.20.2:
+ resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm@0.19.12:
+ resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm@0.20.2:
+ resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-x64@0.19.12:
+ resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-x64@0.20.2:
+ resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-arm64@0.19.12:
+ resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-arm64@0.20.2:
+ resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-x64@0.19.12:
+ resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-x64@0.20.2:
+ resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-arm64@0.19.12:
+ resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-arm64@0.20.2:
+ resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-x64@0.19.12:
+ resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-x64@0.20.2:
+ resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm64@0.19.12:
+ resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm64@0.20.2:
+ resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm@0.19.12:
+ resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm@0.20.2:
+ resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ia32@0.19.12:
+ resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ia32@0.20.2:
+ resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-loong64@0.19.12:
+ resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-loong64@0.20.2:
+ resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-mips64el@0.19.12:
+ resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-mips64el@0.20.2:
+ resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ppc64@0.19.12:
+ resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ppc64@0.20.2:
+ resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-riscv64@0.19.12:
+ resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-riscv64@0.20.2:
+ resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-s390x@0.19.12:
+ resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-s390x@0.20.2:
+ resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-x64@0.19.12:
+ resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-x64@0.20.2:
+ resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/netbsd-x64@0.19.12:
+ resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/netbsd-x64@0.20.2:
+ resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/openbsd-x64@0.19.12:
+ resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/openbsd-x64@0.20.2:
+ resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/sunos-x64@0.19.12:
+ resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/sunos-x64@0.20.2:
+ resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-arm64@0.19.12:
+ resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-arm64@0.20.2:
+ resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-ia32@0.19.12:
+ resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-ia32@0.20.2:
+ resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-x64@0.19.12:
+ resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-x64@0.20.2:
+ resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 8.57.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@eslint-community/regexpp@4.10.0:
+ resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /@eslint/eslintrc@2.1.4:
+ resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4(supports-color@8.1.1)
+ espree: 9.6.1
+ globals: 13.24.0
+ ignore: 5.3.1
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@eslint/js@8.57.0:
+ resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@humanwhocodes/config-array@0.11.14:
+ resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 2.0.2
+ debug: 4.3.4(supports-color@8.1.1)
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/module-importer@1.0.1:
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+ dev: true
+
+ /@humanwhocodes/object-schema@2.0.2:
+ resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+ dev: true
+
+ /@isaacs/cliui@8.0.2:
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: /string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: /strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: /wrap-ansi@7.0.0
+
+ /@istanbuljs/schema@0.1.3:
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /@jest/schemas@29.6.3:
+ resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dependencies:
+ '@sinclair/typebox': 0.27.8
+ dev: true
+
+ /@jridgewell/gen-mapping@0.3.5:
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.25
+ dev: true
+
+ /@jridgewell/resolve-uri@3.1.2:
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/set-array@1.2.1:
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/sourcemap-codec@1.4.15:
+ resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ dev: true
+
+ /@jridgewell/trace-mapping@0.3.25:
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.4.15
+ dev: true
+
+ /@nodelib/fs.scandir@2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.scandir@3.0.0:
+ resolution: {integrity: sha512-ktI9+PxfHYtKjF3cLTUAh2N+b8MijCRPNwKJNqTVdL0gB0QxLU2rIRaZ1t71oEa3YBDE6bukH1sR0+CDnpp/Mg==}
+ engines: {node: '>=16.14.0'}
+ dependencies:
+ '@nodelib/fs.stat': 3.0.0
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.stat@2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /@nodelib/fs.stat@3.0.0:
+ resolution: {integrity: sha512-2tQOI38s19P9i7X/Drt0v8iMA+KMsgdhB/dyPER+e+2Y8L1Z7QvnuRdW/uLuf5YRFUYmnj4bMA6qCuZHFI1GDQ==}
+ engines: {node: '>=16.14.0'}
+ dev: true
+
+ /@nodelib/fs.walk@1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.17.1
+ dev: true
+
+ /@nodelib/fs.walk@2.0.0:
+ resolution: {integrity: sha512-54voNDBobGdMl3BUXSu7UaDh1P85PGHWlJ5e0XhPugo1JulOyCtp2I+5ri4wplGDJ8QGwPEQW7/x3yTLU7yF1A==}
+ engines: {node: '>=16.14.0'}
+ dependencies:
+ '@nodelib/fs.scandir': 3.0.0
+ fastq: 1.17.1
+ dev: true
+
+ /@npmcli/git@5.0.4:
+ resolution: {integrity: sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ '@npmcli/promise-spawn': 7.0.1
+ lru-cache: 10.2.0
+ npm-pick-manifest: 9.0.0
+ proc-log: 3.0.0
+ promise-inflight: 1.0.1
+ promise-retry: 2.0.1
+ semver: 7.6.0
+ which: 4.0.0
+ transitivePeerDependencies:
+ - bluebird
+ dev: true
+
+ /@npmcli/map-workspaces@3.0.4:
+ resolution: {integrity: sha512-Z0TbvXkRbacjFFLpVpV0e2mheCh+WzQpcqL+4xp49uNJOxOnIAPZyXtUxZ5Qn3QBTGKA11Exjd9a5411rBrhDg==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dependencies:
+ '@npmcli/name-from-folder': 2.0.0
+ glob: 10.3.10
+ minimatch: 9.0.3
+ read-package-json-fast: 3.0.2
+ dev: true
+
+ /@npmcli/name-from-folder@2.0.0:
+ resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /@npmcli/package-json@5.0.0:
+ resolution: {integrity: sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ '@npmcli/git': 5.0.4
+ glob: 10.3.10
+ hosted-git-info: 7.0.1
+ json-parse-even-better-errors: 3.0.1
+ normalize-package-data: 6.0.0
+ proc-log: 3.0.0
+ semver: 7.6.0
+ transitivePeerDependencies:
+ - bluebird
+ dev: true
+
+ /@npmcli/promise-spawn@7.0.1:
+ resolution: {integrity: sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ which: 4.0.0
+ dev: true
+
+ /@phenomnomnominal/tsquery@6.1.3(typescript@5.4.3):
+ resolution: {integrity: sha512-CEqpJ872StsxRmwv9ePCZ4BCisrJSlREUC5XxIRYxhvODt4aQoJFFmjTgaP6meyKiiXxxN/VWPZ58j4yHXRkmw==}
+ peerDependencies:
+ typescript: ^3 || ^4 || ^5
+ dependencies:
+ '@types/esquery': 1.5.3
+ esquery: 1.5.0
+ typescript: 5.4.3
+ dev: false
+
+ /@pkgjs/parseargs@0.11.0:
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+ requiresBuild: true
+ optional: true
+
+ /@pkgr/core@0.1.1:
+ resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
+ engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ dev: true
+
+ /@pnpm/constants@7.1.1:
+ resolution: {integrity: sha512-31pZqMtjwV+Vaq7MaPrT1EoDFSYwye3dp6BiHIGRJmVThCQwySRKM7hCvqqI94epNkqFAAYoWrNynWoRYosGdw==}
+ engines: {node: '>=16.14'}
+ dev: true
+
+ /@pnpm/core-loggers@9.0.6(@pnpm/logger@5.0.0):
+ resolution: {integrity: sha512-iK67SGbp+06bA/elpg51wygPFjNA7JKHtKkpLxqXXHw+AjFFBC3f2OznJsCIuDK6HdGi5UhHLYqo5QxJ2gMqJQ==}
+ engines: {node: '>=16.14'}
+ peerDependencies:
+ '@pnpm/logger': ^5.0.0
+ dependencies:
+ '@pnpm/logger': 5.0.0
+ '@pnpm/types': 9.4.2
+ dev: true
+
+ /@pnpm/error@5.0.3:
+ resolution: {integrity: sha512-ONJU5cUeoeJSy50qOYsMZQHTA/9QKmGgh1ATfEpCLgtbdwqUiwD9MxHNeXUYYI/pocBCz6r1ZCFqiQvO+8SUKA==}
+ engines: {node: '>=16.14'}
+ dependencies:
+ '@pnpm/constants': 7.1.1
+ dev: true
+
+ /@pnpm/fetching-types@5.0.0:
+ resolution: {integrity: sha512-o9gdO1v8Uc5P2fBBuW6GSpfTqIivQmQlqjQJdFiQX0m+tgxlrMRneIg392jZuc6fk7kFqjLheInlslgJfwY+4Q==}
+ engines: {node: '>=16.14'}
+ dependencies:
+ '@zkochan/retry': 0.2.0
+ node-fetch: 3.0.0-beta.9
+ transitivePeerDependencies:
+ - domexception
+ dev: true
+
+ /@pnpm/graceful-fs@3.2.0:
+ resolution: {integrity: sha512-vRoXJxscDpHak7YE9SqCkzfrayn+Lw+YueOeHIPEqkgokrHeYgYeONoc2kGh0ObHaRtNSsonozVfJ456kxLNvA==}
+ engines: {node: '>=16.14'}
+ dependencies:
+ graceful-fs: 4.2.11
+ dev: true
+
+ /@pnpm/logger@5.0.0:
+ resolution: {integrity: sha512-YfcB2QrX+Wx1o6LD1G2Y2fhDhOix/bAY/oAnMpHoNLsKkWIRbt1oKLkIFvxBMzLwAEPqnYWguJrYC+J6i4ywbw==}
+ engines: {node: '>=12.17'}
+ dependencies:
+ bole: 5.0.11
+ ndjson: 2.0.0
+ dev: true
+
+ /@pnpm/npm-package-arg@1.0.0:
+ resolution: {integrity: sha512-oQYP08exi6mOPdAZZWcNIGS+KKPsnNwUBzSuAEGWuCcqwMAt3k/WVCqVIXzBxhO5sP2b43og69VHmPj6IroKqw==}
+ engines: {node: '>=14.6'}
+ dependencies:
+ hosted-git-info: 4.1.0
+ semver: 7.6.0
+ validate-npm-package-name: 4.0.0
+ dev: true
+
+ /@pnpm/npm-resolver@18.1.1(@pnpm/logger@5.0.0):
+ resolution: {integrity: sha512-NptzncmMD5ZMimbjWkGpMzuBRhlCY+sh7mzypPdBOTNlh5hmEQe/VaRKjNK4V9/b0C/llElkvIePL6acybu86w==}
+ engines: {node: '>=16.14'}
+ peerDependencies:
+ '@pnpm/logger': ^5.0.0
+ dependencies:
+ '@pnpm/core-loggers': 9.0.6(@pnpm/logger@5.0.0)
+ '@pnpm/error': 5.0.3
+ '@pnpm/fetching-types': 5.0.0
+ '@pnpm/graceful-fs': 3.2.0
+ '@pnpm/logger': 5.0.0
+ '@pnpm/resolve-workspace-range': 5.0.1
+ '@pnpm/resolver-base': 11.1.0
+ '@pnpm/types': 9.4.2
+ '@zkochan/retry': 0.2.0
+ encode-registry: 3.0.1
+ load-json-file: 6.2.0
+ lru-cache: 10.2.0
+ normalize-path: 3.0.0
+ p-limit: 3.1.0
+ p-memoize: 4.0.1
+ parse-npm-tarball-url: 3.0.0
+ path-temp: 2.1.0
+ ramda: /@pnpm/ramda@0.28.1
+ rename-overwrite: 5.0.0
+ semver: 7.6.0
+ ssri: 10.0.5
+ version-selector-type: 3.0.0
+ transitivePeerDependencies:
+ - domexception
+ dev: true
+
+ /@pnpm/ramda@0.28.1:
+ resolution: {integrity: sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==}
+ dev: true
+
+ /@pnpm/resolve-workspace-range@5.0.1:
+ resolution: {integrity: sha512-yQ0pMthlw8rTgS/C9hrjne+NEnnSNevCjtdodd7i15I59jMBYciHifZ/vjg0NY+Jl+USTc3dBE+0h/4tdYjMKg==}
+ engines: {node: '>=16.14'}
+ dependencies:
+ semver: 7.6.0
+ dev: true
+
+ /@pnpm/resolver-base@11.1.0:
+ resolution: {integrity: sha512-y2qKaj18pwe1VWc3YXEitdYFo+WqOOt60aqTUuOVkJAirUzz0DzuYh3Ifct4znYWPdgUXHaN5DMphNF5iL85rA==}
+ engines: {node: '>=16.14'}
+ dependencies:
+ '@pnpm/types': 9.4.2
+ dev: true
+
+ /@pnpm/types@9.4.2:
+ resolution: {integrity: sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==}
+ engines: {node: '>=16.14'}
+ dev: true
+
+ /@pnpm/workspace.pkgs-graph@2.0.15(@pnpm/logger@5.0.0):
+ resolution: {integrity: sha512-Txxd5FzzVfBfGCTngISaxFlJzZhzdS8BUrCEtAWJfZOFbQzpWy27rzkaS7TaWW2dHiFcCVYzPI/2vgxfeRansA==}
+ engines: {node: '>=16.14'}
+ dependencies:
+ '@pnpm/npm-package-arg': 1.0.0
+ '@pnpm/npm-resolver': 18.1.1(@pnpm/logger@5.0.0)
+ '@pnpm/resolve-workspace-range': 5.0.1
+ ramda: /@pnpm/ramda@0.28.1
+ transitivePeerDependencies:
+ - '@pnpm/logger'
+ - domexception
+ dev: true
+
+ /@rollup/rollup-android-arm-eabi@4.13.0:
+ resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-android-arm64@4.13.0:
+ resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-darwin-arm64@4.13.0:
+ resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-darwin-x64@4.13.0:
+ resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm-gnueabihf@4.13.0:
+ resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-gnu@4.13.0:
+ resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-musl@4.13.0:
+ resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-riscv64-gnu@4.13.0:
+ resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-gnu@4.13.0:
+ resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-musl@4.13.0:
+ resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-arm64-msvc@4.13.0:
+ resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-ia32-msvc@4.13.0:
+ resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-x64-msvc@4.13.0:
+ resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sinclair/typebox@0.27.8:
+ resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+ dev: true
+
+ /@snyk/github-codeowners@1.1.0:
+ resolution: {integrity: sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw==}
+ engines: {node: '>=8.10'}
+ hasBin: true
+ dependencies:
+ commander: 4.1.1
+ ignore: 5.3.1
+ p-map: 4.0.0
+ dev: true
+
+ /@types/eslint@8.56.6:
+ resolution: {integrity: sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==}
+ dependencies:
+ '@types/estree': 1.0.5
+ '@types/json-schema': 7.0.15
+ dev: true
+
+ /@types/esquery@1.5.3:
+ resolution: {integrity: sha512-c55hQOcoPkWDfuEN9EdP1YyNH4D909U40gUEpY0nB5PWHExWHEPxcx3sx0fJ1Gzf4j1OpWktmIgciIlpgHtfDg==}
+ dependencies:
+ '@types/estree': 1.0.5
+ dev: false
+
+ /@types/estree@1.0.5:
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+
+ /@types/glob@7.2.0:
+ resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
+ dependencies:
+ '@types/minimatch': 5.1.2
+ '@types/node': 20.11.30
+ dev: true
+
+ /@types/glob@8.1.0:
+ resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
+ dependencies:
+ '@types/minimatch': 5.1.2
+ '@types/node': 20.11.30
+ dev: true
+
+ /@types/istanbul-lib-coverage@2.0.6:
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+ dev: true
+
+ /@types/json-schema@7.0.15:
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ dev: true
+
+ /@types/mdast@3.0.15:
+ resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
+ dependencies:
+ '@types/unist': 2.0.10
+ dev: true
+
+ /@types/minimatch@5.1.2:
+ resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
+ dev: true
+
+ /@types/node@20.11.30:
+ resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==}
+ dependencies:
+ undici-types: 5.26.5
+ dev: true
+
+ /@types/picomatch@2.3.3:
+ resolution: {integrity: sha512-Yll76ZHikRFCyz/pffKGjrCwe/le2CDwOP5F210KQo27kpRE46U2rDnzikNlVn6/ezH3Mhn46bJMTfeVTtcYMg==}
+ dev: true
+
+ /@types/prop-types@15.7.12:
+ resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
+ dev: true
+
+ /@types/react@18.2.69:
+ resolution: {integrity: sha512-W1HOMUWY/1Yyw0ba5TkCV+oqynRjG7BnteBB+B7JmAK7iw3l2SW+VGOxL+akPweix6jk2NNJtyJKpn4TkpfK3Q==}
+ dependencies:
+ '@types/prop-types': 15.7.12
+ '@types/scheduler': 0.16.8
+ csstype: 3.1.3
+ dev: true
+
+ /@types/scheduler@0.16.8:
+ resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==}
+ dev: true
+
+ /@types/semver@7.5.8:
+ resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
+ dev: true
+
+ /@types/unist@2.0.10:
+ resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
+ dev: true
+
+ /@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^7.0.0
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@eslint-community/regexpp': 4.10.0
+ '@typescript-eslint/parser': 7.3.1(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/scope-manager': 7.3.1
+ '@typescript-eslint/type-utils': 7.3.1(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/utils': 7.3.1(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/visitor-keys': 7.3.1
+ debug: 4.3.4(supports-color@8.1.1)
+ eslint: 8.57.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ natural-compare: 1.4.0
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/scope-manager': 7.3.1
+ '@typescript-eslint/types': 7.3.1
+ '@typescript-eslint/typescript-estree': 7.3.1(typescript@5.4.3)
+ '@typescript-eslint/visitor-keys': 7.3.1
+ debug: 4.3.4(supports-color@8.1.1)
+ eslint: 8.57.0
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/scope-manager@6.21.0:
+ resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/visitor-keys': 6.21.0
+ dev: true
+
+ /@typescript-eslint/scope-manager@7.3.1:
+ resolution: {integrity: sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ dependencies:
+ '@typescript-eslint/types': 7.3.1
+ '@typescript-eslint/visitor-keys': 7.3.1
+ dev: true
+
+ /@typescript-eslint/type-utils@7.3.1(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/typescript-estree': 7.3.1(typescript@5.4.3)
+ '@typescript-eslint/utils': 7.3.1(eslint@8.57.0)(typescript@5.4.3)
+ debug: 4.3.4(supports-color@8.1.1)
+ eslint: 8.57.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/types@6.21.0:
+ resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dev: true
+
+ /@typescript-eslint/types@7.3.1:
+ resolution: {integrity: sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ dev: true
+
+ /@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.3):
+ resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/visitor-keys': 6.21.0
+ debug: 4.3.4(supports-color@8.1.1)
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/typescript-estree@7.3.1(typescript@5.4.3):
+ resolution: {integrity: sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 7.3.1
+ '@typescript-eslint/visitor-keys': 7.3.1
+ debug: 4.3.4(supports-color@8.1.1)
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 6.21.0
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.3)
+ eslint: 8.57.0
+ semver: 7.6.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /@typescript-eslint/utils@7.3.1(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 7.3.1
+ '@typescript-eslint/types': 7.3.1
+ '@typescript-eslint/typescript-estree': 7.3.1(typescript@5.4.3)
+ eslint: 8.57.0
+ semver: 7.6.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /@typescript-eslint/visitor-keys@6.21.0:
+ resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@typescript-eslint/visitor-keys@7.3.1:
+ resolution: {integrity: sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ dependencies:
+ '@typescript-eslint/types': 7.3.1
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@ungap/structured-clone@1.2.0:
+ resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+ dev: true
+
+ /@vitest/coverage-v8@1.4.0(vitest@1.4.0):
+ resolution: {integrity: sha512-4hDGyH1SvKpgZnIByr9LhGgCEuF9DKM34IBLCC/fVfy24Z3+PZ+Ii9hsVBsHvY1umM1aGPEjceRkzxCfcQ10wg==}
+ peerDependencies:
+ vitest: 1.4.0
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@bcoe/v8-coverage': 0.2.3
+ debug: 4.3.4(supports-color@8.1.1)
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 5.0.4
+ istanbul-reports: 3.1.7
+ magic-string: 0.30.8
+ magicast: 0.3.3
+ picocolors: 1.0.0
+ std-env: 3.7.0
+ strip-literal: 2.0.0
+ test-exclude: 6.0.0
+ v8-to-istanbul: 9.2.0
+ vitest: 1.4.0(@types/node@20.11.30)
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@vitest/expect@1.4.0:
+ resolution: {integrity: sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==}
+ dependencies:
+ '@vitest/spy': 1.4.0
+ '@vitest/utils': 1.4.0
+ chai: 4.4.1
+ dev: true
+
+ /@vitest/runner@1.4.0:
+ resolution: {integrity: sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==}
+ dependencies:
+ '@vitest/utils': 1.4.0
+ p-limit: 5.0.0
+ pathe: 1.1.2
+ dev: true
+
+ /@vitest/snapshot@1.4.0:
+ resolution: {integrity: sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==}
+ dependencies:
+ magic-string: 0.30.8
+ pathe: 1.1.2
+ pretty-format: 29.7.0
+ dev: true
+
+ /@vitest/spy@1.4.0:
+ resolution: {integrity: sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==}
+ dependencies:
+ tinyspy: 2.2.1
+ dev: true
+
+ /@vitest/utils@1.4.0:
+ resolution: {integrity: sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==}
+ dependencies:
+ diff-sequences: 29.6.3
+ estree-walker: 3.0.3
+ loupe: 2.3.7
+ pretty-format: 29.7.0
+ dev: true
+
+ /@zkochan/retry@0.2.0:
+ resolution: {integrity: sha512-WhB+2B/ZPlW2Xy/kMJBrMbqecWXcbDDgn0K0wKBAgO2OlBTz1iLJrRWduo+DGGn0Akvz1Lu4Xvls7dJojximWw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /@zkochan/rimraf@2.1.3:
+ resolution: {integrity: sha512-mCfR3gylCzPC+iqdxEA6z5SxJeOgzgbwmyxanKriIne5qZLswDe/M43aD3p5MNzwzXRhbZg/OX+MpES6Zk1a6A==}
+ engines: {node: '>=12.10'}
+ dependencies:
+ rimraf: 3.0.2
+ dev: true
+
+ /acorn-jsx@5.3.2(acorn@8.11.3):
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ acorn: 8.11.3
+ dev: true
+
+ /acorn-walk@8.3.2:
+ resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /acorn@8.11.3:
+ resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /aggregate-error@3.1.0:
+ resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
+ engines: {node: '>=8'}
+ dependencies:
+ clean-stack: 2.2.0
+ indent-string: 4.0.0
+ dev: true
+
+ /ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+ dev: true
+
+ /ansi-colors@4.1.1:
+ resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /ansi-colors@4.1.3:
+ resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /ansi-escapes@6.2.0:
+ resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ type-fest: 3.13.1
+ dev: true
+
+ /ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ /ansi-regex@6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ engines: {node: '>=12'}
+
+ /ansi-styles@3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: 1.9.3
+ dev: true
+
+ /ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+
+ /ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
+
+ /any-promise@1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+ dev: true
+
+ /anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+ dev: true
+
+ /are-docs-informative@0.0.2:
+ resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ dependencies:
+ sprintf-js: 1.0.3
+ dev: true
+
+ /argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ dev: true
+
+ /arity-n@1.0.4:
+ resolution: {integrity: sha512-fExL2kFDC1Q2DUOx3whE/9KoN66IzkY4b4zUHUBFM1ojEYjZZYDcUW3bek/ufGionX9giIKDC5redH2IlGqcQQ==}
+ dev: true
+
+ /array-last@1.3.0:
+ resolution: {integrity: sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-number: 4.0.0
+ dev: true
+
+ /array-timsort@1.0.3:
+ resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
+ dev: true
+
+ /array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /assertion-error@1.1.0:
+ resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ dev: true
+
+ /automutate-tests@0.5.0:
+ resolution: {integrity: sha512-MqYx7tloN0HhwE/1uaow81ld8URhm9UJ6j6SIlFTLLqDjtj3qAL0FfeFsfz4yidrxGIvSX5RNMs8NwZ63RtJJg==}
+ dependencies:
+ automutate: 0.9.0
+ chai: 4.4.1
+ chalk: 2.4.2
+ glob: 7.2.3
+ mz: 2.7.0
+ dev: true
+
+ /automutate@0.9.0:
+ resolution: {integrity: sha512-A1AydgfyQCGAihiu3NciBtRAbVw0HPHfwz7wRow3rYRSpT3BrTGSWX7vFJlXjbF1On3hKfzsa4ZWsAcAnAgTVg==}
+
+ /babylon@6.18.0:
+ resolution: {integrity: sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==}
+ hasBin: true
+ dev: true
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ /binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /bole@5.0.11:
+ resolution: {integrity: sha512-KB0Ye0iMAW5BnNbnLfMSQcnI186hKUzE2fpkZWqcxsoTR7eqzlTidSOMYPHJOn/yR7VGH7uSZp37qH9q2Et0zQ==}
+ dependencies:
+ fast-safe-stringify: 2.1.1
+ individual: 3.0.0
+ dev: true
+
+ /brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+ dev: true
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+
+ /braces@3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+ dev: true
+
+ /browser-stdout@1.3.1:
+ resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==}
+ dev: true
+
+ /builtin-modules@3.3.0:
+ resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
+ engines: {node: '>=6'}
+
+ /builtins@5.0.1:
+ resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==}
+ dependencies:
+ semver: 7.6.0
+ dev: true
+
+ /bundle-require@4.0.2(esbuild@0.19.12):
+ resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ peerDependencies:
+ esbuild: '>=0.17'
+ dependencies:
+ esbuild: 0.19.12
+ load-tsconfig: 0.2.5
+ dev: true
+
+ /cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /camelcase@6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /chai@4.4.1:
+ resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==}
+ engines: {node: '>=4'}
+ dependencies:
+ assertion-error: 1.1.0
+ check-error: 1.0.3
+ deep-eql: 4.1.3
+ get-func-name: 2.0.2
+ loupe: 2.3.7
+ pathval: 1.1.1
+ type-detect: 4.0.8
+ dev: true
+
+ /chalk-template@1.1.0:
+ resolution: {integrity: sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ chalk: 5.3.0
+ dev: true
+
+ /chalk@2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+ dev: true
+
+ /chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+ dev: true
+
+ /chalk@5.3.0:
+ resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
+ /character-entities-legacy@1.1.4:
+ resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==}
+ dev: true
+
+ /character-entities@1.2.4:
+ resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==}
+ dev: true
+
+ /character-reference-invalid@1.1.4:
+ resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
+ dev: true
+
+ /check-error@1.0.3:
+ resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+ dependencies:
+ get-func-name: 2.0.2
+ dev: true
+
+ /chokidar@3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
+ /chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
+ /clean-stack@2.2.0:
+ resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /clear-module@4.1.2:
+ resolution: {integrity: sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==}
+ engines: {node: '>=8'}
+ dependencies:
+ parent-module: 2.0.0
+ resolve-from: 5.0.0
+ dev: true
+
+ /cli-cursor@4.0.0:
+ resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ restore-cursor: 4.0.0
+ dev: true
+
+ /cli-truncate@4.0.0:
+ resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
+ engines: {node: '>=18'}
+ dependencies:
+ slice-ansi: 5.0.0
+ string-width: 7.1.0
+ dev: true
+
+ /cliui@7.0.4:
+ resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /clone@1.0.4:
+ resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
+ engines: {node: '>=0.8'}
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ dependencies:
+ color-name: 1.1.3
+ dev: true
+
+ /color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+
+ /color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+ dev: true
+
+ /color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ /colorette@2.0.20:
+ resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+ dev: true
+
+ /commander@11.1.0:
+ resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
+ engines: {node: '>=16'}
+ dev: true
+
+ /commander@12.0.0:
+ resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==}
+ engines: {node: '>=18'}
+
+ /commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /comment-json@4.2.3:
+ resolution: {integrity: sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==}
+ engines: {node: '>= 6'}
+ dependencies:
+ array-timsort: 1.0.3
+ core-util-is: 1.0.3
+ esprima: 4.0.1
+ has-own-prop: 2.0.0
+ repeat-string: 1.6.1
+ dev: true
+
+ /comment-parser@1.4.1:
+ resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
+ engines: {node: '>= 12.0.0'}
+ dev: true
+
+ /compose-function@3.0.3:
+ resolution: {integrity: sha512-xzhzTJ5eC+gmIzvZq+C3kCJHsp9os6tJkrigDRZclyGtOKINbZtE8n1Tzmeh32jW+BUDPbvZpibwvJHBLGMVwg==}
+ dependencies:
+ arity-n: 1.0.4
+ dev: true
+
+ /concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ dev: true
+
+ /configstore@6.0.0:
+ resolution: {integrity: sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==}
+ engines: {node: '>=12'}
+ dependencies:
+ dot-prop: 6.0.1
+ graceful-fs: 4.2.11
+ unique-string: 3.0.0
+ write-file-atomic: 3.0.3
+ xdg-basedir: 5.1.0
+ dev: true
+
+ /console-fail-test@0.2.3:
+ resolution: {integrity: sha512-p1xfi9ubVM2X3NpjPH1Gm8Gxc7vXyTwcOIquU8rpUDA+ISSitAOiBDnT/Bti1We5YzZKRxgI0JU+fFvOmOXtvA==}
+ dev: true
+
+ /convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ dev: true
+
+ /core-util-is@1.0.3:
+ resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ dev: true
+
+ /cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ /crypto-random-string@2.0.0:
+ resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /crypto-random-string@4.0.0:
+ resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}
+ engines: {node: '>=12'}
+ dependencies:
+ type-fest: 1.4.0
+ dev: true
+
+ /cspell-config-lib@8.6.0:
+ resolution: {integrity: sha512-Q1rvQFUDJTu4hUtxwL6+q83Hjx/a5grEjMS5axxFJzjJuFRbRsXCagncdSCx/YBqLkNM5noBbRP/0rVh7ufqxw==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/cspell-types': 8.6.0
+ comment-json: 4.2.3
+ yaml: 2.4.1
+ dev: true
+
+ /cspell-dictionary@8.6.0:
+ resolution: {integrity: sha512-ohToeOQznIrb2/z7RfKxX3NID0WiO4sXK3IxKdnbn2viGgdn17tQ8Z2f4Xuy9egjSGRKyr6N25Z5AOes1C8R3w==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/cspell-pipe': 8.6.0
+ '@cspell/cspell-types': 8.6.0
+ cspell-trie-lib: 8.6.0
+ fast-equals: 5.0.1
+ gensequence: 7.0.0
+ dev: true
+
+ /cspell-gitignore@8.6.0:
+ resolution: {integrity: sha512-6INRlNb17iKtQH7NmDM/EsX5OZOD2TzIwHiJnnWci0Y5l10V/zN9WGLDegTjMh9HU3TS6uUuN4I/ffkCs9m+LA==}
+ engines: {node: '>=18'}
+ hasBin: true
+ dependencies:
+ cspell-glob: 8.6.0
+ find-up-simple: 1.0.0
+ dev: true
+
+ /cspell-glob@8.6.0:
+ resolution: {integrity: sha512-AyuExc34F8JsEYNl4inx1m1v5VoSRA/cTptREq/AoNTcMTyG5s+wt5J+VWBfvJjEDEEpd9Cb2it0j8TMo/Tpjw==}
+ engines: {node: '>=18'}
+ dependencies:
+ micromatch: 4.0.5
+ dev: true
+
+ /cspell-grammar@8.6.0:
+ resolution: {integrity: sha512-wVpZ4pPOqRoOmzLUc34wyOQnBi/6RsV3Y1KiPn8BNSkObb9XSohb1xJJMJ69unEmgE0snQDMHIeUaLTQH414MA==}
+ engines: {node: '>=18'}
+ hasBin: true
+ dependencies:
+ '@cspell/cspell-pipe': 8.6.0
+ '@cspell/cspell-types': 8.6.0
+ dev: true
+
+ /cspell-io@8.6.0:
+ resolution: {integrity: sha512-jx7ccRpcshqxN6xnOiGnX4VycaqTpmatRjHITn4vLoDmQNfxQeU69YT62bhyjogCBuJsZS9ksjo7GQIsrYBekA==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/cspell-service-bus': 8.6.0
+ dev: true
+
+ /cspell-lib@8.6.0:
+ resolution: {integrity: sha512-l1bBxBz8noPOxEIIu1Ahvd4e/j6Re1PNDD9FwZgaRmvMyIPZbupTxzCM0MZWvYz1VymBmrrVEKRwtZ34VocaCw==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/cspell-bundled-dicts': 8.6.0
+ '@cspell/cspell-pipe': 8.6.0
+ '@cspell/cspell-resolver': 8.6.0
+ '@cspell/cspell-types': 8.6.0
+ '@cspell/dynamic-import': 8.6.0
+ '@cspell/strong-weak-map': 8.6.0
+ clear-module: 4.1.2
+ comment-json: 4.2.3
+ configstore: 6.0.0
+ cspell-config-lib: 8.6.0
+ cspell-dictionary: 8.6.0
+ cspell-glob: 8.6.0
+ cspell-grammar: 8.6.0
+ cspell-io: 8.6.0
+ cspell-trie-lib: 8.6.0
+ fast-equals: 5.0.1
+ gensequence: 7.0.0
+ import-fresh: 3.3.0
+ resolve-from: 5.0.0
+ vscode-languageserver-textdocument: 1.0.11
+ vscode-uri: 3.0.8
+ dev: true
+
+ /cspell-trie-lib@8.6.0:
+ resolution: {integrity: sha512-S8nGCnEJBL1maiKPd3FhI54QG+OgtOkcJ/yUDXGXGrokSruWFdNocioPirlFAHf959ax1GBUVEYNIgnu/EIWNg==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@cspell/cspell-pipe': 8.6.0
+ '@cspell/cspell-types': 8.6.0
+ gensequence: 7.0.0
+ dev: true
+
+ /cspell@8.6.0:
+ resolution: {integrity: sha512-aAaVD3v1105OQePCpcdYkHnHxxkxKxxQzFcfJ4tKsH06dlW04Sp1oQLlsjgWDa3y6cdYTpSYj1eSenavBvfOFg==}
+ engines: {node: '>=18'}
+ hasBin: true
+ dependencies:
+ '@cspell/cspell-json-reporter': 8.6.0
+ '@cspell/cspell-pipe': 8.6.0
+ '@cspell/cspell-types': 8.6.0
+ '@cspell/dynamic-import': 8.6.0
+ chalk: 5.3.0
+ chalk-template: 1.1.0
+ commander: 12.0.0
+ cspell-gitignore: 8.6.0
+ cspell-glob: 8.6.0
+ cspell-io: 8.6.0
+ cspell-lib: 8.6.0
+ fast-glob: 3.3.2
+ fast-json-stable-stringify: 2.1.0
+ file-entry-cache: 8.0.0
+ get-stdin: 9.0.0
+ semver: 7.6.0
+ strip-ansi: 7.1.0
+ vscode-uri: 3.0.8
+ dev: true
+
+ /csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ dev: true
+
+ /data-uri-to-buffer@3.0.1:
+ resolution: {integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /debug@4.3.4(supports-color@8.1.1):
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+ supports-color: 8.1.1
+ dev: true
+
+ /decamelize@4.0.0:
+ resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /deep-eql@4.1.3:
+ resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
+ engines: {node: '>=6'}
+ dependencies:
+ type-detect: 4.0.8
+ dev: true
+
+ /deep-extend@0.6.0:
+ resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
+ engines: {node: '>=4.0.0'}
+ dev: true
+
+ /deep-freeze@0.0.1:
+ resolution: {integrity: sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg==}
+ dev: true
+
+ /deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ dev: true
+
+ /defaults@1.0.4:
+ resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+ requiresBuild: true
+ dependencies:
+ clone: 1.0.4
+ dev: true
+ optional: true
+
+ /detect-indent@6.1.0:
+ resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /detect-indent@7.0.1:
+ resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==}
+ engines: {node: '>=12.20'}
+ dev: true
+
+ /detect-newline@3.1.0:
+ resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /detect-newline@4.0.1:
+ resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /diff-sequences@29.6.3:
+ resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dev: true
+
+ /diff@5.0.0:
+ resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==}
+ engines: {node: '>=0.3.1'}
+ dev: true
+
+ /dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-type: 4.0.0
+ dev: true
+
+ /doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /dot-prop@6.0.1:
+ resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
+ engines: {node: '>=10'}
+ dependencies:
+ is-obj: 2.0.0
+ dev: true
+
+ /eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+ /easy-table@1.2.0:
+ resolution: {integrity: sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==}
+ dependencies:
+ ansi-regex: 5.0.1
+ optionalDependencies:
+ wcwidth: 1.0.1
+ dev: true
+
+ /emoji-regex@10.3.0:
+ resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
+ dev: true
+
+ /emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ /emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ /encode-registry@3.0.1:
+ resolution: {integrity: sha512-6qOwkl1g0fv0DN3Y3ggr2EaZXN71aoAqPp3p/pVaWSBSIo+YjLOWN61Fva43oVyQNPf7kgm8lkudzlzojwE2jw==}
+ engines: {node: '>=10'}
+ dependencies:
+ mem: 8.1.1
+ dev: true
+
+ /enquirer@2.4.1:
+ resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ ansi-colors: 4.1.3
+ strip-ansi: 6.0.1
+ dev: false
+
+ /entities@1.1.2:
+ resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
+ dev: true
+
+ /entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+ dev: true
+
+ /err-code@2.0.3:
+ resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
+ dev: true
+
+ /error-ex@1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ dependencies:
+ is-arrayish: 0.2.1
+ dev: true
+
+ /esbuild@0.19.12:
+ resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.19.12
+ '@esbuild/android-arm': 0.19.12
+ '@esbuild/android-arm64': 0.19.12
+ '@esbuild/android-x64': 0.19.12
+ '@esbuild/darwin-arm64': 0.19.12
+ '@esbuild/darwin-x64': 0.19.12
+ '@esbuild/freebsd-arm64': 0.19.12
+ '@esbuild/freebsd-x64': 0.19.12
+ '@esbuild/linux-arm': 0.19.12
+ '@esbuild/linux-arm64': 0.19.12
+ '@esbuild/linux-ia32': 0.19.12
+ '@esbuild/linux-loong64': 0.19.12
+ '@esbuild/linux-mips64el': 0.19.12
+ '@esbuild/linux-ppc64': 0.19.12
+ '@esbuild/linux-riscv64': 0.19.12
+ '@esbuild/linux-s390x': 0.19.12
+ '@esbuild/linux-x64': 0.19.12
+ '@esbuild/netbsd-x64': 0.19.12
+ '@esbuild/openbsd-x64': 0.19.12
+ '@esbuild/sunos-x64': 0.19.12
+ '@esbuild/win32-arm64': 0.19.12
+ '@esbuild/win32-ia32': 0.19.12
+ '@esbuild/win32-x64': 0.19.12
+ dev: true
+
+ /esbuild@0.20.2:
+ resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.20.2
+ '@esbuild/android-arm': 0.20.2
+ '@esbuild/android-arm64': 0.20.2
+ '@esbuild/android-x64': 0.20.2
+ '@esbuild/darwin-arm64': 0.20.2
+ '@esbuild/darwin-x64': 0.20.2
+ '@esbuild/freebsd-arm64': 0.20.2
+ '@esbuild/freebsd-x64': 0.20.2
+ '@esbuild/linux-arm': 0.20.2
+ '@esbuild/linux-arm64': 0.20.2
+ '@esbuild/linux-ia32': 0.20.2
+ '@esbuild/linux-loong64': 0.20.2
+ '@esbuild/linux-mips64el': 0.20.2
+ '@esbuild/linux-ppc64': 0.20.2
+ '@esbuild/linux-riscv64': 0.20.2
+ '@esbuild/linux-s390x': 0.20.2
+ '@esbuild/linux-x64': 0.20.2
+ '@esbuild/netbsd-x64': 0.20.2
+ '@esbuild/openbsd-x64': 0.20.2
+ '@esbuild/sunos-x64': 0.20.2
+ '@esbuild/win32-arm64': 0.20.2
+ '@esbuild/win32-ia32': 0.20.2
+ '@esbuild/win32-x64': 0.20.2
+ dev: true
+
+ /escalade@3.1.2:
+ resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /escape-string-regexp@1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+ dev: true
+
+ /escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /eslint-compat-utils@0.5.0(eslint@8.57.0):
+ resolution: {integrity: sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ eslint: '>=6.0.0'
+ dependencies:
+ eslint: 8.57.0
+ semver: 7.6.0
+ dev: true
+
+ /eslint-plugin-deprecation@2.0.0(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0
+ typescript: ^4.2.4 || ^5.0.0
+ dependencies:
+ '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3)
+ eslint: 8.57.0
+ tslib: 2.6.2
+ tsutils: 3.21.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-plugin-es-x@7.6.0(eslint@8.57.0):
+ resolution: {integrity: sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=8'
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/regexpp': 4.10.0
+ eslint: 8.57.0
+ eslint-compat-utils: 0.5.0(eslint@8.57.0)
+ dev: true
+
+ /eslint-plugin-eslint-comments@3.2.0(eslint@8.57.0):
+ resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==}
+ engines: {node: '>=6.5.0'}
+ peerDependencies:
+ eslint: '>=4.19.1'
+ dependencies:
+ escape-string-regexp: 1.0.5
+ eslint: 8.57.0
+ ignore: 5.3.1
+ dev: true
+
+ /eslint-plugin-jsdoc@48.2.1(eslint@8.57.0):
+ resolution: {integrity: sha512-iUvbcyDZSO/9xSuRv2HQBw++8VkV/pt3UWtX9cpPH0l7GKPq78QC/6+PmyQHHvNZaTjAce6QVciEbnc6J/zH5g==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
+ dependencies:
+ '@es-joy/jsdoccomment': 0.42.0
+ are-docs-informative: 0.0.2
+ comment-parser: 1.4.1
+ debug: 4.3.4(supports-color@8.1.1)
+ escape-string-regexp: 4.0.0
+ eslint: 8.57.0
+ esquery: 1.5.0
+ is-builtin-module: 3.2.1
+ semver: 7.6.0
+ spdx-expression-parse: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-plugin-jsonc@2.14.1(eslint@8.57.0):
+ resolution: {integrity: sha512-Tei6G4N7pZulP5MHi0EIdtseiCqUPkDMd0O8Zrw4muMIlsjJ5/B9X+U3Pfo6B7l0mTL9LN9FwuWT70dRJ6z7tg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=6.0.0'
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ eslint: 8.57.0
+ eslint-compat-utils: 0.5.0(eslint@8.57.0)
+ espree: 9.6.1
+ graphemer: 1.4.0
+ jsonc-eslint-parser: 2.4.0
+ natural-compare: 1.4.0
+ synckit: 0.6.2
+ dev: true
+
+ /eslint-plugin-markdown@4.0.1(eslint@8.57.0):
+ resolution: {integrity: sha512-5/MnGvYU0i8MbHH5cg8S+Vl3DL+bqRNYshk1xUO86DilNBaxtTkhH+5FD0/yO03AmlI6+lfNFdk2yOw72EPzpA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: '>=8'
+ dependencies:
+ eslint: 8.57.0
+ mdast-util-from-markdown: 0.8.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-plugin-n@16.6.2(eslint@8.57.0):
+ resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ eslint: '>=7.0.0'
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ builtins: 5.0.1
+ eslint: 8.57.0
+ eslint-plugin-es-x: 7.6.0(eslint@8.57.0)
+ get-tsconfig: 4.7.3
+ globals: 13.24.0
+ ignore: 5.3.1
+ is-builtin-module: 3.2.1
+ is-core-module: 2.13.1
+ minimatch: 3.1.2
+ resolve: 1.22.8
+ semver: 7.6.0
+ dev: true
+
+ /eslint-plugin-package-json@0.10.4(eslint@8.57.0)(jsonc-eslint-parser@2.4.0):
+ resolution: {integrity: sha512-dape6w9G7hCXDkoVWoPwrQjUK0V6636qAgUPewduXLH9RdEw/y4XGqCyvD5KujlMBQuagadMkxuGNluW0GC4vQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ eslint: '>=8.0.0'
+ jsonc-eslint-parser: ^2.0.0
+ dependencies:
+ eslint: 8.57.0
+ jsonc-eslint-parser: 2.4.0
+ package-json-validator: 0.6.3
+ semver: 7.6.0
+ sort-package-json: 1.57.0
+ validate-npm-package-name: 5.0.0
+ dev: true
+
+ /eslint-plugin-perfectionist@2.7.0(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-RpSMc0T0DT9DlOj4APzwlAjCqQMxFdsIYlupe73eDkKLn1mMK7fVw2z3nj2y822szKOpvHA7bDa56ySOlr4GXw==}
+ peerDependencies:
+ astro-eslint-parser: ^0.16.0
+ eslint: '>=8.0.0'
+ svelte: '>=3.0.0'
+ svelte-eslint-parser: ^0.33.0
+ vue-eslint-parser: '>=9.0.0'
+ peerDependenciesMeta:
+ astro-eslint-parser:
+ optional: true
+ svelte:
+ optional: true
+ svelte-eslint-parser:
+ optional: true
+ vue-eslint-parser:
+ optional: true
+ dependencies:
+ '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3)
+ eslint: 8.57.0
+ minimatch: 9.0.3
+ natural-compare-lite: 1.4.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /eslint-plugin-regexp@2.3.0(eslint@8.57.0):
+ resolution: {integrity: sha512-T8JUs7ssRGbuXb+CGfdUJbcxTBMCNOpNqNBLuC8JUKAEIez72J37RaOi5/4dAUsGz92GbWVtqTLPSJZGyP/sQA==}
+ engines: {node: ^18 || >=20}
+ peerDependencies:
+ eslint: '>=8.44.0'
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/regexpp': 4.10.0
+ comment-parser: 1.4.1
+ eslint: 8.57.0
+ jsdoc-type-pratt-parser: 4.0.0
+ refa: 0.12.1
+ regexp-ast-analysis: 0.7.1
+ scslre: 0.3.0
+ dev: true
+
+ /eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.3.1)(eslint@8.57.0)(typescript@5.4.3)(vitest@1.4.0):
+ resolution: {integrity: sha512-oxe5JSPgRjco8caVLTh7Ti8PxpwJdhSV0hTQAmkFcNcmy/9DnqLB/oNVRA11RmVRP//2+jIIT6JuBEcpW3obYg==}
+ engines: {node: ^18.0.0 || >= 20.0.0}
+ peerDependencies:
+ '@typescript-eslint/eslint-plugin': '*'
+ eslint: '>=8.0.0'
+ vitest: '*'
+ peerDependenciesMeta:
+ '@typescript-eslint/eslint-plugin':
+ optional: true
+ vitest:
+ optional: true
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 7.3.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/utils': 7.3.1(eslint@8.57.0)(typescript@5.4.3)
+ eslint: 8.57.0
+ vitest: 1.4.0(@types/node@20.11.30)
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /eslint-plugin-yml@1.13.2(eslint@8.57.0):
+ resolution: {integrity: sha512-1i71VhmsG5UxE41rIJmJjhlTTxYy7upAY5Hqj8AdBc7rfJzRIZr3a2spuOS8+N7ZDCWsHAWY3J6lzQNQHDv6Uw==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=6.0.0'
+ dependencies:
+ debug: 4.3.4(supports-color@8.1.1)
+ eslint: 8.57.0
+ eslint-compat-utils: 0.5.0(eslint@8.57.0)
+ lodash: 4.17.21
+ natural-compare: 1.4.0
+ yaml-eslint-parser: 1.2.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-scope@7.2.2:
+ resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint@8.57.0:
+ resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/regexpp': 4.10.0
+ '@eslint/eslintrc': 2.1.4
+ '@eslint/js': 8.57.0
+ '@humanwhocodes/config-array': 0.11.14
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ '@ungap/structured-clone': 1.2.0
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4(supports-color@8.1.1)
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.24.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.3
+ strip-ansi: 6.0.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree@9.6.1:
+ resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.11.3
+ acorn-jsx: 5.3.2(acorn@8.11.3)
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /esquery@1.5.0:
+ resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+
+ /esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ /estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+ dependencies:
+ '@types/estree': 1.0.5
+ dev: true
+
+ /esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /eventemitter3@5.0.1:
+ resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+ dev: true
+
+ /execa@5.1.1:
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+ engines: {node: '>=10'}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 6.0.1
+ human-signals: 2.1.0
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+ dev: true
+
+ /execa@8.0.1:
+ resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+ engines: {node: '>=16.17'}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 8.0.1
+ human-signals: 5.0.0
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 4.1.0
+ strip-final-newline: 3.0.0
+ dev: true
+
+ /fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ dev: true
+
+ /fast-equals@5.0.1:
+ resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /fast-glob@3.3.2:
+ resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.5
+ dev: true
+
+ /fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ dev: true
+
+ /fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ dev: true
+
+ /fast-safe-stringify@2.1.1:
+ resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ dev: true
+
+ /fastq@1.17.1:
+ resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+ dependencies:
+ reusify: 1.0.4
+ dev: true
+
+ /fetch-blob@2.1.2:
+ resolution: {integrity: sha512-YKqtUDwqLyfyMnmbw8XD6Q8j9i/HggKtPEI+pZ1+8bvheBu78biSmNaXWusx1TauGqtUUGx/cBb1mKdq2rLYow==}
+ engines: {node: ^10.17.0 || >=12.3.0}
+ peerDependencies:
+ domexception: '*'
+ peerDependenciesMeta:
+ domexception:
+ optional: true
+ dev: true
+
+ /file-entry-cache@6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.2.0
+ dev: true
+
+ /file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+ dependencies:
+ flat-cache: 4.0.1
+ dev: true
+
+ /fill-range@7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+ dev: true
+
+ /filter-iterator@0.0.1:
+ resolution: {integrity: sha512-v4lhL7Qa8XpbW3LN46CEnmhGk3eHZwxfNl5at20aEkreesht4YKb/Ba3BUIbnPhAC/r3dmu7ABaGk6MAvh2alA==}
+ dev: true
+
+ /filter-obj@1.1.0:
+ resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /find-up-simple@1.0.0:
+ resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /flat-cache@3.2.0:
+ resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.3.1
+ keyv: 4.5.4
+ rimraf: 3.0.2
+ dev: true
+
+ /flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+ dependencies:
+ flatted: 3.3.1
+ keyv: 4.5.4
+ dev: true
+
+ /flat@5.0.2:
+ resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
+ hasBin: true
+ dev: true
+
+ /flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+ dev: true
+
+ /foreground-child@3.1.1:
+ resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+ engines: {node: '>=14'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 4.1.0
+
+ /fs-extra@10.1.0:
+ resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 6.1.0
+ universalify: 2.0.1
+ dev: true
+
+ /fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ dev: true
+
+ /fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ dev: true
+
+ /gensequence@7.0.0:
+ resolution: {integrity: sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dev: true
+
+ /get-east-asian-width@1.2.0:
+ resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /get-func-name@2.0.2:
+ resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+ dev: true
+
+ /get-stdin@9.0.0:
+ resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /get-stream@8.0.1:
+ resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+ engines: {node: '>=16'}
+ dev: true
+
+ /get-tsconfig@4.7.3:
+ resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==}
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+ dev: true
+
+ /git-hooks-list@1.0.3:
+ resolution: {integrity: sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ==}
+ dev: true
+
+ /git-hooks-list@3.1.0:
+ resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==}
+ dev: true
+
+ /glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob@10.3.10:
+ resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ foreground-child: 3.1.1
+ jackspeak: 2.3.6
+ minimatch: 9.0.3
+ minipass: 7.0.4
+ path-scurry: 1.10.1
+
+ /glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /glob@8.1.0:
+ resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 5.0.1
+ once: 1.4.0
+ dev: true
+
+ /global-directory@4.0.1:
+ resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
+ engines: {node: '>=18'}
+ dependencies:
+ ini: 4.1.1
+ dev: true
+
+ /globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /globals@13.24.0:
+ resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /globby@10.0.0:
+ resolution: {integrity: sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@types/glob': 7.2.0
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ glob: 7.2.3
+ ignore: 5.3.1
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.1
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /globby@13.2.2:
+ resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.1
+ merge2: 1.4.1
+ slash: 4.0.0
+ dev: true
+
+ /graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ dev: true
+
+ /graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ dev: true
+
+ /has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /has-own-prop@2.0.0:
+ resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /has-own-property@0.1.0:
+ resolution: {integrity: sha512-14qdBKoonU99XDhWcFKZTShK+QV47qU97u8zzoVo9cL5TZ3BmBHXogItSt9qJjR0KUMFRhcCW8uGIGl8nkl7Aw==}
+ dev: true
+
+ /hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ function-bind: 1.1.2
+ dev: true
+
+ /he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+ dev: true
+
+ /hosted-git-info@4.1.0:
+ resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
+ engines: {node: '>=10'}
+ dependencies:
+ lru-cache: 6.0.0
+ dev: true
+
+ /hosted-git-info@7.0.1:
+ resolution: {integrity: sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ lru-cache: 10.2.0
+ dev: true
+
+ /html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+ dev: true
+
+ /human-signals@2.1.0:
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+ engines: {node: '>=10.17.0'}
+ dev: true
+
+ /human-signals@5.0.0:
+ resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+ engines: {node: '>=16.17.0'}
+ dev: true
+
+ /husky@9.0.11:
+ resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==}
+ engines: {node: '>=18'}
+ hasBin: true
+ dev: true
+
+ /identity-function@1.0.0:
+ resolution: {integrity: sha512-kNrgUK0qI+9qLTBidsH85HjDLpZfrrS0ElquKKe/fJFdB3D7VeKdXXEvOPDUHSHOzdZKCAAaQIWWyp0l2yq6pw==}
+ dev: true
+
+ /ignore@5.3.1:
+ resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+ dev: true
+
+ /import-meta-resolve@4.0.0:
+ resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==}
+ dev: true
+
+ /imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+ dev: true
+
+ /indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /individual@3.0.0:
+ resolution: {integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==}
+ dev: true
+
+ /inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+ dev: true
+
+ /inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ dev: true
+
+ /ini@4.1.1:
+ resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /ini@4.1.2:
+ resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /is-alphabetical@1.0.4:
+ resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==}
+ dev: true
+
+ /is-alphanumerical@1.0.4:
+ resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==}
+ dependencies:
+ is-alphabetical: 1.0.4
+ is-decimal: 1.0.4
+ dev: true
+
+ /is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ dev: true
+
+ /is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.3.0
+ dev: true
+
+ /is-builtin-module@3.2.1:
+ resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
+ engines: {node: '>=6'}
+ dependencies:
+ builtin-modules: 3.3.0
+ dev: true
+
+ /is-core-module@2.13.1:
+ resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ dependencies:
+ hasown: 2.0.2
+ dev: true
+
+ /is-decimal@1.0.4:
+ resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==}
+ dev: true
+
+ /is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ /is-fullwidth-code-point@4.0.0:
+ resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /is-fullwidth-code-point@5.0.0:
+ resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
+ engines: {node: '>=18'}
+ dependencies:
+ get-east-asian-width: 1.2.0
+ dev: true
+
+ /is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+ dev: true
+
+ /is-hexadecimal@1.0.4:
+ resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==}
+ dev: true
+
+ /is-iterable@1.1.1:
+ resolution: {integrity: sha512-EdOZCr0NsGE00Pot+x1ZFx9MJK3C6wy91geZpXwvwexDLJvA4nzYyZf7r+EIwSeVsOLDdBz7ATg9NqKTzuNYuQ==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /is-number@4.0.0:
+ resolution: {integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+ dev: true
+
+ /is-obj@2.0.0:
+ resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-path-inside@3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-plain-obj@2.1.0:
+ resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-plain-obj@4.1.0:
+ resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /is-typedarray@1.0.0:
+ resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+ dev: true
+
+ /is-unicode-supported@0.1.0:
+ resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ /isexe@3.1.1:
+ resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
+ engines: {node: '>=16'}
+ dev: true
+
+ /istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+ dev: true
+
+ /istanbul-lib-source-maps@5.0.4:
+ resolution: {integrity: sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ debug: 4.3.4(supports-color@8.1.1)
+ istanbul-lib-coverage: 3.2.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /istanbul-reports@3.1.7:
+ resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
+ engines: {node: '>=8'}
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+ dev: true
+
+ /iterable-lookahead@1.0.0:
+ resolution: {integrity: sha512-hJnEP2Xk4+44DDwJqUQGdXal5VbyeWLaPyDl2AQc242Zr7iqz4DgpQOrEzglWVMGHMDCkguLHEKxd1+rOsmgSQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /jackspeak@2.3.6:
+ resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
+ /jiti@1.21.0:
+ resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
+ hasBin: true
+ dev: true
+
+ /joycon@3.1.1:
+ resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ dev: true
+
+ /js-tokens@8.0.3:
+ resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==}
+ dev: true
+
+ /js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ dev: true
+
+ /jsdoc-type-pratt-parser@4.0.0:
+ resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==}
+ engines: {node: '>=12.0.0'}
+ dev: true
+
+ /jsesc@2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ dev: true
+
+ /json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ dev: true
+
+ /json-parse-even-better-errors@3.0.1:
+ resolution: {integrity: sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ dev: true
+
+ /json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ dev: true
+
+ /json-stringify-safe@5.0.1:
+ resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+ dev: true
+
+ /jsonc-eslint-parser@2.4.0:
+ resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.11.3
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ semver: 7.6.0
+ dev: true
+
+ /jsonc-parser@3.2.1:
+ resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==}
+ dev: true
+
+ /jsonfile@6.1.0:
+ resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ dependencies:
+ universalify: 2.0.1
+ optionalDependencies:
+ graceful-fs: 4.2.11
+ dev: true
+
+ /keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ dependencies:
+ json-buffer: 3.0.1
+ dev: true
+
+ /knip@5.2.2(@types/node@20.11.30)(typescript@5.4.3):
+ resolution: {integrity: sha512-4HMMUFk34KOE37NzmDnxWhBH6WMfStqN5jTPGXS7lq+Z6WvQxjWMo/ewuhPje4+BBN6LYWw+aiQOsbo9FHYhpw==}
+ engines: {node: '>=18.6.0'}
+ hasBin: true
+ peerDependencies:
+ '@types/node': '>=18'
+ typescript: '>=5.0.4'
+ dependencies:
+ '@ericcornelissen/bash-parser': 0.5.2
+ '@nodelib/fs.walk': 2.0.0
+ '@npmcli/map-workspaces': 3.0.4
+ '@npmcli/package-json': 5.0.0
+ '@pnpm/logger': 5.0.0
+ '@pnpm/workspace.pkgs-graph': 2.0.15(@pnpm/logger@5.0.0)
+ '@snyk/github-codeowners': 1.1.0
+ '@types/node': 20.11.30
+ '@types/picomatch': 2.3.3
+ easy-table: 1.2.0
+ fast-glob: 3.3.2
+ jiti: 1.21.0
+ js-yaml: 4.1.0
+ micromatch: 4.0.5
+ minimist: 1.2.8
+ picocolors: 1.0.0
+ picomatch: 4.0.1
+ pretty-ms: 9.0.0
+ smol-toml: 1.1.4
+ strip-json-comments: 5.0.1
+ summary: 2.1.0
+ typescript: 5.4.3
+ zod: 3.22.4
+ zod-validation-error: 3.0.3(zod@3.22.4)
+ transitivePeerDependencies:
+ - bluebird
+ - domexception
+ dev: true
+
+ /levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /lilconfig@3.0.0:
+ resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /lilconfig@3.1.1:
+ resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ dev: true
+
+ /linkify-it@2.2.0:
+ resolution: {integrity: sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==}
+ dependencies:
+ uc.micro: 1.0.6
+ dev: true
+
+ /linkify-it@5.0.0:
+ resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
+ dependencies:
+ uc.micro: 2.1.0
+ dev: true
+
+ /lint-staged@15.2.2:
+ resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==}
+ engines: {node: '>=18.12.0'}
+ hasBin: true
+ dependencies:
+ chalk: 5.3.0
+ commander: 11.1.0
+ debug: 4.3.4(supports-color@8.1.1)
+ execa: 8.0.1
+ lilconfig: 3.0.0
+ listr2: 8.0.1
+ micromatch: 4.0.5
+ pidtree: 0.6.0
+ string-argv: 0.3.2
+ yaml: 2.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /listr2@8.0.1:
+ resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==}
+ engines: {node: '>=18.0.0'}
+ dependencies:
+ cli-truncate: 4.0.0
+ colorette: 2.0.20
+ eventemitter3: 5.0.1
+ log-update: 6.0.0
+ rfdc: 1.3.1
+ wrap-ansi: 9.0.0
+ dev: true
+
+ /load-json-file@6.2.0:
+ resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ graceful-fs: 4.2.11
+ parse-json: 5.2.0
+ strip-bom: 4.0.0
+ type-fest: 0.6.0
+ dev: true
+
+ /load-tsconfig@0.2.5:
+ resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /local-pkg@0.5.0:
+ resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
+ engines: {node: '>=14'}
+ dependencies:
+ mlly: 1.6.1
+ pkg-types: 1.0.3
+ dev: true
+
+ /locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash.curry@4.1.1:
+ resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==}
+ dev: true
+
+ /lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash.sortby@4.7.0:
+ resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
+ dev: true
+
+ /lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ dev: true
+
+ /log-symbols@4.1.0:
+ resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+ engines: {node: '>=10'}
+ dependencies:
+ chalk: 4.1.2
+ is-unicode-supported: 0.1.0
+ dev: true
+
+ /log-update@6.0.0:
+ resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
+ engines: {node: '>=18'}
+ dependencies:
+ ansi-escapes: 6.2.0
+ cli-cursor: 4.0.0
+ slice-ansi: 7.1.0
+ strip-ansi: 7.1.0
+ wrap-ansi: 9.0.0
+ dev: true
+
+ /loupe@2.3.7:
+ resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ dependencies:
+ get-func-name: 2.0.2
+ dev: true
+
+ /lru-cache@10.2.0:
+ resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
+ engines: {node: 14 || >=16.14}
+
+ /lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ yallist: 4.0.0
+ dev: true
+
+ /magic-string@0.16.0:
+ resolution: {integrity: sha512-c4BEos3y6G2qO0B9X7K0FVLOPT9uGrjYwYRLFmDqyl5YMboUviyecnXWp94fJTSMwPw2/sf+CEYt5AGpmklkkQ==}
+ dependencies:
+ vlq: 0.2.3
+ dev: true
+
+ /magic-string@0.30.8:
+ resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.4.15
+ dev: true
+
+ /magicast@0.3.3:
+ resolution: {integrity: sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==}
+ dependencies:
+ '@babel/parser': 7.24.1
+ '@babel/types': 7.24.0
+ source-map-js: 1.2.0
+ dev: true
+
+ /make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+ dependencies:
+ semver: 7.6.0
+ dev: true
+
+ /map-age-cleaner@0.1.3:
+ resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==}
+ engines: {node: '>=6'}
+ dependencies:
+ p-defer: 1.0.0
+ dev: true
+
+ /map-obj@2.0.0:
+ resolution: {integrity: sha512-TzQSV2DiMYgoF5RycneKVUzIa9bQsj/B3tTgsE3dOGqlzHnGIDaC7XBE7grnA+8kZPnfqSGFe95VHc2oc0VFUQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /markdown-it@14.0.0:
+ resolution: {integrity: sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+ dev: true
+
+ /markdown-it@14.1.0:
+ resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+ dev: true
+
+ /markdown-it@8.4.2:
+ resolution: {integrity: sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==}
+ hasBin: true
+ dependencies:
+ argparse: 1.0.10
+ entities: 1.1.2
+ linkify-it: 2.2.0
+ mdurl: 1.0.1
+ uc.micro: 1.0.6
+ dev: true
+
+ /markdownlint-cli@0.39.0:
+ resolution: {integrity: sha512-ZuFN7Xpsbn1Nbp0YYkeLOfXOMOfLQBik2lKRy8pVI/llmKQ2uW7x+8k5OMgF6o7XCsTDSYC/OOmeJ+3qplvnJQ==}
+ engines: {node: '>=18'}
+ hasBin: true
+ dependencies:
+ commander: 11.1.0
+ get-stdin: 9.0.0
+ glob: 10.3.10
+ ignore: 5.3.1
+ js-yaml: 4.1.0
+ jsonc-parser: 3.2.1
+ markdownlint: 0.33.0
+ minimatch: 9.0.3
+ run-con: 1.3.2
+ dev: true
+
+ /markdownlint-micromark@0.1.8:
+ resolution: {integrity: sha512-1ouYkMRo9/6gou9gObuMDnvZM8jC/ly3QCFQyoSPCS2XV1ZClU0xpKbL1Ar3bWWRT1RnBZkWUEiNKrI2CwiBQA==}
+ engines: {node: '>=16'}
+ dev: true
+
+ /markdownlint-micromark@0.1.9:
+ resolution: {integrity: sha512-5hVs/DzAFa8XqYosbEAEg6ok6MF2smDj89ztn9pKkCtdKHVdPQuGMH7frFfYL9mLkvfFe4pTyAMffLbjf3/EyA==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /markdownlint@0.11.0:
+ resolution: {integrity: sha512-wE5WdKD6zW2DQaPQ5TFBTXh5j76DnWd/IFffnDQgHmi6Y61DJXBDfLftZ/suJHuv6cwPjM6gKw2GaRLJMOR+Mg==}
+ engines: {node: '>=6'}
+ dependencies:
+ markdown-it: 8.4.2
+ dev: true
+
+ /markdownlint@0.33.0:
+ resolution: {integrity: sha512-4lbtT14A3m0LPX1WS/3d1m7Blg+ZwiLq36WvjQqFGsX3Gik99NV+VXp/PW3n+Q62xyPdbvGOCfjPqjW+/SKMig==}
+ engines: {node: '>=18'}
+ dependencies:
+ markdown-it: 14.0.0
+ markdownlint-micromark: 0.1.8
+ dev: true
+
+ /markdownlint@0.34.0:
+ resolution: {integrity: sha512-qwGyuyKwjkEMOJ10XN6OTKNOVYvOIi35RNvDLNxTof5s8UmyGHlCdpngRHoRGNvQVGuxO3BJ7uNSgdeX166WXw==}
+ engines: {node: '>=18'}
+ dependencies:
+ markdown-it: 14.1.0
+ markdownlint-micromark: 0.1.9
+ dev: true
+
+ /mdast-util-from-markdown@0.8.5:
+ resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==}
+ dependencies:
+ '@types/mdast': 3.0.15
+ mdast-util-to-string: 2.0.0
+ micromark: 2.11.4
+ parse-entities: 2.0.0
+ unist-util-stringify-position: 2.0.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /mdast-util-to-string@2.0.0:
+ resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==}
+ dev: true
+
+ /mdurl@1.0.1:
+ resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==}
+ dev: true
+
+ /mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+ dev: true
+
+ /mem@6.1.1:
+ resolution: {integrity: sha512-Ci6bIfq/UgcxPTYa8dQQ5FY3BzKkT894bwXWXxC/zqs0XgMO2cT20CGkOqda7gZNkmK5VP4x89IGZ6K7hfbn3Q==}
+ engines: {node: '>=8'}
+ dependencies:
+ map-age-cleaner: 0.1.3
+ mimic-fn: 3.1.0
+ dev: true
+
+ /mem@8.1.1:
+ resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==}
+ engines: {node: '>=10'}
+ dependencies:
+ map-age-cleaner: 0.1.3
+ mimic-fn: 3.1.0
+ dev: true
+
+ /merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ dev: true
+
+ /merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /micromark@2.11.4:
+ resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==}
+ dependencies:
+ debug: 4.3.4(supports-color@8.1.1)
+ parse-entities: 2.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /micromatch@4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+ dev: true
+
+ /mimic-fn@2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /mimic-fn@3.1.0:
+ resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ dependencies:
+ brace-expansion: 1.1.11
+ dev: true
+
+ /minimatch@5.0.1:
+ resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==}
+ engines: {node: '>=10'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+
+ /minimist@0.0.10:
+ resolution: {integrity: sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==}
+ dev: true
+
+ /minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ dev: true
+
+ /minipass@7.0.4:
+ resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ /mlly@1.6.1:
+ resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==}
+ dependencies:
+ acorn: 8.11.3
+ pathe: 1.1.2
+ pkg-types: 1.0.3
+ ufo: 1.5.3
+ dev: true
+
+ /mocha@10.3.0:
+ resolution: {integrity: sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==}
+ engines: {node: '>= 14.0.0'}
+ hasBin: true
+ dependencies:
+ ansi-colors: 4.1.1
+ browser-stdout: 1.3.1
+ chokidar: 3.5.3
+ debug: 4.3.4(supports-color@8.1.1)
+ diff: 5.0.0
+ escape-string-regexp: 4.0.0
+ find-up: 5.0.0
+ glob: 8.1.0
+ he: 1.2.0
+ js-yaml: 4.1.0
+ log-symbols: 4.1.0
+ minimatch: 5.0.1
+ ms: 2.1.3
+ serialize-javascript: 6.0.0
+ strip-json-comments: 3.1.1
+ supports-color: 8.1.1
+ workerpool: 6.2.1
+ yargs: 16.2.0
+ yargs-parser: 20.2.4
+ yargs-unparser: 2.0.0
+ dev: true
+
+ /ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ dev: true
+
+ /ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ dev: true
+
+ /mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+ dev: true
+
+ /nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: true
+
+ /natural-compare-lite@1.4.0:
+ resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
+ dev: true
+
+ /natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ dev: true
+
+ /ndjson@2.0.0:
+ resolution: {integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ json-stringify-safe: 5.0.1
+ minimist: 1.2.8
+ readable-stream: 3.6.2
+ split2: 3.2.2
+ through2: 4.0.2
+ dev: true
+
+ /node-fetch@3.0.0-beta.9:
+ resolution: {integrity: sha512-RdbZCEynH2tH46+tj0ua9caUHVWrd/RHnRfvly2EVdqGmI3ndS1Vn/xjm5KuGejDt2RNDQsVRLPNd2QPwcewVg==}
+ engines: {node: ^10.17 || >=12.3}
+ dependencies:
+ data-uri-to-buffer: 3.0.1
+ fetch-blob: 2.1.2
+ transitivePeerDependencies:
+ - domexception
+ dev: true
+
+ /normalize-package-data@6.0.0:
+ resolution: {integrity: sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ hosted-git-info: 7.0.1
+ is-core-module: 2.13.1
+ semver: 7.6.0
+ validate-npm-package-license: 3.0.4
+ dev: true
+
+ /normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /npm-install-checks@6.3.0:
+ resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dependencies:
+ semver: 7.6.0
+ dev: true
+
+ /npm-normalize-package-bin@3.0.1:
+ resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /npm-package-arg@11.0.1:
+ resolution: {integrity: sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ hosted-git-info: 7.0.1
+ proc-log: 3.0.0
+ semver: 7.6.0
+ validate-npm-package-name: 5.0.0
+ dev: true
+
+ /npm-pick-manifest@9.0.0:
+ resolution: {integrity: sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ dependencies:
+ npm-install-checks: 6.3.0
+ npm-normalize-package-bin: 3.0.1
+ npm-package-arg: 11.0.1
+ semver: 7.6.0
+ dev: true
+
+ /npm-run-path@4.0.1:
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-key: 3.1.1
+ dev: true
+
+ /npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ path-key: 4.0.0
+ dev: true
+
+ /object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /object-pairs@0.1.0:
+ resolution: {integrity: sha512-3ECr6K831I4xX/Mduxr9UC+HPOz/d6WKKYj9p4cmC8Lg8p7g8gitzsxNX5IWlSIgFWN/a4JgrJaoAMKn20oKwA==}
+ dev: true
+
+ /object-values@1.0.0:
+ resolution: {integrity: sha512-+8hwcz/JnQ9EpLIXzN0Rs7DLsBpJNT/xYehtB/jU93tHYr5BFEO8E+JGQNOSqE7opVzz5cGksKFHt7uUJVLSjQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ dependencies:
+ wrappy: 1.0.2
+ dev: true
+
+ /onetime@5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+ dependencies:
+ mimic-fn: 2.1.0
+ dev: true
+
+ /onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ mimic-fn: 4.0.0
+ dev: true
+
+ /optimist@0.6.1:
+ resolution: {integrity: sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==}
+ dependencies:
+ minimist: 0.0.10
+ wordwrap: 0.0.3
+ dev: true
+
+ /optionator@0.9.3:
+ resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ '@aashutoshrathi/word-wrap': 1.2.6
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /p-defer@1.0.0:
+ resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ yocto-queue: 0.1.0
+ dev: true
+
+ /p-limit@5.0.0:
+ resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ yocto-queue: 1.0.0
+ dev: true
+
+ /p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /p-map@4.0.0:
+ resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ aggregate-error: 3.1.0
+ dev: true
+
+ /p-memoize@4.0.1:
+ resolution: {integrity: sha512-km0sP12uE0dOZ5qP+s7kGVf07QngxyG0gS8sYFvFWhqlgzOsSy+m71aUejf/0akxj5W7gE//2G74qTv6b4iMog==}
+ engines: {node: '>=10'}
+ dependencies:
+ mem: 6.1.1
+ mimic-fn: 3.1.0
+ dev: true
+
+ /package-json-validator@0.6.3:
+ resolution: {integrity: sha512-juKiFboV4UKUvWQ+OSxstnyukhuluyuEoFmgZw1Rx21XzmwlgDWLcbl3qzjA3789IRORYhVFs7cmAO0YFGwHCg==}
+ hasBin: true
+ dependencies:
+ optimist: 0.6.1
+ dev: true
+
+ /parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parent-module@2.0.0:
+ resolution: {integrity: sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==}
+ engines: {node: '>=8'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parse-entities@2.0.0:
+ resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
+ dependencies:
+ character-entities: 1.2.4
+ character-entities-legacy: 1.1.4
+ character-reference-invalid: 1.1.4
+ is-alphanumerical: 1.0.4
+ is-decimal: 1.0.4
+ is-hexadecimal: 1.0.4
+ dev: true
+
+ /parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/code-frame': 7.24.2
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+ dev: true
+
+ /parse-ms@4.0.0:
+ resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /parse-npm-tarball-url@3.0.0:
+ resolution: {integrity: sha512-InpdgIdNe5xWMEUcrVQUniQKwnggBtJ7+SCwh7zQAZwbbIYZV9XdgJyhtmDSSvykFyQXoe4BINnzKTfCwWLs5g==}
+ engines: {node: '>=8.15'}
+ dependencies:
+ semver: 6.3.1
+ dev: true
+
+ /path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ /path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ dev: true
+
+ /path-scurry@1.10.1:
+ resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ lru-cache: 10.2.0
+ minipass: 7.0.4
+
+ /path-temp@2.1.0:
+ resolution: {integrity: sha512-cMMJTAZlion/RWRRC48UbrDymEIt+/YSD/l8NqjneyDw2rDOBQcP5yRkMB4CYGn47KMhZvbblBP7Z79OsMw72w==}
+ engines: {node: '>=8.15'}
+ dependencies:
+ unique-string: 2.0.0
+ dev: true
+
+ /path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /pathe@1.1.2:
+ resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+ dev: true
+
+ /pathval@1.1.1:
+ resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ dev: true
+
+ /picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ dev: true
+
+ /picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+ dev: true
+
+ /picomatch@4.0.1:
+ resolution: {integrity: sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /pidtree@0.6.0:
+ resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+ dev: true
+
+ /pirates@4.0.6:
+ resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /pkg-types@1.0.3:
+ resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
+ dependencies:
+ jsonc-parser: 3.2.1
+ mlly: 1.6.1
+ pathe: 1.1.2
+ dev: true
+
+ /postcss-load-config@4.0.2:
+ resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 3.1.1
+ yaml: 2.4.1
+ dev: true
+
+ /postcss@8.4.38:
+ resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.0
+ source-map-js: 1.2.0
+ dev: true
+
+ /prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prettier-plugin-curly@0.2.1(prettier@3.2.5):
+ resolution: {integrity: sha512-BadJTlVy/nX+4sgCc5htrgej4yLVRWIMa1PwN96BqlRru4tGkj1fo2OqZE446fJWlddx9xxTMJByDKIZYc7F3Q==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ prettier: ^2 || ^3
+ dependencies:
+ '@babel/generator': 7.24.1
+ '@babel/parser': 7.24.1
+ '@babel/traverse': 7.24.1
+ prettier: 3.2.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /prettier-plugin-packagejson@2.4.12(prettier@3.2.5):
+ resolution: {integrity: sha512-hifuuOgw5rHHTdouw9VrhT8+Nd7UwxtL1qco8dUfd4XUFQL6ia3xyjSxhPQTsGnSYFraTWy5Omb+MZm/OWDTpQ==}
+ peerDependencies:
+ prettier: '>= 1.16.0'
+ peerDependenciesMeta:
+ prettier:
+ optional: true
+ dependencies:
+ prettier: 3.2.5
+ sort-package-json: 2.8.0
+ synckit: 0.9.0
+ dev: true
+
+ /prettier@3.2.5:
+ resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
+ engines: {node: '>=14'}
+ hasBin: true
+ dev: true
+
+ /pretty-format@29.7.0:
+ resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dependencies:
+ '@jest/schemas': 29.6.3
+ ansi-styles: 5.2.0
+ react-is: 18.2.0
+ dev: true
+
+ /pretty-ms@9.0.0:
+ resolution: {integrity: sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==}
+ engines: {node: '>=18'}
+ dependencies:
+ parse-ms: 4.0.0
+ dev: true
+
+ /proc-log@3.0.0:
+ resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /promise-inflight@1.0.1:
+ resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
+ peerDependencies:
+ bluebird: '*'
+ peerDependenciesMeta:
+ bluebird:
+ optional: true
+ dev: true
+
+ /promise-retry@2.0.1:
+ resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
+ engines: {node: '>=10'}
+ dependencies:
+ err-code: 2.0.3
+ retry: 0.12.0
+ dev: true
+
+ /punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ dev: true
+
+ /randombytes@2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /react-is@18.2.0:
+ resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
+ dev: true
+
+ /read-package-json-fast@3.0.2:
+ resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dependencies:
+ json-parse-even-better-errors: 3.0.1
+ npm-normalize-package-bin: 3.0.1
+ dev: true
+
+ /readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+ dev: true
+
+ /refa@0.12.1:
+ resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dependencies:
+ '@eslint-community/regexpp': 4.10.0
+ dev: true
+
+ /regexp-ast-analysis@0.7.1:
+ resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dependencies:
+ '@eslint-community/regexpp': 4.10.0
+ refa: 0.12.1
+ dev: true
+
+ /rename-overwrite@5.0.0:
+ resolution: {integrity: sha512-vSxE5Ww7Jnyotvaxi3Dj0vOMoojH8KMkBfs9xYeW/qNfJiLTcC1fmwTjrbGUq3mQSOCxkG0DbdcvwTUrpvBN4w==}
+ engines: {node: '>=12.10'}
+ dependencies:
+ '@zkochan/rimraf': 2.1.3
+ fs-extra: 10.1.0
+ dev: true
+
+ /repeat-string@1.6.1:
+ resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
+ engines: {node: '>=0.10'}
+ dev: true
+
+ /require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /resolve-from@5.0.0:
+ resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ dev: true
+
+ /resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.13.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
+ /restore-cursor@4.0.0:
+ resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ dev: true
+
+ /retry@0.12.0:
+ resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ dev: true
+
+ /reverse-arguments@1.0.0:
+ resolution: {integrity: sha512-/x8uIPdTafBqakK0TmPNJzgkLP+3H+yxpUJhCQHsLBg1rYEVNR2D8BRYNWQhVBjyOd7oo1dZRVzIkwMY2oqfYQ==}
+ dev: true
+
+ /rfdc@1.3.1:
+ resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
+ dev: true
+
+ /rimraf@3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.3
+ dev: true
+
+ /rollup@4.13.0:
+ resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ '@types/estree': 1.0.5
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.13.0
+ '@rollup/rollup-android-arm64': 4.13.0
+ '@rollup/rollup-darwin-arm64': 4.13.0
+ '@rollup/rollup-darwin-x64': 4.13.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.13.0
+ '@rollup/rollup-linux-arm64-gnu': 4.13.0
+ '@rollup/rollup-linux-arm64-musl': 4.13.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.13.0
+ '@rollup/rollup-linux-x64-gnu': 4.13.0
+ '@rollup/rollup-linux-x64-musl': 4.13.0
+ '@rollup/rollup-win32-arm64-msvc': 4.13.0
+ '@rollup/rollup-win32-ia32-msvc': 4.13.0
+ '@rollup/rollup-win32-x64-msvc': 4.13.0
+ fsevents: 2.3.3
+ dev: true
+
+ /run-con@1.3.2:
+ resolution: {integrity: sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==}
+ hasBin: true
+ dependencies:
+ deep-extend: 0.6.0
+ ini: 4.1.2
+ minimist: 1.2.8
+ strip-json-comments: 3.1.1
+ dev: true
+
+ /run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+ dev: true
+
+ /safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ dev: true
+
+ /scslre@0.3.0:
+ resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
+ engines: {node: ^14.0.0 || >=16.0.0}
+ dependencies:
+ '@eslint-community/regexpp': 4.10.0
+ refa: 0.12.1
+ regexp-ast-analysis: 0.7.1
+ dev: true
+
+ /semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+ dev: true
+
+ /semver@7.6.0:
+ resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: true
+
+ /sentences-per-line@0.2.1:
+ resolution: {integrity: sha512-6hlyKBwqoaZJ5+RBTKNNem2kBGAboh9e9KfFw5KYKA+64xaTYWbv5C6XnOudx8xk1Sg6f/4yalhJtCZFSLWIsQ==}
+ dependencies:
+ markdownlint: 0.11.0
+ dev: true
+
+ /serialize-javascript@6.0.0:
+ resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==}
+ dependencies:
+ randombytes: 2.1.0
+ dev: true
+
+ /shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+
+ /shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ /shell-quote-word@1.0.1:
+ resolution: {integrity: sha512-lT297f1WLAdq0A4O+AknIFRP6kkiI3s8C913eJ0XqBxJbZPGWUNkRQk2u8zk4bEAjUJ5i+fSLwB6z1HzeT+DEg==}
+ dev: true
+
+ /siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+ dev: true
+
+ /signal-exit@3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ dev: true
+
+ /signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ /slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /slash@4.0.0:
+ resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /slice-ansi@5.0.0:
+ resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.2.1
+ is-fullwidth-code-point: 4.0.0
+ dev: true
+
+ /slice-ansi@7.1.0:
+ resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
+ engines: {node: '>=18'}
+ dependencies:
+ ansi-styles: 6.2.1
+ is-fullwidth-code-point: 5.0.0
+ dev: true
+
+ /smol-toml@1.1.4:
+ resolution: {integrity: sha512-Y0OT8HezWsTNeEOSVxDnKOW/AyNXHQ4BwJNbAXlLTF5wWsBvrcHhIkE5Rf8kQMLmgf7nDX3PVOlgC6/Aiggu3Q==}
+ engines: {node: '>= 18', pnpm: '>= 8'}
+ dev: true
+
+ /sort-object-keys@1.1.3:
+ resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==}
+ dev: true
+
+ /sort-package-json@1.57.0:
+ resolution: {integrity: sha512-FYsjYn2dHTRb41wqnv+uEqCUvBpK3jZcTp9rbz2qDTmel7Pmdtf+i2rLaaPMRZeSVM60V3Se31GyWFpmKs4Q5Q==}
+ hasBin: true
+ dependencies:
+ detect-indent: 6.1.0
+ detect-newline: 3.1.0
+ git-hooks-list: 1.0.3
+ globby: 10.0.0
+ is-plain-obj: 2.1.0
+ sort-object-keys: 1.1.3
+ dev: true
+
+ /sort-package-json@2.8.0:
+ resolution: {integrity: sha512-PxeNg93bTJWmDGnu0HADDucoxfFiKkIr73Kv85EBThlI1YQPdc0XovBgg2llD0iABZbu2SlKo8ntGmOP9wOj/g==}
+ hasBin: true
+ dependencies:
+ detect-indent: 7.0.1
+ detect-newline: 4.0.1
+ get-stdin: 9.0.0
+ git-hooks-list: 3.1.0
+ globby: 13.2.2
+ is-plain-obj: 4.1.0
+ sort-object-keys: 1.1.3
+ dev: true
+
+ /source-map-js@1.2.0:
+ resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /source-map@0.8.0-beta.0:
+ resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
+ engines: {node: '>= 8'}
+ dependencies:
+ whatwg-url: 7.1.0
+ dev: true
+
+ /spdx-correct@3.2.0:
+ resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
+ dependencies:
+ spdx-expression-parse: 3.0.1
+ spdx-license-ids: 3.0.17
+ dev: true
+
+ /spdx-exceptions@2.5.0:
+ resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==}
+ dev: true
+
+ /spdx-expression-parse@3.0.1:
+ resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+ dependencies:
+ spdx-exceptions: 2.5.0
+ spdx-license-ids: 3.0.17
+ dev: true
+
+ /spdx-expression-parse@4.0.0:
+ resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==}
+ dependencies:
+ spdx-exceptions: 2.5.0
+ spdx-license-ids: 3.0.17
+ dev: true
+
+ /spdx-license-ids@3.0.17:
+ resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==}
+ dev: true
+
+ /split2@3.2.2:
+ resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==}
+ dependencies:
+ readable-stream: 3.6.2
+ dev: true
+
+ /sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ dev: true
+
+ /ssri@10.0.5:
+ resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dependencies:
+ minipass: 7.0.4
+ dev: true
+
+ /stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ dev: true
+
+ /std-env@3.7.0:
+ resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
+ dev: true
+
+ /string-argv@0.3.2:
+ resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
+ engines: {node: '>=0.6.19'}
+ dev: true
+
+ /string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ /string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+
+ /string-width@7.1.0:
+ resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==}
+ engines: {node: '>=18'}
+ dependencies:
+ emoji-regex: 10.3.0
+ get-east-asian-width: 1.2.0
+ strip-ansi: 7.1.0
+ dev: true
+
+ /string.fromcodepoint@0.2.1:
+ resolution: {integrity: sha512-n69H31OnxSGSZyZbgBlvYIXlrMhJQ0dQAX1js1QDhpaUH6zmU3QYlj07bCwCNlPOu3oRXIubGPl2gDGnHsiCqg==}
+ dev: true
+
+ /string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+
+ /strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-regex: 6.0.1
+
+ /strip-bom@4.0.0:
+ resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strip-final-newline@2.0.0:
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strip-json-comments@5.0.1:
+ resolution: {integrity: sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==}
+ engines: {node: '>=14.16'}
+ dev: true
+
+ /strip-literal@2.0.0:
+ resolution: {integrity: sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==}
+ dependencies:
+ js-tokens: 8.0.3
+ dev: true
+
+ /sucrase@3.35.0:
+ resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ commander: 4.1.1
+ glob: 10.3.10
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.6
+ ts-interface-checker: 0.1.13
+ dev: true
+
+ /summary@2.1.0:
+ resolution: {integrity: sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==}
+ dev: true
+
+ /supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+ dev: true
+
+ /supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /supports-color@8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /synckit@0.6.2:
+ resolution: {integrity: sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA==}
+ engines: {node: '>=12.20'}
+ dependencies:
+ tslib: 2.6.2
+ dev: true
+
+ /synckit@0.9.0:
+ resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ dependencies:
+ '@pkgr/core': 0.1.1
+ tslib: 2.6.2
+ dev: true
+
+ /test-exclude@6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.3
+ minimatch: 3.1.2
+ dev: true
+
+ /text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ dev: true
+
+ /thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
+ dev: true
+
+ /thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+ dev: true
+
+ /through2@4.0.2:
+ resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
+ dependencies:
+ readable-stream: 3.6.2
+ dev: true
+
+ /tinybench@2.6.0:
+ resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==}
+ dev: true
+
+ /tinypool@0.8.2:
+ resolution: {integrity: sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==}
+ engines: {node: '>=14.0.0'}
+ dev: true
+
+ /tinyspy@2.2.1:
+ resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
+ engines: {node: '>=14.0.0'}
+ dev: true
+
+ /to-fast-properties@2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /to-no-case@1.0.2:
+ resolution: {integrity: sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==}
+ dev: true
+
+ /to-pascal-case@1.0.0:
+ resolution: {integrity: sha512-QGMWHqM6xPrcQW57S23c5/3BbYb0Tbe9p+ur98ckRnGDwD4wbbtDiYI38CfmMKNB5Iv0REjs5SNDntTwvDxzZA==}
+ dependencies:
+ to-space-case: 1.0.0
+ dev: true
+
+ /to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+ dev: true
+
+ /to-space-case@1.0.0:
+ resolution: {integrity: sha512-rLdvwXZ39VOn1IxGL3V6ZstoTbwLRckQmn/U8ZDLuWwIXNpuZDhQ3AiRUlhTbOXFVE9C+dR51wM0CBDhk31VcA==}
+ dependencies:
+ to-no-case: 1.0.2
+ dev: true
+
+ /tr46@1.0.1:
+ resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
+ /tree-kill@1.2.2:
+ resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
+ hasBin: true
+ dev: true
+
+ /ts-api-utils@1.3.0(typescript@5.4.3):
+ resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ typescript: '>=4.2.0'
+ dependencies:
+ typescript: 5.4.3
+
+ /ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+ dev: true
+
+ /tslib@1.14.1:
+ resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+ dev: true
+
+ /tslib@2.6.2:
+ resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+ dev: true
+
+ /tsup@8.0.2(typescript@5.4.3):
+ resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==}
+ engines: {node: '>=18'}
+ hasBin: true
+ peerDependencies:
+ '@microsoft/api-extractor': ^7.36.0
+ '@swc/core': ^1
+ postcss: ^8.4.12
+ typescript: '>=4.5.0'
+ peerDependenciesMeta:
+ '@microsoft/api-extractor':
+ optional: true
+ '@swc/core':
+ optional: true
+ postcss:
+ optional: true
+ typescript:
+ optional: true
+ dependencies:
+ bundle-require: 4.0.2(esbuild@0.19.12)
+ cac: 6.7.14
+ chokidar: 3.6.0
+ debug: 4.3.4(supports-color@8.1.1)
+ esbuild: 0.19.12
+ execa: 5.1.1
+ globby: 11.1.0
+ joycon: 3.1.1
+ postcss-load-config: 4.0.2
+ resolve-from: 5.0.0
+ rollup: 4.13.0
+ source-map: 0.8.0-beta.0
+ sucrase: 3.35.0
+ tree-kill: 1.2.2
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ - ts-node
+ dev: true
+
+ /tsutils@3.21.0(typescript@5.4.3):
+ resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+ engines: {node: '>= 6'}
+ peerDependencies:
+ typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+ dependencies:
+ tslib: 1.14.1
+ typescript: 5.4.3
+ dev: true
+
+ /type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ dev: true
+
+ /type-detect@4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /type-fest@0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-fest@0.6.0:
+ resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /type-fest@1.4.0:
+ resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-fest@3.13.1:
+ resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
+ engines: {node: '>=14.16'}
+ dev: true
+
+ /typedarray-to-buffer@3.1.5:
+ resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
+ dependencies:
+ is-typedarray: 1.0.0
+ dev: true
+
+ /typescript@5.4.3:
+ resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ /uc.micro@1.0.6:
+ resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
+ dev: true
+
+ /uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+ dev: true
+
+ /ufo@1.5.3:
+ resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
+ dev: true
+
+ /undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+ dev: true
+
+ /unescape-js@1.1.4:
+ resolution: {integrity: sha512-42SD8NOQEhdYntEiUQdYq/1V/YHwr1HLwlHuTJB5InVVdOSbgI6xu8jK5q65yIzuFCfczzyDF/7hbGzVbyCw0g==}
+ dependencies:
+ string.fromcodepoint: 0.2.1
+ dev: true
+
+ /unique-string@2.0.0:
+ resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
+ engines: {node: '>=8'}
+ dependencies:
+ crypto-random-string: 2.0.0
+ dev: true
+
+ /unique-string@3.0.0:
+ resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ crypto-random-string: 4.0.0
+ dev: true
+
+ /unist-util-stringify-position@2.0.3:
+ resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==}
+ dependencies:
+ '@types/unist': 2.0.10
+ dev: true
+
+ /universalify@2.0.1:
+ resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
+ engines: {node: '>= 10.0.0'}
+ dev: true
+
+ /uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
+ /util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ dev: true
+
+ /v8-to-istanbul@9.2.0:
+ resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
+ engines: {node: '>=10.12.0'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ '@types/istanbul-lib-coverage': 2.0.6
+ convert-source-map: 2.0.0
+ dev: true
+
+ /validate-npm-package-license@3.0.4:
+ resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
+ dependencies:
+ spdx-correct: 3.2.0
+ spdx-expression-parse: 3.0.1
+ dev: true
+
+ /validate-npm-package-name@4.0.0:
+ resolution: {integrity: sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==}
+ engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ dependencies:
+ builtins: 5.0.1
+ dev: true
+
+ /validate-npm-package-name@5.0.0:
+ resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dependencies:
+ builtins: 5.0.1
+ dev: true
+
+ /version-selector-type@3.0.0:
+ resolution: {integrity: sha512-PSvMIZS7C1MuVNBXl/CDG2pZq8EXy/NW2dHIdm3bVP5N0PC8utDK8ttXLXj44Gn3J0lQE3U7Mpm1estAOd+eiA==}
+ engines: {node: '>=10.13'}
+ dependencies:
+ semver: 7.6.0
+ dev: true
+
+ /vite-node@1.4.0(@types/node@20.11.30):
+ resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ dependencies:
+ cac: 6.7.14
+ debug: 4.3.4(supports-color@8.1.1)
+ pathe: 1.1.2
+ picocolors: 1.0.0
+ vite: 5.2.4(@types/node@20.11.30)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
+ /vite@5.2.4(@types/node@20.11.30):
+ resolution: {integrity: sha512-vjFghvHWidBTinu5TCymJk/lRHlR5ljqB83yugr0HA1xspUPdOZHqbqDLnZ8f9/jINrtFHTCYYyIUi+o+Q5iyg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ '@types/node': 20.11.30
+ esbuild: 0.20.2
+ postcss: 8.4.38
+ rollup: 4.13.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
+ /vitest@1.4.0(@types/node@20.11.30):
+ resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 1.4.0
+ '@vitest/ui': 1.4.0
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ dependencies:
+ '@types/node': 20.11.30
+ '@vitest/expect': 1.4.0
+ '@vitest/runner': 1.4.0
+ '@vitest/snapshot': 1.4.0
+ '@vitest/spy': 1.4.0
+ '@vitest/utils': 1.4.0
+ acorn-walk: 8.3.2
+ chai: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
+ execa: 8.0.1
+ local-pkg: 0.5.0
+ magic-string: 0.30.8
+ pathe: 1.1.2
+ picocolors: 1.0.0
+ std-env: 3.7.0
+ strip-literal: 2.0.0
+ tinybench: 2.6.0
+ tinypool: 0.8.2
+ vite: 5.2.4(@types/node@20.11.30)
+ vite-node: 1.4.0(@types/node@20.11.30)
+ why-is-node-running: 2.2.2
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
+ /vlq@0.2.3:
+ resolution: {integrity: sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==}
+ dev: true
+
+ /vscode-languageserver-textdocument@1.0.11:
+ resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==}
+ dev: true
+
+ /vscode-uri@3.0.8:
+ resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
+ dev: true
+
+ /wcwidth@1.0.1:
+ resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+ requiresBuild: true
+ dependencies:
+ defaults: 1.0.4
+ dev: true
+ optional: true
+
+ /webidl-conversions@4.0.2:
+ resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
+ dev: true
+
+ /whatwg-url@7.1.0:
+ resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
+ dependencies:
+ lodash.sortby: 4.7.0
+ tr46: 1.0.1
+ webidl-conversions: 4.0.2
+ dev: true
+
+ /which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+
+ /which@4.0.0:
+ resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
+ engines: {node: ^16.13.0 || >=18.0.0}
+ hasBin: true
+ dependencies:
+ isexe: 3.1.1
+ dev: true
+
+ /why-is-node-running@2.2.2:
+ resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+ dev: true
+
+ /wordwrap@0.0.3:
+ resolution: {integrity: sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /workerpool@6.2.1:
+ resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==}
+ dev: true
+
+ /wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ /wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+
+ /wrap-ansi@9.0.0:
+ resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
+ engines: {node: '>=18'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 7.1.0
+ strip-ansi: 7.1.0
+ dev: true
+
+ /wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ dev: true
+
+ /write-file-atomic@3.0.3:
+ resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
+ dependencies:
+ imurmurhash: 0.1.4
+ is-typedarray: 1.0.0
+ signal-exit: 3.0.7
+ typedarray-to-buffer: 3.1.5
+ dev: true
+
+ /xdg-basedir@5.1.0:
+ resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ dev: true
+
+ /yaml-eslint-parser@1.2.2:
+ resolution: {integrity: sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ dependencies:
+ eslint-visitor-keys: 3.4.3
+ lodash: 4.17.21
+ yaml: 2.4.1
+ dev: true
+
+ /yaml@2.3.4:
+ resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
+ engines: {node: '>= 14'}
+ dev: true
+
+ /yaml@2.4.1:
+ resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==}
+ engines: {node: '>= 14'}
+ hasBin: true
+ dev: true
+
+ /yargs-parser@20.2.4:
+ resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yargs-unparser@2.0.0:
+ resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==}
+ engines: {node: '>=10'}
+ dependencies:
+ camelcase: 6.3.0
+ decamelize: 4.0.0
+ flat: 5.0.2
+ is-plain-obj: 2.1.0
+ dev: true
+
+ /yargs@16.2.0:
+ resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
+ engines: {node: '>=10'}
+ dependencies:
+ cliui: 7.0.4
+ escalade: 3.1.2
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 20.2.4
+ dev: true
+
+ /yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yocto-queue@1.0.0:
+ resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
+ engines: {node: '>=12.20'}
+ dev: true
+
+ /zod-validation-error@3.0.3(zod@3.22.4):
+ resolution: {integrity: sha512-cETTrcMq3Ze58vhdR0zD37uJm/694I6mAxcf/ei5bl89cC++fBNxrC2z8lkFze/8hVMPwrbtrwXHR2LB50fpHw==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ zod: ^3.18.0
+ dependencies:
+ zod: 3.22.4
+ dev: true
+
+ /zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
+ dev: true
diff --git a/renovate.json b/renovate.json
index d2c6df781..1cb7a9124 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,4 +1,4 @@
{
- "automerge": true,
- "extends": ["config:base"]
+ "automerge": true,
+ "extends": ["config:base"]
}
diff --git a/src/cleanups/builtin/suppressTypeErrors/README.md b/src/cleanups/builtin/suppressTypeErrors/README.md
index 72923b133..d42c24cb6 100644
--- a/src/cleanups/builtin/suppressTypeErrors/README.md
+++ b/src/cleanups/builtin/suppressTypeErrors/README.md
@@ -4,15 +4,15 @@ Whether to add a `// @ts-expect-error` comment directive before each remaining t
## Use Cases
-* Your existing code has type errors that are too complex or context-dependent for TypeStat to clean up.
+- Your existing code has type errors that are too complex or context-dependent for TypeStat to clean up.
## Configuration
```json
{
- "cleanups": {
- "suppressTypeErrors": true
- }
+ "cleanups": {
+ "suppressTypeErrors": true
+ }
}
```
diff --git a/src/cleanups/builtin/suppressTypeErrors/index.ts b/src/cleanups/builtin/suppressTypeErrors/index.ts
index 2580215a3..928c11c78 100644
--- a/src/cleanups/builtin/suppressTypeErrors/index.ts
+++ b/src/cleanups/builtin/suppressTypeErrors/index.ts
@@ -1,44 +1,46 @@
-import * as ts from "typescript";
+import ts from "typescript";
import {
- DiagnosticWithStart,
- getLineForDiagnostic,
- isDiagnosticWithStart,
- stringifyDiagnosticMessageText,
-} from "../../../shared/diagnostics";
-import { FileMutator } from "../../../shared/fileMutator";
+ DiagnosticWithStart,
+ getLineForDiagnostic,
+ isDiagnosticWithStart,
+ stringifyDiagnosticMessageText,
+} from "../../../shared/diagnostics.js";
+import { FileMutator } from "../../../shared/fileMutator.js";
export const suppressRemainingTypeIssues: FileMutator = (request) => {
- if (!request.options.cleanups.suppressTypeErrors) {
- return undefined;
- }
+ if (!request.options.cleanups.suppressTypeErrors) {
+ return undefined;
+ }
- const allDiagnostics = request.services.program.getSemanticDiagnostics(request.sourceFile).filter(isDiagnosticWithStart);
- if (!allDiagnostics.length) {
- return undefined;
- }
+ const allDiagnostics = request.services.program
+ .getSemanticDiagnostics(request.sourceFile)
+ .filter(isDiagnosticWithStart);
+ if (!allDiagnostics.length) {
+ return undefined;
+ }
- const diagnosticsPerLine = new Map();
+ const diagnosticsPerLine = new Map();
- for (const diagnostic of allDiagnostics) {
- const line = getLineForDiagnostic(diagnostic, request.sourceFile);
- const existing = diagnosticsPerLine.get(line);
+ for (const diagnostic of allDiagnostics) {
+ const line = getLineForDiagnostic(diagnostic, request.sourceFile);
+ const existing = diagnosticsPerLine.get(line);
- if (existing) {
- existing.push(diagnostic);
- } else {
- diagnosticsPerLine.set(line, [diagnostic]);
- }
- }
+ if (existing) {
+ existing.push(diagnostic);
+ } else {
+ diagnosticsPerLine.set(line, [diagnostic]);
+ }
+ }
- return Array.from(diagnosticsPerLine).map(([line, diagnostics]) => {
- const messages = diagnostics.map(stringifyDiagnosticMessageText).join(" ");
- return {
- insertion: `// @ts-expect-error -- TODO: ${messages}\n`,
- range: {
- begin: ts.getPositionOfLineAndCharacter(request.sourceFile, line, 0),
- },
- type: "text-insert",
- };
- });
+ return Array.from(diagnosticsPerLine).map(([line, diagnostics]) => {
+ const messages = diagnostics.map(stringifyDiagnosticMessageText).join(" ");
+ return {
+ insertion: `// @ts-expect-error -- TODO: ${messages}\n`,
+ range: {
+ begin: ts.getPositionOfLineAndCharacter(request.sourceFile, line, 0),
+ },
+ type: "text-insert",
+ };
+ });
};
diff --git a/src/cli/runCli.test.ts b/src/cli/runCli.test.ts
index 150aa0713..32ed5bc2e 100644
--- a/src/cli/runCli.test.ts
+++ b/src/cli/runCli.test.ts
@@ -1,110 +1,152 @@
-import { ResultStatus } from "..";
-import { version } from "../../package.json";
+import { describe, expect, it, vi } from "vitest";
-import { runCli } from "./runCli";
+import { version } from "../../package.json";
+import { ResultStatus } from "../index.js";
+import { runCli } from "./runCli.js";
const createTestArgs = (...argv: string[]) => ({
- argv: ["node.exe", "typestat", ...argv],
- initializationRunner: jest.fn().mockResolvedValueOnce({
- status: ResultStatus.ConfigurationError,
- }),
- output: {
- log: jest.fn(),
- stderr: jest.fn(),
- stdout: jest.fn(),
- },
- mainRunner: jest.fn(),
+ argv: ["node.exe", "typestat", ...argv],
+ initializationRunner: vi.fn().mockResolvedValueOnce({
+ status: ResultStatus.ConfigurationError,
+ }),
+ mainRunner: vi.fn(),
+ output: {
+ log: vi.fn(),
+ stderr: vi.fn(),
+ stdout: vi.fn(),
+ },
});
describe("runCli", () => {
- it("runs initializationRunner when no args are provided", async () => {
- // Arrange
- const { argv, initializationRunner, output, mainRunner } = createTestArgs();
-
- // Act
- await runCli(argv, { initializationRunner, output, mainRunner });
-
- // Assert
- expect(initializationRunner).toHaveBeenCalledTimes(1);
- expect(mainRunner).not.toHaveBeenCalled();
- });
-
- it("logs the current version when --version is provided", async () => {
- // Arrange
- const { argv, initializationRunner, output, mainRunner } = createTestArgs("--version");
-
- // Act
- const resultStatus = await runCli(argv, { initializationRunner, output, mainRunner });
-
- // Assert
- expect(output.stdout).toHaveBeenLastCalledWith(`${version}`);
- expect(resultStatus).toEqual(ResultStatus.Succeeded);
- });
-
- it("logs a string when the main runner rejects with one", async () => {
- // Arrange
- const { argv, initializationRunner, output, mainRunner } = createTestArgs("--config", "typestat.json");
- const message = "Error message";
-
- mainRunner.mockRejectedValue(message);
-
- // Act
- const resultStatus = await runCli(argv, { initializationRunner, output, mainRunner });
-
- // Assert
- expect(output.stderr).toHaveBeenCalledWith(expect.stringMatching(message));
- expect(resultStatus).toEqual(ResultStatus.Failed);
- });
-
- it("logs an error with a stack when the main runner rejects with one", async () => {
- // Arrange
- const { argv, initializationRunner, output, mainRunner } = createTestArgs("--config", "typestat.json");
- const message = "Error message";
- const error = new Error(message);
-
- mainRunner.mockRejectedValue(error);
-
- // Act
- const resultStatus = await runCli(argv, { initializationRunner, output, mainRunner });
-
- // Assert
- expect(output.stderr).toHaveBeenCalledWith(expect.stringMatching(message));
- expect(output.stderr).toHaveBeenLastCalledWith(expect.stringMatching(" at"));
- expect(resultStatus).toEqual(ResultStatus.Failed);
- });
-
- it("logs help and the error when a configuration error is reported", async () => {
- // Arrange
- const { argv, initializationRunner, output, mainRunner } = createTestArgs("--config", "typestat.json");
- const message = "Error message";
-
- mainRunner.mockResolvedValue({
- error: message,
- status: ResultStatus.ConfigurationError,
- });
-
- // Act
- const resultStatus = await runCli(argv, { initializationRunner, output, mainRunner });
-
- // Assert
- expect(output.stdout).toHaveBeenLastCalledWith(expect.stringMatching("typestat \\[options\\]"));
- expect(output.stderr).toHaveBeenLastCalledWith(expect.stringMatching(message));
- expect(resultStatus).toEqual(ResultStatus.ConfigurationError);
- });
-
- it("logs a happy message when it finishes succesfully", async () => {
- // Arrange
- const { argv, initializationRunner, output, mainRunner } = createTestArgs("--config", "typestat.json");
-
- mainRunner.mockResolvedValue({
- status: ResultStatus.Succeeded,
- });
-
- // Act
- const resultStatus = await runCli(argv, { initializationRunner, output, mainRunner });
-
- // Assert
- expect(output.stdout).toHaveBeenLastCalledWith(expect.stringMatching("All done!"));
- expect(resultStatus).toEqual(ResultStatus.Succeeded);
- });
+ it("runs initializationRunner when no args are provided", async () => {
+ // Arrange
+ const { argv, initializationRunner, mainRunner, output } = createTestArgs();
+
+ // Act
+ await runCli(argv, { initializationRunner, mainRunner, output });
+
+ // Assert
+ expect(initializationRunner).toHaveBeenCalledTimes(1);
+ expect(mainRunner).not.toHaveBeenCalled();
+ });
+
+ it("logs the current version when --version is provided", async () => {
+ // Arrange
+ const { argv, initializationRunner, mainRunner, output } =
+ createTestArgs("--version");
+
+ // Act
+ const resultStatus = await runCli(argv, {
+ initializationRunner,
+ mainRunner,
+ output,
+ });
+
+ // Assert
+ expect(output.stdout).toHaveBeenLastCalledWith(version);
+ expect(resultStatus).toEqual(ResultStatus.Succeeded);
+ });
+
+ it("logs a string when the main runner rejects with one", async () => {
+ // Arrange
+ const { argv, initializationRunner, mainRunner, output } = createTestArgs(
+ "--config",
+ "typestat.json",
+ );
+ const message = "Error message";
+
+ mainRunner.mockRejectedValue(message);
+
+ // Act
+ const resultStatus = await runCli(argv, {
+ initializationRunner,
+ mainRunner,
+ output,
+ });
+
+ // Assert
+ expect(output.stderr).toHaveBeenCalledWith(expect.stringMatching(message));
+ expect(resultStatus).toEqual(ResultStatus.Failed);
+ });
+
+ it("logs an error with a stack when the main runner rejects with one", async () => {
+ // Arrange
+ const { argv, initializationRunner, mainRunner, output } = createTestArgs(
+ "--config",
+ "typestat.json",
+ );
+ const message = "Error message";
+ const error = new Error(message);
+
+ mainRunner.mockRejectedValue(error);
+
+ // Act
+ const resultStatus = await runCli(argv, {
+ initializationRunner,
+ mainRunner,
+ output,
+ });
+
+ // Assert
+ expect(output.stderr).toHaveBeenCalledWith(expect.stringMatching(message));
+ expect(output.stderr).toHaveBeenLastCalledWith(
+ expect.stringMatching(" at"),
+ );
+ expect(resultStatus).toEqual(ResultStatus.Failed);
+ });
+
+ it("logs help and the error when a configuration error is reported", async () => {
+ // Arrange
+ const { argv, initializationRunner, mainRunner, output } = createTestArgs(
+ "--config",
+ "typestat.json",
+ );
+ const message = "Error message";
+
+ mainRunner.mockResolvedValue({
+ error: message,
+ status: ResultStatus.ConfigurationError,
+ });
+
+ // Act
+ const resultStatus = await runCli(argv, {
+ initializationRunner,
+ mainRunner,
+ output,
+ });
+
+ // Assert
+ expect(output.stdout).toHaveBeenLastCalledWith(
+ expect.stringMatching("typestat \\[options\\]"),
+ );
+ expect(output.stderr).toHaveBeenLastCalledWith(
+ expect.stringMatching(message),
+ );
+ expect(resultStatus).toEqual(ResultStatus.ConfigurationError);
+ });
+
+ it("logs a happy message when it finishes successfully", async () => {
+ // Arrange
+ const { argv, initializationRunner, mainRunner, output } = createTestArgs(
+ "--config",
+ "typestat.json",
+ );
+
+ mainRunner.mockResolvedValue({
+ status: ResultStatus.Succeeded,
+ });
+
+ // Act
+ const resultStatus = await runCli(argv, {
+ initializationRunner,
+ mainRunner,
+ output,
+ });
+
+ // Assert
+ expect(output.stdout).toHaveBeenLastCalledWith(
+ expect.stringMatching("All done!"),
+ );
+ expect(resultStatus).toEqual(ResultStatus.Succeeded);
+ });
});
diff --git a/src/cli/runCli.ts b/src/cli/runCli.ts
index 0e893f24c..e598d757c 100644
--- a/src/cli/runCli.ts
+++ b/src/cli/runCli.ts
@@ -1,95 +1,107 @@
import chalk from "chalk";
import { Command } from "commander";
-import * as fs from "mz/fs";
+import * as fs from "node:fs/promises";
+import * as path from "node:path";
import { EOL } from "os";
-import * as path from "path";
-import { ResultStatus, typeStat, TypeStatArgv, TypeStatResult } from "../index";
-import { initialization } from "../initialization";
-import { createProcessOutput } from "../output/createProcessOutput";
-import { ProcessOutput } from "../output/types";
+import {
+ ResultStatus,
+ TypeStatArgv,
+ TypeStatResult,
+ typeStat,
+} from "../index.js";
+import { initialization } from "../initialization/index.js";
+import { createProcessOutput } from "../output/createProcessOutput.js";
+import { ProcessOutput } from "../output/types.js";
export interface CliRuntime {
- initializationRunner: typeof initialization;
- output: ProcessOutput;
- mainRunner: typeof typeStat;
+ initializationRunner: typeof initialization;
+ mainRunner: typeof typeStat;
+ output: ProcessOutput;
}
/**
* Parses raw string arguments and, if they're valid, calls to a main method.
- *
* @param rawArgv Raw string arguments and any system dependency overrides.
- * @param mainRunner Method to run with parsed arguments: generally `typeStat`.
+ * @param runtime Method to run with parsed arguments: generally `typeStat`.
* @returns Promise for the result of running TypeStat.
*/
-export const runCli = async (rawArgv: readonly string[], runtime?: CliRuntime): Promise => {
- const command = new Command()
- .storeOptionsAsProperties(true)
- .option("-c --config [config]", "path to a TypeStat config file")
- .option("-l --logfile [logfile]", "path to a logfile to print detailed logs in")
- .option("-V --version", "output the package version");
-
- const rawOptions = command.parse(rawArgv as string[]) as TypeStatArgv;
- runtime ??= {
- initializationRunner: initialization,
- output: createProcessOutput(rawOptions.logfile),
- mainRunner: typeStat,
- };
-
- if (rawArgv.length === 2) {
- const initialized = await runtime.initializationRunner(runtime.output);
- if (initialized.status !== ResultStatus.Succeeded || !initialized.skipped) {
- return initialized.status;
- }
-
- rawOptions.config = "typestat.json";
- }
-
- if ({}.hasOwnProperty.call(rawOptions, "version")) {
- runtime.output.stdout(await getPackageVersion());
- return ResultStatus.Succeeded;
- }
-
- let result: TypeStatResult;
-
- try {
- result = await runtime.mainRunner(rawOptions, runtime.output);
- } catch (error) {
- result = {
- error: error instanceof Error ? error : new Error(error as string),
- status: ResultStatus.Failed,
- };
- }
-
- switch (result.status) {
- case ResultStatus.ConfigurationError:
- runtime.output.stdout(command.helpInformation());
- logError(runtime, result.error);
- break;
-
- case ResultStatus.Failed:
- logError(runtime, result.error);
- break;
-
- case ResultStatus.Succeeded:
- runtime.output.stdout(chalk.greenBright(`${EOL}All done! โจ`));
- break;
- }
-
- return result.status;
+export const runCli = async (
+ rawArgv: readonly string[],
+ runtime?: CliRuntime,
+): Promise => {
+ const command = new Command()
+ .storeOptionsAsProperties(true)
+ .option("-c --config [config]", "path to a TypeStat config file")
+ .option(
+ "-l --logfile [logfile]",
+ "path to a logfile to print detailed logs in",
+ )
+ .option("-V --version", "output the package version");
+
+ const rawOptions = command.parse(rawArgv as string[]) as TypeStatArgv;
+ runtime ??= {
+ initializationRunner: initialization,
+ mainRunner: typeStat,
+ output: createProcessOutput(rawOptions.logfile),
+ };
+
+ if (rawArgv.length === 2) {
+ const initialized = await runtime.initializationRunner(runtime.output);
+ if (initialized.status !== ResultStatus.Succeeded || !initialized.skipped) {
+ return initialized.status;
+ }
+
+ rawOptions.config = "typestat.json";
+ }
+
+ if ({}.hasOwnProperty.call(rawOptions, "version")) {
+ runtime.output.stdout(await getPackageVersion());
+ return ResultStatus.Succeeded;
+ }
+
+ let result: TypeStatResult;
+
+ try {
+ result = await runtime.mainRunner(rawOptions, runtime.output);
+ } catch (error) {
+ result = {
+ error: error instanceof Error ? error : new Error(error as string),
+ status: ResultStatus.Failed,
+ };
+ }
+
+ switch (result.status) {
+ case ResultStatus.ConfigurationError:
+ runtime.output.stdout(command.helpInformation());
+ logError(runtime, result.error);
+ break;
+
+ case ResultStatus.Failed:
+ logError(runtime, result.error);
+ break;
+
+ case ResultStatus.Succeeded:
+ runtime.output.stdout(chalk.greenBright(`${EOL}All done! โจ`));
+ break;
+ }
+
+ return result.status;
};
const getPackageVersion = async (): Promise => {
- const packagePath = path.join(__dirname, "../../package.json");
- const rawText = (await fs.readFile(packagePath)).toString();
+ const packagePath = path.join(import.meta.dirname, "../../package.json");
+ const rawText = (await fs.readFile(packagePath)).toString();
- return (JSON.parse(rawText) as { version: string }).version;
+ return (JSON.parse(rawText) as { version: string }).version;
};
const logError = (runtime: CliRuntime, error: Error | string) => {
- runtime.output.stderr(chalk.yellow(error));
+ runtime.output.stderr(chalk.yellow(error));
- if (error instanceof Error && error.stack) {
- runtime.output.stderr(chalk.gray(error.stack.slice(error.stack.indexOf("\n") + 1)));
- }
+ if (error instanceof Error && error.stack) {
+ runtime.output.stderr(
+ chalk.gray(error.stack.slice(error.stack.indexOf("\n") + 1)),
+ );
+ }
};
diff --git a/src/collectFileNames.ts b/src/collectFileNames.ts
index 556f22eb1..b58812106 100644
--- a/src/collectFileNames.ts
+++ b/src/collectFileNames.ts
@@ -1,44 +1,56 @@
import { glob } from "glob";
-import * as path from "path";
+import * as path from "node:path";
-import { TypeStatArgv } from "./index";
+import { TypeStatArgv } from "./index.js";
export const collectFileNames = async (
- argv: TypeStatArgv,
- cwd: string,
- include: ReadonlyArray | undefined,
-): Promise | string | undefined> => {
- const globsAndNames = await collectFileNamesFromGlobs(argv, cwd, include);
- if (!globsAndNames) {
- return undefined;
- }
-
- const [fileGlobs, fileNames] = globsAndNames;
- const implicitNodeModulesInclude = implicitNodeModulesIncluded(fileGlobs, fileNames);
-
- if (implicitNodeModulesInclude) {
- return `At least one path including node_modules was included implicitly: '${implicitNodeModulesInclude}'. Either adjust TypeStat's included files to not include node_modules (recommended) or explicitly include node_modules/ (not recommended).`;
- }
-
- return fileNames;
+ argv: TypeStatArgv,
+ cwd: string,
+ include: readonly string[] | undefined,
+): Promise => {
+ const globsAndNames = await collectFileNamesFromGlobs(argv, cwd, include);
+ if (!globsAndNames) {
+ return undefined;
+ }
+
+ const [fileGlobs, fileNames] = globsAndNames;
+ const implicitNodeModulesInclude = implicitNodeModulesIncluded(
+ fileGlobs,
+ fileNames,
+ );
+
+ if (implicitNodeModulesInclude) {
+ return `At least one path including node_modules was included implicitly: '${implicitNodeModulesInclude}'. Either adjust TypeStat's included files to not include node_modules (recommended) or explicitly include node_modules/ (not recommended).`;
+ }
+
+ return fileNames;
};
const collectFileNamesFromGlobs = async (
- argv: TypeStatArgv,
- cwd: string,
- include: ReadonlyArray | undefined,
-): Promise<[ReadonlyArray, ReadonlyArray] | undefined> => {
- if (argv.args !== undefined && argv.args.length !== 0) {
- return [argv.args, await glob(argv.args)];
- }
-
- if (include === undefined) {
- return undefined;
- }
-
- return [include, await glob(include.map((subInclude) => path.join(cwd, subInclude)))];
+ argv: TypeStatArgv,
+ cwd: string,
+ include: readonly string[] | undefined,
+): Promise<[readonly string[], readonly string[]] | undefined> => {
+ if (argv.args.length) {
+ return [argv.args, await glob(argv.args)];
+ }
+
+ if (include === undefined) {
+ return undefined;
+ }
+
+ return [
+ include,
+ await glob(include.map((subInclude) => path.join(cwd, subInclude))),
+ ];
};
-const implicitNodeModulesIncluded = (fileGlobs: ReadonlyArray, fileNames: ReadonlyArray | undefined) => {
- return !fileGlobs.some((glob) => glob.includes("node_modules")) && fileNames?.find((fileName) => fileName.includes("node_modules"));
+const implicitNodeModulesIncluded = (
+ fileGlobs: readonly string[],
+ fileNames: readonly string[] | undefined,
+) => {
+ return (
+ !fileGlobs.some((glob) => glob.includes("node_modules")) &&
+ fileNames?.find((fileName) => fileName.includes("node_modules"))
+ );
};
diff --git a/src/index.ts b/src/index.ts
index 3050558be..12ee31279 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,123 +2,156 @@ import { runMutations } from "automutate";
import chalk from "chalk";
import { EOL } from "os";
-import { loadPendingOptions } from "./options/loadPendingOptions";
-import { pluralize } from "./output/pluralize";
-import { ProcessOutput } from "./output/types";
-import { PendingTypeStatOptions } from "./options/types";
-import { createTypeStatProvider } from "./runtime/createTypeStatProvider";
-import { collectFileNames } from "./collectFileNames";
+import { collectFileNames } from "./collectFileNames.js";
+import { loadPendingOptions } from "./options/loadPendingOptions.js";
+import { PendingTypeStatOptions } from "./options/types.js";
+import { pluralize } from "./output/pluralize.js";
+import { ProcessOutput } from "./output/types.js";
+import { createTypeStatProvider } from "./runtime/createTypeStatProvider.js";
/**
* Root arguments to pass to TypeStat.
*/
export interface TypeStatArgv {
- args: string[];
- config?: string;
- logfile?: string;
+ args: string[];
+ config?: string;
+ logfile?: string;
}
export enum ResultStatus {
- Succeeded = 0,
- Failed = 1,
- ConfigurationError = 2,
+ ConfigurationError = 2,
+ Failed = 1,
+ Succeeded = 0,
}
-export type TypeStatResult = ConfigurationErrorResult | FailedResult | SucceededResult;
+export type TypeStatResult =
+ | ConfigurationErrorResult
+ | FailedResult
+ | SucceededResult;
export interface ConfigurationErrorResult {
- readonly error: Error | string;
- readonly status: ResultStatus.ConfigurationError;
+ readonly error: Error | string;
+ readonly status: ResultStatus.ConfigurationError;
}
export interface FailedResult {
- readonly error: Error | string;
- readonly status: ResultStatus.Failed;
+ readonly error: Error | string;
+ readonly status: ResultStatus.Failed;
}
export interface SucceededResult {
- readonly status: ResultStatus.Succeeded;
+ readonly status: ResultStatus.Succeeded;
}
-export const typeStat = async (argv: TypeStatArgv, output: ProcessOutput): Promise => {
- const allPendingOptions = await tryLoadingPendingOptions(argv, output);
- if (allPendingOptions instanceof Error || typeof allPendingOptions === "string") {
- return {
- error: allPendingOptions,
- status: ResultStatus.ConfigurationError,
- };
- }
+export const typeStat = async (
+ argv: TypeStatArgv,
+ output: ProcessOutput,
+): Promise => {
+ const allPendingOptions = await tryLoadingPendingOptions(argv, output);
+ if (
+ allPendingOptions instanceof Error ||
+ typeof allPendingOptions === "string"
+ ) {
+ return {
+ error: allPendingOptions,
+ status: ResultStatus.ConfigurationError,
+ };
+ }
- output.stdout(chalk.greenBright("๐ Welcome to TypeStat!"));
- output.stdout(chalk.yellowBright("โ ๏ธ TypeStat is still very early stage and experimental. โ ๏ธ"));
- output.stdout(chalk.yellowBright("While it will improve your code, it will likely add syntax and type errors."));
- output.stdout(chalk.yellowBright("Use TypeStat as a starting point before you manually fix and verify any changes."));
+ output.stdout(chalk.greenBright("๐ Welcome to TypeStat!"));
+ output.stdout(
+ chalk.yellowBright(
+ "โ ๏ธ TypeStat is still very early stage and experimental. โ ๏ธ",
+ ),
+ );
+ output.stdout(
+ chalk.yellowBright(
+ "While it will improve your code, it will likely add syntax and type errors.",
+ ),
+ );
+ output.stdout(
+ chalk.yellowBright(
+ "Use TypeStat as a starting point before you manually fix and verify any changes.",
+ ),
+ );
- output.stdout(
- [
- chalk.green(`TypeStat will run through the `),
- chalk.greenBright(allPendingOptions.length),
- chalk.green(` options ${pluralize(allPendingOptions.length, "object")} specified in `),
- chalk.greenBright(argv.config),
- chalk.green(` to modify your source code.`),
- ].join(""),
- );
- output.stdout(chalk.greenBright(`This may take a while...${EOL}`));
+ output.stdout(
+ [
+ chalk.green(`TypeStat will run through the `),
+ chalk.greenBright(allPendingOptions.length),
+ chalk.green(
+ ` options ${pluralize(allPendingOptions.length, "object")} specified in `,
+ ),
+ chalk.greenBright(argv.config),
+ chalk.green(` to modify your source code.`),
+ ].join(""),
+ );
+ output.stdout(chalk.greenBright(`This may take a while...${EOL}`));
- for (let i = 0; i < allPendingOptions.length; i += 1) {
- // Collect all files to be run on this option iteration from the include glob(s)
- const fileNames = await collectFileNames(argv, process.cwd(), allPendingOptions[i].include);
- if (typeof fileNames !== "object") {
- return {
- error: new Error(
- `Could not run options object ${i + 1}: ${fileNames ?? `No files included by the 'include' setting were found.`}`,
- ),
- status: ResultStatus.Failed,
- };
- }
+ for (let i = 0; i < allPendingOptions.length; i += 1) {
+ // Collect all files to be run on this option iteration from the include glob(s)
+ const fileNames = await collectFileNames(
+ argv,
+ process.cwd(),
+ allPendingOptions[i].include,
+ );
+ if (typeof fileNames !== "object") {
+ return {
+ error: new Error(
+ `Could not run options object ${i + 1}: ${fileNames ?? `No files included by the 'include' setting were found.`}`,
+ ),
+ status: ResultStatus.Failed,
+ };
+ }
- output.stdout(
- [
- chalk.green(`${EOL}Starting options object `),
- chalk.greenBright(i + 1),
- chalk.green(" of "),
- chalk.greenBright(allPendingOptions.length),
- chalk.green(`.${EOL}`),
- ].join(""),
- );
+ output.stdout(
+ [
+ chalk.green(`${EOL}Starting options object `),
+ chalk.greenBright(i + 1),
+ chalk.green(" of "),
+ chalk.greenBright(allPendingOptions.length),
+ chalk.green(`.${EOL}`),
+ ].join(""),
+ );
- // Run the mutation providers on those starting options and files
- try {
- await runMutations({
- mutationsProvider: createTypeStatProvider({ ...allPendingOptions[i], fileNames }),
- });
- } catch (error) {
- return {
- error: error as Error,
- status: ResultStatus.Failed,
- };
- } finally {
- output.stdout(
- [
- chalk.green(`Finished options object `),
- chalk.greenBright(i + 1),
- chalk.green(" of "),
- chalk.greenBright(allPendingOptions.length),
- chalk.green(`.${EOL}`),
- ].join(""),
- );
- }
- }
+ // Run the mutation providers on those starting options and files
+ try {
+ await runMutations({
+ mutationsProvider: createTypeStatProvider({
+ ...allPendingOptions[i],
+ fileNames,
+ }),
+ });
+ } catch (error) {
+ return {
+ error: error as Error,
+ status: ResultStatus.Failed,
+ };
+ } finally {
+ output.stdout(
+ [
+ chalk.green(`Finished options object `),
+ chalk.greenBright(i + 1),
+ chalk.green(" of "),
+ chalk.greenBright(allPendingOptions.length),
+ chalk.green(`.${EOL}`),
+ ].join(""),
+ );
+ }
+ }
- return {
- status: ResultStatus.Succeeded,
- };
+ return {
+ status: ResultStatus.Succeeded,
+ };
};
-const tryLoadingPendingOptions = async (argv: TypeStatArgv, output: ProcessOutput): Promise => {
- try {
- return await loadPendingOptions(argv, output);
- } catch (error) {
- return error instanceof Error ? error : new Error(error as string);
- }
+const tryLoadingPendingOptions = async (
+ argv: TypeStatArgv,
+ output: ProcessOutput,
+): Promise => {
+ try {
+ return await loadPendingOptions(argv, output);
+ } catch (error) {
+ return error instanceof Error ? error : new Error(error as string);
+ }
};
diff --git a/src/initialization/index.ts b/src/initialization/index.ts
index 5217fb772..a95d12909 100644
--- a/src/initialization/index.ts
+++ b/src/initialization/index.ts
@@ -1,72 +1,106 @@
import chalk from "chalk";
import { EOL } from "os";
-import { ResultStatus } from "..";
-import { ProcessOutput } from "../output/types";
-import { getQuickErrorSummary } from "../shared/errors";
-
-import { initializeJavaScript } from "./initializeJavaScript";
-import { initializeProject } from "./initializeProject";
-import { InitializationPurpose, initializePurpose } from "./initializePurpose";
-import { initializeTypeScript } from "./initializeTypeScript";
+import { ResultStatus } from "../index.js";
+import { ProcessOutput } from "../output/types.js";
+import { getQuickErrorSummary } from "../shared/errors.js";
+import { initializeJavaScript } from "./initializeJavaScript/index.js";
+import { initializeProject } from "./initializeProject/index.js";
+import {
+ InitializationPurpose,
+ initializePurpose,
+} from "./initializePurpose/index.js";
+import { initializeTypeScript } from "./initializeTypeScript/index.js";
const fileName = "typestat.json";
-export type InitializationResults = FailedInitialization | RanInitializationResults;
+export type InitializationResults =
+ | FailedInitialization
+ | RanInitializationResults;
export interface FailedInitialization {
- status: ResultStatus.ConfigurationError;
+ status: ResultStatus.ConfigurationError;
}
export interface RanInitializationResults {
- status: ResultStatus.Failed | ResultStatus.Succeeded;
- skipped: boolean;
+ skipped: boolean;
+ status: ResultStatus.Failed | ResultStatus.Succeeded;
}
-export const initialization = async (output: ProcessOutput): Promise => {
- output.stdout([chalk.greenBright("๐"), chalk.green(" Welcome to TypeStat! "), chalk.greenBright("๐"), chalk.reset("")].join(""));
-
- output.stdout([chalk.reset(`This will create a new `), chalk.yellowBright(fileName), chalk.reset(` for you.`)].join(""));
-
- output.stdout(`If you don't know how to answer, that's ok - just select the default answer.`);
- output.stdout(chalk.reset(""));
-
- let skipped: boolean;
-
- try {
- skipped = await runPrompts();
- } catch (error) {
- output.stderr(getQuickErrorSummary(error));
- return {
- status: ResultStatus.ConfigurationError,
- };
- }
-
- if (!skipped) {
- output.stdout(chalk.reset(`${EOL}Awesome! You're now ready to:`));
- output.stdout(chalk.greenBright(`npx typestat --config ${fileName}`));
- output.stdout(chalk.reset(`${EOL}Once you run that, TypeStat will start auto-fixing your typings.`));
- output.stdout(
- [chalk.yellow(`Please report any bugs on https://github.com/JoshuaKGoldberg/TypeStat! `), chalk.yellowBright("๐")].join(""),
- );
- }
-
- output.stdout(chalk.reset(""));
-
- return {
- skipped,
- status: ResultStatus.Succeeded,
- };
+export const initialization = async (
+ output: ProcessOutput,
+): Promise => {
+ output.stdout(
+ [
+ chalk.greenBright("๐"),
+ chalk.green(" Welcome to TypeStat! "),
+ chalk.greenBright("๐"),
+ chalk.reset(""),
+ ].join(""),
+ );
+
+ output.stdout(
+ [
+ chalk.reset(`This will create a new `),
+ chalk.yellowBright(fileName),
+ chalk.reset(` for you.`),
+ ].join(""),
+ );
+
+ output.stdout(
+ `If you don't know how to answer, that's ok - just select the default answer.`,
+ );
+ output.stdout(chalk.reset(""));
+
+ let skipped: boolean;
+
+ try {
+ skipped = await runPrompts();
+ } catch (error) {
+ output.stderr(getQuickErrorSummary(error));
+ return {
+ status: ResultStatus.ConfigurationError,
+ };
+ }
+
+ if (!skipped) {
+ output.stdout(chalk.reset(`${EOL}Awesome! You're now ready to:`));
+ output.stdout(chalk.greenBright(`npx typestat --config ${fileName}`));
+ output.stdout(
+ chalk.reset(
+ `${EOL}Once you run that, TypeStat will start auto-fixing your typings.`,
+ ),
+ );
+ output.stdout(
+ [
+ chalk.yellow(
+ `Please report any bugs on https://github.com/JoshuaKGoldberg/TypeStat! `,
+ ),
+ chalk.yellowBright("๐"),
+ ].join(""),
+ );
+ }
+
+ output.stdout(chalk.reset(""));
+
+ return {
+ skipped,
+ status: ResultStatus.Succeeded,
+ };
};
const runPrompts = async () => {
- const purpose = await initializePurpose();
- if (purpose === InitializationPurpose.Skipped) {
- return true;
- }
-
- const project = await initializeProject();
- await (purpose === InitializationPurpose.ConvertJavaScript ? initializeJavaScript : initializeTypeScript)({ fileName, project });
-
- return false;
+ const purpose = await initializePurpose();
+ if (purpose === InitializationPurpose.Skipped) {
+ return true;
+ }
+
+ const project = await initializeProject();
+ await (
+ purpose === InitializationPurpose.ConvertJavaScript
+ ? initializeJavaScript
+ : initializeTypeScript
+ )({ fileName, project });
+
+ return false;
};
diff --git a/src/initialization/initializeJavaScript/cleanups.ts b/src/initialization/initializeJavaScript/cleanups.ts
index 1d136a719..d4461911a 100644
--- a/src/initialization/initializeJavaScript/cleanups.ts
+++ b/src/initialization/initializeJavaScript/cleanups.ts
@@ -1,20 +1,21 @@
import { prompt } from "enquirer";
export enum InitializationCleanups {
- No = "No",
- Yes = "Yes",
+ No = "No",
+ Yes = "Yes",
}
export const initializeCleanups = async () => {
- const { cleanups } = await prompt<{ cleanups: InitializationCleanups }>([
- {
- choices: [InitializationCleanups.No, InitializationCleanups.Yes],
- initial: 1,
- message: "Would you like to suppress remaining type errors with // @ts-expect-error comments?",
- name: "cleanups",
- type: "select",
- },
- ]);
+ const { cleanups } = await prompt<{ cleanups: InitializationCleanups }>([
+ {
+ choices: [InitializationCleanups.No, InitializationCleanups.Yes],
+ initial: 1,
+ message:
+ "Would you like to suppress remaining type errors with // @ts-expect-error comments?",
+ name: "cleanups",
+ type: "select",
+ },
+ ]);
- return cleanups;
+ return cleanups;
};
diff --git a/src/initialization/initializeJavaScript/createJavaScriptConfig.test.ts b/src/initialization/initializeJavaScript/createJavaScriptConfig.test.ts
index 75daeeab6..97f22b5f1 100644
--- a/src/initialization/initializeJavaScript/createJavaScriptConfig.test.ts
+++ b/src/initialization/initializeJavaScript/createJavaScriptConfig.test.ts
@@ -1,186 +1,227 @@
-import { InitializationImports } from "./imports";
-import { InitializationRenames } from "./renames";
-import { createJavaScriptConfig } from "./createJavaScriptConfig";
-import { InitializationCleanups } from "./cleanups";
+import { describe, expect, test } from "vitest";
-describe(createJavaScriptConfig, () => {
- test.each([
- {
- expected: {
- files: { renameExtensions: "ts" },
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- project: "tsconfig.json",
- },
- name: "Basic",
- settings: {
- cleanups: InitializationCleanups.No,
- imports: InitializationImports.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.TS,
- },
- },
- {
- expected: {
- files: { renameExtensions: "ts" },
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- cleanups: { suppressTypeErrors: true },
- project: "tsconfig.json",
- },
- name: "Basic with Suppressions",
- settings: {
- cleanups: InitializationCleanups.Yes,
- imports: InitializationImports.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.TS,
- },
- },
- {
- expected: [
- {
- files: { renameExtensions: "ts" },
- fixes: { importExtensions: true },
- include: ["src/**/*.{js,jsx}"],
- project: "tsconfig.json",
- },
- {
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- include: ["src/**/*.ts"],
- project: "tsconfig.json",
- },
- ],
- name: "TS Renames (multiple sourceFiles extensions)",
- settings: {
- imports: InitializationImports.Yes,
- cleanups: InitializationCleanups.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.TS,
- sourceFiles: "src/**/*.{js,jsx}",
- },
- },
- {
- expected: [
- {
- files: { renameExtensions: "tsx" },
- fixes: { importExtensions: true },
- include: ["src/**/*.{js,jsx}"],
- project: "tsconfig.json",
- },
- {
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- include: ["src/**/*.tsx"],
- project: "tsconfig.json",
- },
- ],
- name: "TSX Renames (multiple sourceFiles extensions)",
- settings: {
- imports: InitializationImports.Yes,
- cleanups: InitializationCleanups.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.TSX,
- sourceFiles: "src/**/*.{js,jsx}",
- },
- },
- {
- expected: [
- { files: { renameExtensions: true }, fixes: { importExtensions: true }, project: "tsconfig.json" },
- { fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true }, project: "tsconfig.json" },
- ],
- name: "Auto Renames (no sourceFiles)",
- settings: {
- cleanups: InitializationCleanups.No,
- imports: InitializationImports.Yes,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.Auto,
- },
- },
- {
- expected: [
- {
- files: { renameExtensions: true },
- fixes: { importExtensions: true },
- include: ["src/**/*.js"],
- project: "tsconfig.json",
- },
- {
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- include: ["src/**/*.{ts,tsx}"],
- project: "tsconfig.json",
- },
- ],
- name: "Auto Renames (single sourceFiles extension)",
- settings: {
- imports: InitializationImports.Yes,
- cleanups: InitializationCleanups.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.Auto,
- sourceFiles: "src/**/*.js",
- },
- },
- {
- expected: [
- {
- files: { renameExtensions: true },
- fixes: { importExtensions: true },
- include: ["src/**/*.{js,jsx}"],
- project: "tsconfig.json",
- },
- {
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- include: ["src/**/*.{ts,tsx}"],
- project: "tsconfig.json",
- },
- ],
- name: "Auto Renames (multiple sourceFiles extensions)",
- settings: {
- imports: InitializationImports.Yes,
- cleanups: InitializationCleanups.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.Auto,
- sourceFiles: "src/**/*.{js,jsx}",
- },
- },
- {
- expected: [
- {
- files: { renameExtensions: true },
- fixes: { importExtensions: true },
- include: ["src/**/*.js(x)"],
- project: "tsconfig.json",
- },
- {
- fixes: { incompleteTypes: true, missingProperties: true, noImplicitAny: true },
- include: ["src/**/*.ts(x)"],
- project: "tsconfig.json",
- },
- ],
- name: "Auto Renames (parenthesized sourceFiles extensions)",
- settings: {
- imports: InitializationImports.Yes,
- cleanups: InitializationCleanups.No,
- project: {
- filePath: "tsconfig.json",
- },
- renames: InitializationRenames.Auto,
- sourceFiles: "src/**/*.js(x)",
- },
- },
- ])("$name", ({ expected, settings }) => {
- const actual = createJavaScriptConfig(settings);
+import { InitializationCleanups } from "./cleanups.js";
+import { createJavaScriptConfig } from "./createJavaScriptConfig.js";
+import { InitializationImports } from "./imports.js";
+import { InitializationRenames } from "./renames.js";
- expect(actual).toEqual(expected);
- });
+describe("createJavaScriptConfig", () => {
+ test.each([
+ {
+ expected: {
+ files: { renameExtensions: "ts" },
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ project: "tsconfig.json",
+ },
+ name: "Basic",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.No,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.TS,
+ },
+ },
+ {
+ expected: {
+ cleanups: { suppressTypeErrors: true },
+ files: { renameExtensions: "ts" },
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ project: "tsconfig.json",
+ },
+ name: "Basic with Suppressions",
+ settings: {
+ cleanups: InitializationCleanups.Yes,
+ imports: InitializationImports.No,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.TS,
+ },
+ },
+ {
+ expected: [
+ {
+ files: { renameExtensions: "ts" },
+ fixes: { importExtensions: true },
+ include: ["src/**/*.{js,jsx}"],
+ project: "tsconfig.json",
+ },
+ {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ include: ["src/**/*.ts"],
+ project: "tsconfig.json",
+ },
+ ],
+ name: "TS Renames (multiple sourceFiles extensions)",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.Yes,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.TS,
+ sourceFiles: "src/**/*.{js,jsx}",
+ },
+ },
+ {
+ expected: [
+ {
+ files: { renameExtensions: "tsx" },
+ fixes: { importExtensions: true },
+ include: ["src/**/*.{js,jsx}"],
+ project: "tsconfig.json",
+ },
+ {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ include: ["src/**/*.tsx"],
+ project: "tsconfig.json",
+ },
+ ],
+ name: "TSX Renames (multiple sourceFiles extensions)",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.Yes,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.TSX,
+ sourceFiles: "src/**/*.{js,jsx}",
+ },
+ },
+ {
+ expected: [
+ {
+ files: { renameExtensions: true },
+ fixes: { importExtensions: true },
+ project: "tsconfig.json",
+ },
+ {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ project: "tsconfig.json",
+ },
+ ],
+ name: "Auto Renames (no sourceFiles)",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.Yes,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.Auto,
+ },
+ },
+ {
+ expected: [
+ {
+ files: { renameExtensions: true },
+ fixes: { importExtensions: true },
+ include: ["src/**/*.js"],
+ project: "tsconfig.json",
+ },
+ {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ include: ["src/**/*.{ts,tsx}"],
+ project: "tsconfig.json",
+ },
+ ],
+ name: "Auto Renames (single sourceFiles extension)",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.Yes,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.Auto,
+ sourceFiles: "src/**/*.js",
+ },
+ },
+ {
+ expected: [
+ {
+ files: { renameExtensions: true },
+ fixes: { importExtensions: true },
+ include: ["src/**/*.{js,jsx}"],
+ project: "tsconfig.json",
+ },
+ {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ include: ["src/**/*.{ts,tsx}"],
+ project: "tsconfig.json",
+ },
+ ],
+ name: "Auto Renames (multiple sourceFiles extensions)",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.Yes,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.Auto,
+ sourceFiles: "src/**/*.{js,jsx}",
+ },
+ },
+ {
+ expected: [
+ {
+ files: { renameExtensions: true },
+ fixes: { importExtensions: true },
+ include: ["src/**/*.js(x)"],
+ project: "tsconfig.json",
+ },
+ {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ include: ["src/**/*.ts(x)"],
+ project: "tsconfig.json",
+ },
+ ],
+ name: "Auto Renames (parenthesized sourceFiles extensions)",
+ settings: {
+ cleanups: InitializationCleanups.No,
+ imports: InitializationImports.Yes,
+ project: {
+ filePath: "tsconfig.json",
+ },
+ renames: InitializationRenames.Auto,
+ sourceFiles: "src/**/*.js(x)",
+ },
+ },
+ ])("$name", ({ expected, settings }) => {
+ const actual = createJavaScriptConfig(settings);
+
+ expect(actual).toEqual(expected);
+ });
});
diff --git a/src/initialization/initializeJavaScript/createJavaScriptConfig.ts b/src/initialization/initializeJavaScript/createJavaScriptConfig.ts
index 3daa3876a..024e0a8ae 100644
--- a/src/initialization/initializeJavaScript/createJavaScriptConfig.ts
+++ b/src/initialization/initializeJavaScript/createJavaScriptConfig.ts
@@ -1,91 +1,103 @@
-import { ProjectDescription } from "../initializeProject/shared";
-import { InitializationImports } from "./imports";
-import { InitializationRenames } from "./renames";
-import { InitializationCleanups } from "./cleanups";
+import { ProjectDescription } from "../initializeProject/shared.js";
+import { InitializationCleanups } from "./cleanups.js";
+import { InitializationImports } from "./imports.js";
+import { InitializationRenames } from "./renames.js";
export interface JavaScriptConfigSettings {
- cleanups: InitializationCleanups;
- imports: InitializationImports;
- project: ProjectDescription;
- renames: InitializationRenames;
- sourceFiles?: string;
+ cleanups: InitializationCleanups;
+ imports: InitializationImports;
+ project: ProjectDescription;
+ renames: InitializationRenames;
+ sourceFiles?: string;
}
-export const createJavaScriptConfig = ({ imports, project, sourceFiles, cleanups, renames }: JavaScriptConfigSettings) => {
- const fileConversion = {
- files: {
- renameExtensions: printRenames(renames),
- },
- };
- const coreConversion = {
- fixes: {
- incompleteTypes: true,
- missingProperties: true,
- noImplicitAny: true,
- },
- ...(cleanups === InitializationCleanups.Yes ? { cleanups: { suppressTypeErrors: true } } : {}),
- };
- const shared = (include: string[] | undefined) => ({
- ...(include && { include }),
- project: project.filePath,
- });
+export const createJavaScriptConfig = ({
+ cleanups,
+ imports,
+ project,
+ renames,
+ sourceFiles,
+}: JavaScriptConfigSettings) => {
+ const fileConversion = {
+ files: {
+ renameExtensions: printRenames(renames),
+ },
+ };
+ const coreConversion = {
+ fixes: {
+ incompleteTypes: true,
+ missingProperties: true,
+ noImplicitAny: true,
+ },
+ ...(cleanups === InitializationCleanups.Yes
+ ? { cleanups: { suppressTypeErrors: true } }
+ : {}),
+ };
+ const shared = (include: string[] | undefined) => ({
+ ...(include && { include }),
+ project: project.filePath,
+ });
- const allConversions =
- imports === InitializationImports.Yes
- ? [
- {
- ...fileConversion,
- fixes: {
- importExtensions: true,
- },
- ...shared(sourceFiles ? [sourceFiles] : undefined),
- },
- {
- ...coreConversion,
- ...shared(
- sourceFiles
- ? renames === InitializationRenames.Auto
- ? renameSourceFilesExtensionsAuto(sourceFiles)
- : renames === InitializationRenames.TS
- ? renameSourceFilesExtensions(sourceFiles, "ts")
- : renameSourceFilesExtensions(sourceFiles, "tsx")
- : undefined,
- ),
- },
- ]
- : {
- ...fileConversion,
- ...coreConversion,
- ...shared(sourceFiles ? [sourceFiles] : undefined),
- };
+ const allConversions =
+ imports === InitializationImports.Yes
+ ? [
+ {
+ ...fileConversion,
+ fixes: {
+ importExtensions: true,
+ },
+ ...shared(sourceFiles ? [sourceFiles] : undefined),
+ },
+ {
+ ...coreConversion,
+ ...shared(
+ sourceFiles
+ ? renames === InitializationRenames.Auto
+ ? renameSourceFilesExtensionsAuto(sourceFiles)
+ : renames === InitializationRenames.TS
+ ? renameSourceFilesExtensions(sourceFiles, "ts")
+ : renameSourceFilesExtensions(sourceFiles, "tsx")
+ : undefined,
+ ),
+ },
+ ]
+ : {
+ ...fileConversion,
+ ...coreConversion,
+ ...shared(sourceFiles ? [sourceFiles] : undefined),
+ };
- return allConversions;
+ return allConversions;
};
const printRenames = (renames: InitializationRenames) => {
- switch (renames) {
- case InitializationRenames.Auto:
- return true;
+ switch (renames) {
+ case InitializationRenames.Auto:
+ return true;
- case InitializationRenames.TS:
- return "ts";
+ case InitializationRenames.TS:
+ return "ts";
- case InitializationRenames.TSX:
- return "tsx";
- }
+ case InitializationRenames.TSX:
+ return "tsx";
+ }
};
function renameSourceFilesExtensionsAuto(sourceFiles: string) {
- for (const [original, replacement] of [
- [/\{js,jsx\}/, "{ts,tsx}"],
- [/\.js$/, ".{ts,tsx}"],
- ] as const) {
- sourceFiles = sourceFiles.replace(original, replacement);
- }
+ for (const [original, replacement] of [
+ [/\{js,jsx\}/, "{ts,tsx}"],
+ [/\.js$/, ".{ts,tsx}"],
+ ] as const) {
+ sourceFiles = sourceFiles.replace(original, replacement);
+ }
- return renameSourceFilesExtensions(sourceFiles, "ts");
+ return renameSourceFilesExtensions(sourceFiles, "ts");
}
function renameSourceFilesExtensions(sourceFiles: string, extension: string) {
- return [sourceFiles.replace(/(\.|{)js/, `$1${extension}`).replace(new RegExp(`{${extension},jsx?}`), extension)];
+ return [
+ sourceFiles
+ .replace(/(\.|\{)js/, `$1${extension}`)
+ .replace(new RegExp(`{${extension},jsx?}`), extension),
+ ];
}
diff --git a/src/initialization/initializeJavaScript/imports.ts b/src/initialization/initializeJavaScript/imports.ts
index f1d422660..9979f1c7a 100644
--- a/src/initialization/initializeJavaScript/imports.ts
+++ b/src/initialization/initializeJavaScript/imports.ts
@@ -1,20 +1,21 @@
import { prompt } from "enquirer";
export enum InitializationImports {
- No = "No",
- Yes = "Yes",
+ No = "No",
+ Yes = "Yes",
}
export const initializeImports = async () => {
- const { imports } = await prompt<{ imports: InitializationImports }>([
- {
- choices: [InitializationImports.No, InitializationImports.Yes],
- initial: 1,
- message: "Would you like imports without extensions to have those extensions added in?",
- name: "imports",
- type: "select",
- },
- ]);
+ const { imports } = await prompt<{ imports: InitializationImports }>([
+ {
+ choices: [InitializationImports.No, InitializationImports.Yes],
+ initial: 1,
+ message:
+ "Would you like imports without extensions to have those extensions added in?",
+ name: "imports",
+ type: "select",
+ },
+ ]);
- return imports;
+ return imports;
};
diff --git a/src/initialization/initializeJavaScript/index.ts b/src/initialization/initializeJavaScript/index.ts
index 00e9e439c..a4ebd9388 100644
--- a/src/initialization/initializeJavaScript/index.ts
+++ b/src/initialization/initializeJavaScript/index.ts
@@ -1,24 +1,36 @@
-import { writeFile } from "mz/fs";
+import * as fs from "node:fs/promises";
-import { ProjectDescription } from "../initializeProject/shared";
-import { initializeSources } from "../sources";
-import { initializeImports } from "./imports";
-import { initializeRenames } from "./renames";
-import { createJavaScriptConfig } from "./createJavaScriptConfig";
-import { initializeCleanups } from "./cleanups";
+import { ProjectDescription } from "../initializeProject/shared.js";
+import { initializeSources } from "../sources/index.js";
+import { initializeCleanups } from "./cleanups.js";
+import { createJavaScriptConfig } from "./createJavaScriptConfig.js";
+import { initializeImports } from "./imports.js";
+import { initializeRenames } from "./renames.js";
export interface InitializeJavaScriptSettings {
- fileName: string;
- project: ProjectDescription;
+ fileName: string;
+ project: ProjectDescription;
}
-export const initializeJavaScript = async ({ fileName, project }: InitializeJavaScriptSettings) => {
- const sourceFiles = await initializeSources({ fromJavaScript: true, project });
- const renames = await initializeRenames();
- const imports = await initializeImports();
- const cleanups = await initializeCleanups();
+export const initializeJavaScript = async ({
+ fileName,
+ project,
+}: InitializeJavaScriptSettings) => {
+ const sourceFiles = await initializeSources({
+ fromJavaScript: true,
+ project,
+ });
+ const renames = await initializeRenames();
+ const imports = await initializeImports();
+ const cleanups = await initializeCleanups();
- const settings = createJavaScriptConfig({ imports, project, sourceFiles, cleanups, renames });
+ const settings = createJavaScriptConfig({
+ cleanups,
+ imports,
+ project,
+ renames,
+ sourceFiles,
+ });
- await writeFile(fileName, JSON.stringify(settings, undefined, 4));
+ await fs.writeFile(fileName, JSON.stringify(settings, undefined, 4));
};
diff --git a/src/initialization/initializeJavaScript/renames.ts b/src/initialization/initializeJavaScript/renames.ts
index bf9628a90..fc0109c57 100644
--- a/src/initialization/initializeJavaScript/renames.ts
+++ b/src/initialization/initializeJavaScript/renames.ts
@@ -1,21 +1,25 @@
import { prompt } from "enquirer";
export enum InitializationRenames {
- Auto = "Rename files containing JSX to .tsx and others to .ts",
- TS = "Rename all files to .ts",
- TSX = "Rename all files to .tsx",
+ Auto = "Rename files containing JSX to .tsx and others to .ts",
+ TS = "Rename all files to .ts",
+ TSX = "Rename all files to .tsx",
}
export const initializeRenames = async () => {
- const { renames } = await prompt<{ renames: InitializationRenames }>([
- {
- choices: [InitializationRenames.Auto, InitializationRenames.TS, InitializationRenames.TSX],
- initial: 0,
- message: "How would you like .js files to be renamed?",
- name: "renames",
- type: "select",
- },
- ]);
+ const { renames } = await prompt<{ renames: InitializationRenames }>([
+ {
+ choices: [
+ InitializationRenames.Auto,
+ InitializationRenames.TS,
+ InitializationRenames.TSX,
+ ],
+ initial: 0,
+ message: "How would you like .js files to be renamed?",
+ name: "renames",
+ type: "select",
+ },
+ ]);
- return renames;
+ return renames;
};
diff --git a/src/initialization/initializeProject/index.ts b/src/initialization/initializeProject/index.ts
index a1f8b6bb1..ee323c3c2 100644
--- a/src/initialization/initializeProject/index.ts
+++ b/src/initialization/initializeProject/index.ts
@@ -2,55 +2,67 @@ import { prompt } from "enquirer";
import * as fs from "fs";
import { glob } from "glob";
-import { uniquify } from "../../shared/arrays";
-import { initializeNewProject } from "./initializeNewProject";
-import { ProjectDescription, TSConfigLocationSuggestion, TSConfigLocation } from "./shared";
+import { uniquify } from "../../shared/arrays.js";
+import { initializeNewProject } from "./initializeNewProject.js";
+import {
+ ProjectDescription,
+ TSConfigLocation,
+ TSConfigLocationSuggestion,
+} from "./shared.js";
export const initializeProject = async (): Promise => {
- const project = await initializeBuiltInProject();
+ const project = await initializeBuiltInProject();
- return project === TSConfigLocationSuggestion.Custom
- ? initializeCustomProject()
- : project === TSConfigLocationSuggestion.DoesNotExist
- ? initializeNewProject()
- : { filePath: project };
+ return project === TSConfigLocationSuggestion.Custom
+ ? initializeCustomProject()
+ : project === TSConfigLocationSuggestion.DoesNotExist
+ ? initializeNewProject()
+ : { filePath: project };
};
const defaultSettings = {
- message: "Where is your tsconfig.json?",
- name: "project",
+ message: "Where is your tsconfig.json?",
+ name: "project",
};
const initializeBuiltInProject = async () => {
- const choices = [
- ...uniquify(TSConfigLocation.Root, TSConfigLocation.UnderSrc, ...(await glob(["./tsconfig*json", "./*/tsconfig*json"]))),
- TSConfigLocationSuggestion.Custom,
- TSConfigLocationSuggestion.DoesNotExist,
- ];
-
- const { project } = await prompt<{ project: TSConfigLocation | TSConfigLocationSuggestion }>([
- {
- ...defaultSettings,
- choices,
- initial: Math.max(
- 0,
- [TSConfigLocation.Root, TSConfigLocation.UnderSrc].findIndex((choice) => fs.existsSync(choice)),
- ),
- type: "select",
- },
- ]);
-
- return project;
+ const choices = [
+ ...uniquify(
+ TSConfigLocation.Root,
+ TSConfigLocation.UnderSrc,
+ ...(await glob(["./tsconfig*json", "./*/tsconfig*json"])),
+ ),
+ TSConfigLocationSuggestion.Custom,
+ TSConfigLocationSuggestion.DoesNotExist,
+ ];
+
+ const { project } = await prompt<{
+ project: TSConfigLocation | TSConfigLocationSuggestion;
+ }>([
+ {
+ ...defaultSettings,
+ choices,
+ initial: Math.max(
+ 0,
+ [TSConfigLocation.Root, TSConfigLocation.UnderSrc].findIndex((choice) =>
+ fs.existsSync(choice),
+ ),
+ ),
+ type: "select",
+ },
+ ]);
+
+ return project;
};
const initializeCustomProject = async (): Promise => {
- const { project } = await prompt<{ project: string }>([
- {
- ...defaultSettings,
- initial: "./tsconfig.json",
- type: "text",
- },
- ]);
-
- return { filePath: project };
+ const { project } = await prompt<{ project: string }>([
+ {
+ ...defaultSettings,
+ initial: "./tsconfig.json",
+ type: "text",
+ },
+ ]);
+
+ return { filePath: project };
};
diff --git a/src/initialization/initializeProject/initializeNewProject.ts b/src/initialization/initializeProject/initializeNewProject.ts
index 632b63ccd..add3447a5 100644
--- a/src/initialization/initializeProject/initializeNewProject.ts
+++ b/src/initialization/initializeProject/initializeNewProject.ts
@@ -1,78 +1,80 @@
-import { fs } from "mz";
import { prompt } from "enquirer";
-import { ProjectDescription } from "./shared";
+import * as fs from "node:fs/promises";
+
+import { ProjectDescription } from "./shared.js";
const filePath = "./tsconfig.json";
export const initializeNewProject = async (): Promise => {
- const { emit } = await prompt<{ emit: string }>([
- {
- choices: ["yes", "no"],
- message: "Should TypeScript output .js files from .ts sources?",
- name: "emit",
- type: "select",
- },
- ]);
- const { inBrowser } = await prompt<{ inBrowser: string }>([
- {
- choices: ["yes", "no"],
- message: "Does your code run in browser?",
- name: "inBrowser",
- type: "select",
- },
- ]);
- const jsx =
- inBrowser &&
- (
- await prompt<{ jsx: string }>([
- {
- choices: ["yes", "no"],
- message: "Does your project use JSX?",
- name: "jsx",
- type: "select",
- },
- ])
- ).jsx;
- const { target } = await prompt<{ target: string }>([
- {
- choices: ["es2020", "es2021", "es2022", "esnext"],
- message: "What minimum runtime does your code run on?",
- name: "target",
- type: "select",
- },
- ]);
- const { strict } = await prompt<{ strict: string }>([
- {
- choices: ["yes", "no"],
- message: "Would you like to enable TypeScript's strict compiler options? (recommended)",
- name: "strict",
- type: "select",
- },
- ]);
+ const { emit } = await prompt<{ emit: string }>([
+ {
+ choices: ["yes", "no"],
+ message: "Should TypeScript output .js files from .ts sources?",
+ name: "emit",
+ type: "select",
+ },
+ ]);
+ const { inBrowser } = await prompt<{ inBrowser: string }>([
+ {
+ choices: ["yes", "no"],
+ message: "Does your code run in browser?",
+ name: "inBrowser",
+ type: "select",
+ },
+ ]);
+ const jsx =
+ inBrowser &&
+ (
+ await prompt<{ jsx: string }>([
+ {
+ choices: ["yes", "no"],
+ message: "Does your project use JSX?",
+ name: "jsx",
+ type: "select",
+ },
+ ])
+ ).jsx;
+ const { target } = await prompt<{ target: string }>([
+ {
+ choices: ["es2020", "es2021", "es2022", "esnext"],
+ message: "What minimum runtime does your code run on?",
+ name: "target",
+ type: "select",
+ },
+ ]);
+ const { strict } = await prompt<{ strict: string }>([
+ {
+ choices: ["yes", "no"],
+ message:
+ "Would you like to enable TypeScript's strict compiler options? (recommended)",
+ name: "strict",
+ type: "select",
+ },
+ ]);
- await fs.writeFile(
- filePath,
- JSON.stringify(
- {
- compilerOptions: {
- declaration: true,
- declarationMap: true,
- ...(emit === "no" && { noEmit: true }),
- esModuleInterop: true,
- ...(inBrowser === "no" && { lib: [target] }),
- ...(jsx === "yes" && { jsx: "react" }),
- sourceMap: true,
- moduleResolution: "node",
- module: "nodenext",
- skipLibCheck: true,
- ...(strict === "yes" ? { strict: true } : {}),
- target,
- },
- },
- null,
- 4,
- ),
- );
+ await fs.writeFile(
+ filePath,
+ JSON.stringify(
+ {
+ compilerOptions: {
+ declaration: true,
+ declarationMap: true,
+ ...(emit === "no" && { noEmit: true }),
+ esModuleInterop: true,
+ ...(inBrowser === "no" && { lib: [target] }),
+ ...(jsx === "yes" && { jsx: "react" }),
+ module: "nodenext",
+ moduleResolution: "node",
+ skipLibCheck: true,
+ sourceMap: true,
+ ...(strict === "yes" ? { strict: true } : {}),
+ target,
+ },
+ },
+ null,
+ 4,
+ ),
+ );
- return { created: true, filePath };
+ return { created: true, filePath };
};
diff --git a/src/initialization/initializeProject/shared.ts b/src/initialization/initializeProject/shared.ts
index 56f1d23c7..7b6392e85 100644
--- a/src/initialization/initializeProject/shared.ts
+++ b/src/initialization/initializeProject/shared.ts
@@ -1,14 +1,14 @@
export enum TSConfigLocationSuggestion {
- Custom = "custom",
- DoesNotExist = "I don't have one yet",
+ Custom = "custom",
+ DoesNotExist = "I don't have one yet",
}
export enum TSConfigLocation {
- Root = "./tsconfig.json",
- UnderSrc = "./src/tsconfig.json",
+ Root = "./tsconfig.json",
+ UnderSrc = "./src/tsconfig.json",
}
export interface ProjectDescription {
- created?: boolean;
- filePath: string;
+ created?: boolean;
+ filePath: string;
}
diff --git a/src/initialization/initializePurpose/index.ts b/src/initialization/initializePurpose/index.ts
index b481ff0f5..77c273c1a 100644
--- a/src/initialization/initializePurpose/index.ts
+++ b/src/initialization/initializePurpose/index.ts
@@ -2,26 +2,29 @@ import { prompt } from "enquirer";
import * as fs from "fs";
export enum InitializationPurpose {
- ConvertJavaScript = "Convert my JavaScript files to TypeScript",
- Skipped = "Run TypeStat with the typestat.json file that already exists",
- ImproveTypeScript = "Improve typings in my TypeScript files",
+ ConvertJavaScript = "Convert my JavaScript files to TypeScript",
+ ImproveTypeScript = "Improve typings in my TypeScript files",
+ Skipped = "Run TypeStat with the typestat.json file that already exists",
}
export const initializePurpose = async () => {
- const choices = [InitializationPurpose.ConvertJavaScript, InitializationPurpose.ImproveTypeScript];
+ const choices = [
+ InitializationPurpose.ConvertJavaScript,
+ InitializationPurpose.ImproveTypeScript,
+ ];
- if (fs.existsSync("typestat.json")) {
- choices.unshift(InitializationPurpose.Skipped);
- }
+ if (fs.existsSync("typestat.json")) {
+ choices.unshift(InitializationPurpose.Skipped);
+ }
- const { purpose } = await prompt<{ purpose: InitializationPurpose }>([
- {
- choices,
- message: "What are you trying to accomplish?",
- name: "purpose",
- type: "select",
- },
- ]);
+ const { purpose } = await prompt<{ purpose: InitializationPurpose }>([
+ {
+ choices,
+ message: "What are you trying to accomplish?",
+ name: "purpose",
+ type: "select",
+ },
+ ]);
- return purpose;
+ return purpose;
};
diff --git a/src/initialization/initializeTypeScript/improvements.ts b/src/initialization/initializeTypeScript/improvements.ts
index 128d2e9aa..444861226 100644
--- a/src/initialization/initializeTypeScript/improvements.ts
+++ b/src/initialization/initializeTypeScript/improvements.ts
@@ -1,31 +1,33 @@
import { prompt } from "enquirer";
export enum InitializationImprovement {
- MissingProperties = "Add missing property declarations to classes",
- NoImplicitAny = "Enable the --noImplicitAny compiler flag",
- NoImplicitThis = "Enable the --noImplicitThis compiler flag",
- NoInferableTypes = "Remove type annotations that don't change the meaning of code",
- StrictNullChecks = "Enable the --strictNullChecks compiler flag",
+ MissingProperties = "Add missing property declarations to classes",
+ NoImplicitAny = "Enable the --noImplicitAny compiler flag",
+ NoImplicitThis = "Enable the --noImplicitThis compiler flag",
+ NoInferableTypes = "Remove type annotations that don't change the meaning of code",
+ StrictNullChecks = "Enable the --strictNullChecks compiler flag",
}
export const initializeImprovements = async () => {
- const choices = [
- InitializationImprovement.MissingProperties,
- InitializationImprovement.NoImplicitAny,
- InitializationImprovement.NoImplicitThis,
- InitializationImprovement.NoInferableTypes,
- InitializationImprovement.StrictNullChecks,
- ];
+ const choices = [
+ InitializationImprovement.MissingProperties,
+ InitializationImprovement.NoImplicitAny,
+ InitializationImprovement.NoImplicitThis,
+ InitializationImprovement.NoInferableTypes,
+ InitializationImprovement.StrictNullChecks,
+ ];
- const { improvements } = await prompt<{ improvements: InitializationImprovement[] }>([
- {
- choices,
- initial: 0,
- message: "Which improvements would you like to make?",
- name: "improvements",
- type: "multiselect",
- },
- ]);
+ const { improvements } = await prompt<{
+ improvements: InitializationImprovement[];
+ }>([
+ {
+ choices,
+ initial: 0,
+ message: "Which improvements would you like to make?",
+ name: "improvements",
+ type: "multiselect",
+ },
+ ]);
- return improvements;
+ return improvements;
};
diff --git a/src/initialization/initializeTypeScript/index.ts b/src/initialization/initializeTypeScript/index.ts
index bfe9009c4..c5710adf7 100644
--- a/src/initialization/initializeTypeScript/index.ts
+++ b/src/initialization/initializeTypeScript/index.ts
@@ -1,25 +1,44 @@
-import { initializeSources } from "../sources";
-
-import { ProjectDescription } from "../initializeProject/shared";
-import { InitializationImprovement, initializeImprovements } from "./improvements";
-import { initializeTests } from "./initializeTests";
-import { writeMultiTypeScriptConfig } from "./writeMultiTypeScriptConfig";
-import { writeSingleTypeScriptConfig } from "./writeSingleTypeScriptConfig";
+import { ProjectDescription } from "../initializeProject/shared.js";
+import { initializeSources } from "../sources/index.js";
+import {
+ InitializationImprovement,
+ initializeImprovements,
+} from "./improvements.js";
+import { initializeTests } from "./initializeTests.js";
+import { writeMultiTypeScriptConfig } from "./writeMultiTypeScriptConfig.js";
+import { writeSingleTypeScriptConfig } from "./writeSingleTypeScriptConfig.js";
export interface InitializeTypeScriptSettings {
- fileName: string;
- project: ProjectDescription;
+ fileName: string;
+ project: ProjectDescription;
}
-export const initializeTypeScript = async ({ fileName, project }: InitializeTypeScriptSettings) => {
- const improvements = new Set(await initializeImprovements());
- const sourceFiles = await initializeSources({ fromJavaScript: false, project });
+export const initializeTypeScript = async ({
+ fileName,
+ project,
+}: InitializeTypeScriptSettings) => {
+ const improvements = new Set(await initializeImprovements());
+ const sourceFiles = await initializeSources({
+ fromJavaScript: false,
+ project,
+ });
- if (!improvements.has(InitializationImprovement.StrictNullChecks)) {
- await writeSingleTypeScriptConfig({ fileName, improvements, project, sourceFiles });
- return;
- }
+ if (!improvements.has(InitializationImprovement.StrictNullChecks)) {
+ await writeSingleTypeScriptConfig({
+ fileName,
+ improvements,
+ project,
+ sourceFiles,
+ });
+ return;
+ }
- const testFiles = await initializeTests();
- await writeMultiTypeScriptConfig({ fileName, improvements, project, sourceFiles, testFiles });
+ const testFiles = await initializeTests();
+ await writeMultiTypeScriptConfig({
+ fileName,
+ improvements,
+ project,
+ sourceFiles,
+ testFiles,
+ });
};
diff --git a/src/initialization/initializeTypeScript/initializeTests.ts b/src/initialization/initializeTypeScript/initializeTests.ts
index f4a9afecb..3ddb75b15 100644
--- a/src/initialization/initializeTypeScript/initializeTests.ts
+++ b/src/initialization/initializeTypeScript/initializeTests.ts
@@ -4,44 +4,47 @@ const other = "other";
const none = "(none)";
export const initializeTests = async () => {
- const builtIn = await initializeBuiltInTests();
- if (builtIn === none) return;
+ const builtIn = await initializeBuiltInTests();
- return builtIn === other ? getCustomTests() : builtIn;
+ if (builtIn === none) {
+ return;
+ }
+
+ return builtIn === other ? getCustomTests() : builtIn;
};
const initializeBuiltInTests = async () => {
- const choices = [
- "lib/**/__tests__/*.test.{ts,tsx}",
- "lib/**/*.test.{ts,tsx}",
- "src/**/__tests__/*.test.{ts,tsx}",
- "src/**/*.test.{ts,tsx}",
- "test/**/*.{ts,tsx}",
- none,
- ];
-
- const { testFiles } = await prompt<{ testFiles: string }>([
- {
- choices,
- initial: choices.length - 1,
- message: "Which glob matches your test files?",
- name: "testFiles",
- type: "select",
- },
- ]);
-
- return testFiles;
+ const choices = [
+ "lib/**/__tests__/*.test.{ts,tsx}",
+ "lib/**/*.test.{ts,tsx}",
+ "src/**/__tests__/*.test.{ts,tsx}",
+ "src/**/*.test.{ts,tsx}",
+ "test/**/*.{ts,tsx}",
+ none,
+ ];
+
+ const { testFiles } = await prompt<{ testFiles: string }>([
+ {
+ choices,
+ initial: choices.length - 1,
+ message: "Which glob matches your test files?",
+ name: "testFiles",
+ type: "select",
+ },
+ ]);
+
+ return testFiles;
};
const getCustomTests = async () => {
- const { testFiles } = await prompt<{ testFiles: string }>([
- {
- initial: "test/**/*.{ts,tsx}",
- message: "Where are your test files?",
- name: "testFiles",
- type: "text",
- },
- ]);
-
- return testFiles;
+ const { testFiles } = await prompt<{ testFiles: string }>([
+ {
+ initial: "test/**/*.{ts,tsx}",
+ message: "Where are your test files?",
+ name: "testFiles",
+ type: "text",
+ },
+ ]);
+
+ return testFiles;
};
diff --git a/src/initialization/initializeTypeScript/writeMultiTypeScriptConfig.ts b/src/initialization/initializeTypeScript/writeMultiTypeScriptConfig.ts
index bc5779415..9350cb3a0 100644
--- a/src/initialization/initializeTypeScript/writeMultiTypeScriptConfig.ts
+++ b/src/initialization/initializeTypeScript/writeMultiTypeScriptConfig.ts
@@ -1,61 +1,71 @@
-import { fs } from "mz";
-import { ProjectDescription } from "../initializeProject/shared";
+import * as fs from "node:fs/promises";
-import { InitializationImprovement } from "./improvements";
+import { ProjectDescription } from "../initializeProject/shared.js";
+import { InitializationImprovement } from "./improvements.js";
export interface MultiTypeScriptConfigSettings {
- fileName: string;
- improvements: ReadonlySet;
- project: ProjectDescription;
- sourceFiles?: string;
- testFiles?: string;
+ fileName: string;
+ improvements: ReadonlySet;
+ project: ProjectDescription;
+ sourceFiles?: string;
+ testFiles?: string;
}
export const writeMultiTypeScriptConfig = async ({
- fileName,
- improvements,
- project,
- sourceFiles,
- testFiles,
+ fileName,
+ improvements,
+ project,
+ sourceFiles,
+ testFiles,
}: MultiTypeScriptConfigSettings) => {
- await fs.writeFile(
- fileName,
- JSON.stringify(
- [
- {
- fixes: {
- ...printImprovements(improvements),
- strictNonNullAssertions: true,
- },
- ...(testFiles && { include: [testFiles] }),
- projectPath: project.filePath,
- types: {
- strictNullChecks: true,
- },
- },
- {
- ...(testFiles && { exclude: [testFiles] }),
- fixes: printImprovements(improvements),
- ...(sourceFiles && { include: [sourceFiles] }),
- projectPath: project.filePath,
- },
- {
- fixes: printImprovements(improvements),
- ...(testFiles ? { include: [testFiles, sourceFiles] } : { include: [sourceFiles] }),
- projectPath: project.filePath,
- },
- ],
- undefined,
- 4,
- ),
- );
+ await fs.writeFile(
+ fileName,
+ JSON.stringify(
+ [
+ {
+ fixes: {
+ ...printImprovements(improvements),
+ strictNonNullAssertions: true,
+ },
+ ...(testFiles && { include: [testFiles] }),
+ projectPath: project.filePath,
+ types: {
+ strictNullChecks: true,
+ },
+ },
+ {
+ ...(testFiles && { exclude: [testFiles] }),
+ fixes: printImprovements(improvements),
+ ...(sourceFiles && { include: [sourceFiles] }),
+ projectPath: project.filePath,
+ },
+ {
+ fixes: printImprovements(improvements),
+ ...(testFiles
+ ? { include: [testFiles, sourceFiles] }
+ : { include: [sourceFiles] }),
+ projectPath: project.filePath,
+ },
+ ],
+ undefined,
+ 4,
+ ),
+ );
};
-const printImprovements = (improvements: ReadonlySet) => {
- return {
- incompleteTypes: true,
- ...(improvements.has(InitializationImprovement.NoImplicitAny) && { noImplicitAny: true }),
- ...(improvements.has(InitializationImprovement.NoInferableTypes) && { inferableTypes: true }),
- ...(improvements.has(InitializationImprovement.NoImplicitThis) && { noImplicitThis: true }),
- };
+const printImprovements = (
+ improvements: ReadonlySet,
+) => {
+ return {
+ incompleteTypes: true,
+ ...(improvements.has(InitializationImprovement.NoImplicitAny) && {
+ noImplicitAny: true,
+ }),
+ ...(improvements.has(InitializationImprovement.NoInferableTypes) && {
+ inferableTypes: true,
+ }),
+ ...(improvements.has(InitializationImprovement.NoImplicitThis) && {
+ noImplicitThis: true,
+ }),
+ };
};
diff --git a/src/initialization/initializeTypeScript/writeSingleTypeScriptConfig.ts b/src/initialization/initializeTypeScript/writeSingleTypeScriptConfig.ts
index 8c011022e..c4a0febb1 100644
--- a/src/initialization/initializeTypeScript/writeSingleTypeScriptConfig.ts
+++ b/src/initialization/initializeTypeScript/writeSingleTypeScriptConfig.ts
@@ -1,34 +1,45 @@
-import { fs } from "mz";
+import * as fs from "node:fs/promises";
-import { ProjectDescription } from "../initializeProject/shared";
-import { InitializationImprovement } from "./improvements";
+import { ProjectDescription } from "../initializeProject/shared.js";
+import { InitializationImprovement } from "./improvements.js";
export interface SingleTypeScriptConfigSettings {
- fileName: string;
- project: ProjectDescription;
- improvements: ReadonlySet;
- sourceFiles?: string;
+ fileName: string;
+ improvements: ReadonlySet;
+ project: ProjectDescription;
+ sourceFiles?: string;
}
-export const writeSingleTypeScriptConfig = async ({ fileName, project, sourceFiles, improvements }: SingleTypeScriptConfigSettings) => {
- await fs.writeFile(
- fileName,
- JSON.stringify(
- {
- fixes: printImprovements(improvements),
- ...(sourceFiles && { include: [sourceFiles] }),
- projectPath: project.filePath,
- },
- undefined,
- 4,
- ),
- );
+export const writeSingleTypeScriptConfig = async ({
+ fileName,
+ improvements,
+ project,
+ sourceFiles,
+}: SingleTypeScriptConfigSettings) => {
+ await fs.writeFile(
+ fileName,
+ JSON.stringify(
+ {
+ fixes: printImprovements(improvements),
+ ...(sourceFiles && { include: [sourceFiles] }),
+ projectPath: project.filePath,
+ },
+ undefined,
+ 4,
+ ),
+ );
};
-const printImprovements = (improvements: ReadonlySet) => {
- return {
- incompleteTypes: true,
- ...(improvements.has(InitializationImprovement.NoImplicitAny) && { noImplicitAny: true }),
- ...(improvements.has(InitializationImprovement.NoImplicitThis) && { noImplicitThis: true }),
- };
+const printImprovements = (
+ improvements: ReadonlySet,
+) => {
+ return {
+ incompleteTypes: true,
+ ...(improvements.has(InitializationImprovement.NoImplicitAny) && {
+ noImplicitAny: true,
+ }),
+ ...(improvements.has(InitializationImprovement.NoImplicitThis) && {
+ noImplicitThis: true,
+ }),
+ };
};
diff --git a/src/initialization/sources/index.ts b/src/initialization/sources/index.ts
index 157deae8d..21cc22b31 100644
--- a/src/initialization/sources/index.ts
+++ b/src/initialization/sources/index.ts
@@ -1,79 +1,91 @@
import { prompt } from "enquirer";
-import { fs } from "mz";
+import * as fs from "node:fs/promises";
-import { ProjectDescription } from "../initializeProject/shared";
+import { ProjectDescription } from "../initializeProject/shared.js";
export interface InitializeSourcesSettings {
- fromJavaScript: boolean;
- project: ProjectDescription;
+ fromJavaScript: boolean;
+ project: ProjectDescription;
}
const everything = "everything";
const other = "other";
-export const initializeSources = async (settings: InitializeSourcesSettings) => {
- const completion = settings.fromJavaScript ? "/**/*.{js,jsx}" : "/**/*.{ts,tsx}";
- const builtIn = await initializeBuiltInSources(completion, settings.project);
+export const initializeSources = async (
+ settings: InitializeSourcesSettings,
+) => {
+ const completion = settings.fromJavaScript
+ ? "/**/*.{js,jsx}"
+ : "/**/*.{ts,tsx}";
+ const builtIn = await initializeBuiltInSources(completion);
- if (builtIn === other) {
- return await getCustomSources(completion);
- }
+ if (builtIn === other) {
+ return await getCustomSources(completion);
+ }
- if (builtIn === everything) {
- return undefined;
- }
+ if (builtIn === everything) {
+ return undefined;
+ }
- if (settings.project.created) {
- await fs.writeFile(
- settings.project.filePath,
- JSON.stringify(
- {
- ...JSON.parse((await fs.readFile(settings.project.filePath)).toString()),
- include: [builtIn.replace(/\*\.\{(j|t)s\,(j|t)sx\}/, "").replace(/\/\*\*\/$/, "")],
- },
- null,
- 4,
- ),
- );
- }
+ if (settings.project.created) {
+ await fs.writeFile(
+ settings.project.filePath,
+ JSON.stringify(
+ {
+ ...JSON.parse(
+ (await fs.readFile(settings.project.filePath)).toString(),
+ ),
+ include: [
+ builtIn
+ .replace(/\*\.\{(?:j|t)s,(?:j|t)sx\}/, "")
+ .replace(/\/\*\*\/$/, ""),
+ ],
+ },
+ null,
+ 4,
+ ),
+ );
+ }
- return builtIn;
+ return builtIn;
};
-const initializeBuiltInSources = async (completion: string, project: ProjectDescription) => {
- // https://github.com/enquirer/enquirer/issues/202
- const choices: string[] = [
- {
- message: "everything in my tsconfig.json",
- name: everything,
- } as any,
- `lib${completion}`,
- `src${completion}`,
- other,
- ];
+const initializeBuiltInSources = async (completion: string) => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const choices: string[] = [
+ {
+ message: "everything in my tsconfig.json",
+ name: everything,
+ // https://github.com/enquirer/enquirer/issues/202
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } as any,
+ `lib${completion}`,
+ `src${completion}`,
+ other,
+ ];
- const { sourceFiles } = await prompt<{ sourceFiles: string }>([
- {
- choices,
- initial: choices.length - 1,
- message: "Which glob matches files you'd like to convert?",
- name: "sourceFiles",
- type: "select",
- },
- ]);
+ const { sourceFiles } = await prompt<{ sourceFiles: string }>([
+ {
+ choices,
+ initial: choices.length - 1,
+ message: "Which glob matches files you'd like to convert?",
+ name: "sourceFiles",
+ type: "select",
+ },
+ ]);
- return sourceFiles;
+ return sourceFiles;
};
const getCustomSources = async (completion: string) => {
- const { sourceFiles } = await prompt<{ sourceFiles: string }>([
- {
- initial: `src${completion}`,
- message: "Which files would you like to convert?",
- name: "sourceFiles",
- type: "text",
- },
- ]);
+ const { sourceFiles } = await prompt<{ sourceFiles: string }>([
+ {
+ initial: `src${completion}`,
+ message: "Which files would you like to convert?",
+ name: "sourceFiles",
+ type: "text",
+ },
+ ]);
- return sourceFiles;
+ return sourceFiles;
};
diff --git a/src/mutations/aliasing/aliases.ts b/src/mutations/aliasing/aliases.ts
index 4f4efc773..b80dbd9de 100644
--- a/src/mutations/aliasing/aliases.ts
+++ b/src/mutations/aliasing/aliases.ts
@@ -1,34 +1,38 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
/**
* Type flags and aliases to check when --strictNullChecks is not enabled.
*/
const nonStrictTypeFlagAliases = new Map([
- [ts.TypeFlags.Boolean, "boolean"],
- [ts.TypeFlags.BooleanLiteral, "boolean"],
- [ts.TypeFlags.Number, "number"],
- [ts.TypeFlags.NumberLiteral, "number"],
- [ts.TypeFlags.String, "string"],
- [ts.TypeFlags.StringLiteral, "string"],
+ [ts.TypeFlags.Boolean, "boolean"],
+ [ts.TypeFlags.BooleanLiteral, "boolean"],
+ [ts.TypeFlags.Number, "number"],
+ [ts.TypeFlags.NumberLiteral, "number"],
+ [ts.TypeFlags.String, "string"],
+ [ts.TypeFlags.StringLiteral, "string"],
]);
/**
* Type flags and aliases to check when --strictNullChecks is enabled.
*/
const strictTypeFlagsWithAliases = new Map([
- ...nonStrictTypeFlagAliases,
- [ts.TypeFlags.Null, "null"],
- [ts.TypeFlags.Undefined, "undefined"],
+ ...nonStrictTypeFlagAliases,
+ [ts.TypeFlags.Null, "null"],
+ [ts.TypeFlags.Undefined, "undefined"],
]);
/**
* @returns Built-in type flags and aliases per overall request strictNullChecks setting.
*/
-export const getApplicableTypeAliases = (request: FileMutationsRequest, alwaysAllowStrictNullCheckAliases = false) =>
- alwaysAllowStrictNullCheckAliases ||
- request.options.types.strictNullChecks ||
- request.services.program.getCompilerOptions().strictNullChecks
- ? strictTypeFlagsWithAliases
- : nonStrictTypeFlagAliases;
+export const getApplicableTypeAliases = (
+ request: FileMutationsRequest,
+ alwaysAllowStrictNullCheckAliases = false,
+) =>
+ alwaysAllowStrictNullCheckAliases ||
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+ request.options.types.strictNullChecks ||
+ request.services.program.getCompilerOptions().strictNullChecks
+ ? strictTypeFlagsWithAliases
+ : nonStrictTypeFlagAliases;
diff --git a/src/mutations/aliasing/joinIntoType.ts b/src/mutations/aliasing/joinIntoType.ts
index 28ae9597a..d9ac0f361 100644
--- a/src/mutations/aliasing/joinIntoType.ts
+++ b/src/mutations/aliasing/joinIntoType.ts
@@ -1,18 +1,22 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { isNotUndefined, uniquify } from "../../shared/arrays";
-import { getApplicableTypeAliases } from "./aliases";
+import { isNotUndefined, uniquify } from "../../shared/arrays.js";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { getApplicableTypeAliases } from "./aliases.js";
-export const joinIntoType = (flags: ReadonlySet, types: ReadonlySet, request: FileMutationsRequest) => {
- const alias = getApplicableTypeAliases(request);
+export const joinIntoType = (
+ flags: ReadonlySet,
+ types: ReadonlySet,
+ request: FileMutationsRequest,
+) => {
+ const alias = getApplicableTypeAliases(request);
- return uniquify(
- ...Array.from(types)
- .map((type) => request.services.printers.type(type))
- .map((type) => (type.includes("=>") ? `(${type})` : type)),
- ...Array.from(flags)
- .map((flag) => alias.get(flag))
- .filter(isNotUndefined),
- ).join(" | ");
+ return uniquify(
+ ...Array.from(types)
+ .map((type) => request.services.printers.type(type))
+ .map((type) => (type.includes("=>") ? `(${type})` : type)),
+ ...Array.from(flags)
+ .map((flag) => alias.get(flag))
+ .filter(isNotUndefined),
+ ).join(" | ");
};
diff --git a/src/mutations/arrays.ts b/src/mutations/arrays.ts
index 80feb4367..bf56807e4 100644
--- a/src/mutations/arrays.ts
+++ b/src/mutations/arrays.ts
@@ -1,5 +1,5 @@
export const constructArrayShorthand = (genericTypeNames: string[]) => {
- const body = genericTypeNames.join(" | ");
+ const body = genericTypeNames.join(" | ");
- return body.includes(" ") ? `(${body})[]` : `${body}[]`;
+ return body.includes(" ") ? `(${body})[]` : `${body}[]`;
};
diff --git a/src/mutations/assignments.ts b/src/mutations/assignments.ts
index 5f975c3d9..df30db585 100644
--- a/src/mutations/assignments.ts
+++ b/src/mutations/assignments.ts
@@ -1,56 +1,64 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../shared/fileMutator";
-import { getTypeAtLocationIfNotError } from "../shared/types";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../shared/types.js";
export interface AssignedTypeValue {
- /**
- * Name of an added child property, if not an entirely new value literal.
- */
- name?: string;
-
- /**
- * Type being added as a property or set as a complete type.
- *
- * @remarks It is strongly preferable to provide this as a Type, so it can be deduplicated later on.
- */
- type: ts.Type | string;
+ /**
+ * Name of an added child property, if not an entirely new value literal.
+ */
+ name?: string | undefined;
+
+ /**
+ * Type being added as a property or set as a complete type.
+ * It is strongly preferable to provide this as a Type, so it can be deduplicated later on.
+ */
+ type: string | ts.Type;
}
/**
* For each new member of a type, a string or type representation of what it is known to be assigned.
*/
-export type AssignedTypesByName = Map;
+export type AssignedTypesByName = Map;
/**
* Joins a set of assigned type values into a single mapping by name.
*/
-export const joinAssignedTypesByName = (request: FileMutationsRequest, assignedTypeValues: readonly AssignedTypeValue[]) => {
- const assignedTypesByName = new Map();
-
- for (const { name, type } of assignedTypeValues) {
- // If the type comes with its own name, it's for a single property
- if (name !== undefined) {
- assignedTypesByName.set(name, type);
- continue;
- }
-
- // Types without names are spread to convey multiple properties
- if (typeof type !== "string") {
- for (const property of type.getProperties()) {
- const declarations = property.getDeclarations();
- const relevantDeclaration = declarations === undefined ? property.valueDeclaration : declarations[0];
- if (relevantDeclaration === undefined) {
- continue;
- }
-
- const propertyType = getTypeAtLocationIfNotError(request, relevantDeclaration);
- if (propertyType !== undefined) {
- assignedTypesByName.set(property.name, propertyType);
- }
- }
- }
- }
-
- return assignedTypesByName;
+export const joinAssignedTypesByName = (
+ request: FileMutationsRequest,
+ assignedTypeValues: readonly AssignedTypeValue[],
+) => {
+ const assignedTypesByName = new Map();
+
+ for (const { name, type } of assignedTypeValues) {
+ // If the type comes with its own name, it's for a single property
+ if (name !== undefined) {
+ assignedTypesByName.set(name, type);
+ continue;
+ }
+
+ // Types without names are spread to convey multiple properties
+ if (typeof type !== "string") {
+ for (const property of type.getProperties()) {
+ const declarations = property.getDeclarations();
+ const relevantDeclaration =
+ declarations === undefined
+ ? property.valueDeclaration
+ : declarations[0];
+ if (relevantDeclaration === undefined) {
+ continue;
+ }
+
+ const propertyType = getTypeAtLocationIfNotError(
+ request,
+ relevantDeclaration,
+ );
+ if (propertyType !== undefined) {
+ assignedTypesByName.set(property.name, propertyType);
+ }
+ }
+ }
+ }
+
+ return assignedTypesByName;
};
diff --git a/src/mutations/codeFixes/addMissingProperty.ts b/src/mutations/codeFixes/addMissingProperty.ts
index a11fabf5e..fe20509de 100644
--- a/src/mutations/codeFixes/addMissingProperty.ts
+++ b/src/mutations/codeFixes/addMissingProperty.ts
@@ -1,48 +1,53 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-
-import { createCodeFixCreationMutation } from "./creation";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { createCodeFixCreationMutation } from "./creation.js";
/**
* Error code for the TypeScript language service to add a missing property.
*/
const fixMissingPropertyErrorCode = 2339;
-export const getMissingPropertyMutations = (request: FileMutationsRequest, node: ts.PropertyAccessExpression): Mutation | undefined => {
- // Skip nodes that aren't setting a member of a `this` node
- if (!nodeIsSettingThisMember(node)) {
- return undefined;
- }
-
- const codeFixes = getMissingPropertyCodeFixes(node, request);
- if (codeFixes.length === 0) {
- return undefined;
- }
-
- return createCodeFixCreationMutation(request, codeFixes);
+export const getMissingPropertyMutations = (
+ request: FileMutationsRequest,
+ node: ts.PropertyAccessExpression,
+): Mutation | undefined => {
+ // Skip nodes that aren't setting a member of a `this` node
+ if (!nodeIsSettingThisMember(node)) {
+ return undefined;
+ }
+
+ const codeFixes = getMissingPropertyCodeFixes(node, request);
+ if (codeFixes.length === 0) {
+ return undefined;
+ }
+
+ return createCodeFixCreationMutation(codeFixes);
};
/**
* @returns Whether a property access is setting a 'this' member.
*/
const nodeIsSettingThisMember = (node: ts.PropertyAccessExpression): boolean =>
- ts.isBinaryExpression(node.parent) &&
- node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
- node.expression.kind === ts.SyntaxKind.ThisKeyword;
+ ts.isBinaryExpression(node.parent) &&
+ node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
+ node.expression.kind === ts.SyntaxKind.ThisKeyword;
/**
* Uses a requesting language service to get missing property code fixes for a type of node.
*/
-const getMissingPropertyCodeFixes = (node: ts.PropertyAccessExpression, request: FileMutationsRequest) =>
- request.services.languageService.getCodeFixesAtPosition(
- request.sourceFile.fileName,
- node.name.getStart(request.sourceFile),
- node.end,
- [fixMissingPropertyErrorCode],
- {
- insertSpaceBeforeAndAfterBinaryOperators: true,
- },
- {},
- );
+const getMissingPropertyCodeFixes = (
+ node: ts.PropertyAccessExpression,
+ request: FileMutationsRequest,
+) =>
+ request.services.languageService.getCodeFixesAtPosition(
+ request.sourceFile.fileName,
+ node.name.getStart(request.sourceFile),
+ node.end,
+ [fixMissingPropertyErrorCode],
+ {
+ insertSpaceBeforeAndAfterBinaryOperators: true,
+ },
+ {},
+ );
diff --git a/src/mutations/codeFixes/creation.ts b/src/mutations/codeFixes/creation.ts
index 9eadbde12..ce1e07d68 100644
--- a/src/mutations/codeFixes/creation.ts
+++ b/src/mutations/codeFixes/creation.ts
@@ -1,55 +1,65 @@
-import { combineMutations, MultipleMutations, TextInsertMutation } from "automutate";
-import * as ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
+import {
+ MultipleMutations,
+ TextInsertMutation,
+ combineMutations,
+} from "automutate";
+import ts from "typescript";
export interface CodeFixCreationPreferences {
- ignoreKnownBlankTypes?: boolean;
+ ignoreKnownBlankTypes?: boolean;
}
-const knownBlankTypes = new Set([": {}", ": any", ": never", ": null", ": Object", ": unknown"]);
+const knownBlankTypes = new Set([
+ ": {}",
+ ": any",
+ ": never",
+ ": null",
+ ": Object",
+ ": unknown",
+]);
/**
* Attempts to convert a language service code fix into a usable mutation.
- *
* @param codeFixes Code fixes from a language service.
* @returns Equivalent mutation, if possible.
*/
export const createCodeFixCreationMutation = (
- request: FileMutationsRequest,
- codeFixes: ReadonlyArray,
- preferences: CodeFixCreationPreferences = {},
+ codeFixes: readonly ts.CodeFixAction[],
+ preferences: CodeFixCreationPreferences = {},
): MultipleMutations | undefined => {
- if (codeFixes.length === 0) {
- return undefined;
- }
+ if (codeFixes.length === 0) {
+ return undefined;
+ }
- const { changes } = codeFixes[0];
- if (changes.length === 0) {
- return undefined;
- }
+ const { changes } = codeFixes[0];
+ if (changes.length === 0) {
+ return undefined;
+ }
- let { textChanges } = changes[0];
+ let { textChanges } = changes[0];
- if (preferences.ignoreKnownBlankTypes) {
- textChanges = textChanges.filter((textChange) => !knownBlankTypes.has(textChange.newText));
- }
+ if (preferences.ignoreKnownBlankTypes) {
+ textChanges = textChanges.filter(
+ (textChange) => !knownBlankTypes.has(textChange.newText),
+ );
+ }
- const simplifiedTextChanges = simplifyTextChanges(textChanges);
- if (simplifiedTextChanges === undefined) {
- return undefined;
- }
+ const simplifiedTextChanges = simplifyTextChanges(textChanges);
+ if (simplifiedTextChanges === undefined) {
+ return undefined;
+ }
- return combineMutations(
- ...simplifiedTextChanges.map(
- (textChange): TextInsertMutation => ({
- insertion: textChange.newText,
- range: {
- begin: textChange.span.start,
- },
- type: "text-insert",
- }),
- ),
- );
+ return combineMutations(
+ ...simplifiedTextChanges.map(
+ (textChange): TextInsertMutation => ({
+ insertion: textChange.newText,
+ range: {
+ begin: textChange.span.start,
+ },
+ type: "text-insert",
+ }),
+ ),
+ );
};
/**
@@ -58,31 +68,33 @@ export const createCodeFixCreationMutation = (
* @see https://github.com/JoshuaKGoldberg/TypeStat/issues/256
*/
const simplifyTextChanges = (textChanges: readonly ts.TextChange[]) => {
- if (textChanges.length === 0 || isOnlyParenthesis(textChanges)) {
- return undefined;
- }
+ if (textChanges.length === 0 || isOnlyParenthesis(textChanges)) {
+ return undefined;
+ }
- return textChanges.slice(1).reduce(
- (previousValues, textChange) => {
- const previousValue = previousValues[previousValues.length - 1];
+ return textChanges.slice(1).reduce(
+ (previousValues, textChange) => {
+ const previousValue = previousValues[previousValues.length - 1];
- // If the span starts aren't the same, there's nothing we can simplify
- if (previousValue.span.start !== textChange.span.start) {
- return [...previousValues, textChange];
- }
+ // If the span starts aren't the same, there's nothing we can simplify
+ if (previousValue.span.start !== textChange.span.start) {
+ return [...previousValues, textChange];
+ }
- // Since two text changes in a row have the same start, rejoice!
- // We can combine them into a single value and lessen the array size
- previousValues[previousValues.length - 1] = {
- ...previousValue,
- newText: `${previousValue.newText}${textChange.newText}`,
- };
+ // Since two text changes in a row have the same start, rejoice!
+ // We can combine them into a single value and lessen the array size
+ previousValues[previousValues.length - 1] = {
+ ...previousValue,
+ newText: `${previousValue.newText}${textChange.newText}`,
+ };
- return previousValues;
- },
- [textChanges[0]],
- );
+ return previousValues;
+ },
+ [textChanges[0]],
+ );
};
const isOnlyParenthesis = (textChanges: readonly ts.TextChange[]) =>
- textChanges.length === 2 && textChanges[0].newText === "(" && textChanges[1].newText === ")";
+ textChanges.length === 2 &&
+ textChanges[0].newText === "(" &&
+ textChanges[1].newText === ")";
diff --git a/src/mutations/codeFixes/getCodeFixIfMatchedByDiagnostic.ts b/src/mutations/codeFixes/getCodeFixIfMatchedByDiagnostic.ts
index 8814d5328..b5852aab5 100644
--- a/src/mutations/codeFixes/getCodeFixIfMatchedByDiagnostic.ts
+++ b/src/mutations/codeFixes/getCodeFixIfMatchedByDiagnostic.ts
@@ -1,37 +1,43 @@
-import * as ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
+import ts from "typescript";
+
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
/**
* Uses a requesting language service to get code fixes for a type of node.
- *
* @param request Source file, metadata, and settings to collect mutations in the file.
* @param node Requesting node to retrieve fixes on.
- * @param errorCode Diagnostic code to retrieve matched fixes for.
- * @remarks
+ * @param errorCodes Diagnostic code to retrieve matched fixes for.
* TypeScript's `getCodeFixesAtPosition` API doesn't check whether the diagnostic actually is being
* emitted for the node. So we must.
*/
-export const getCodeFixIfMatchedByDiagnostic = (request: FileMutationsRequest, node: ts.Node, errorCodes: number[]) => {
- const semanticDiagnostics = request.services.languageService.getSemanticDiagnostics(request.sourceFile.fileName);
- if (
- !semanticDiagnostics.some(
- (diagnostic) =>
- errorCodes.includes(diagnostic.code) &&
- diagnostic.start &&
- diagnostic.length &&
- diagnostic.start >= node.pos &&
- diagnostic.start + diagnostic.length <= node.end,
- )
- ) {
- return undefined;
- }
+export const getCodeFixIfMatchedByDiagnostic = (
+ request: FileMutationsRequest,
+ node: ts.Node,
+ errorCodes: number[],
+) => {
+ const semanticDiagnostics =
+ request.services.languageService.getSemanticDiagnostics(
+ request.sourceFile.fileName,
+ );
+ if (
+ !semanticDiagnostics.some(
+ (diagnostic) =>
+ errorCodes.includes(diagnostic.code) &&
+ diagnostic.start &&
+ diagnostic.length &&
+ diagnostic.start >= node.pos &&
+ diagnostic.start + diagnostic.length <= node.end,
+ )
+ ) {
+ return undefined;
+ }
- return request.services.languageService.getCodeFixesAtPosition(
- request.sourceFile.fileName,
- node.getStart(request.sourceFile),
- node.end,
- errorCodes,
- { insertSpaceBeforeAndAfterBinaryOperators: true },
- {},
- );
+ return request.services.languageService.getCodeFixesAtPosition(
+ request.sourceFile.fileName,
+ node.getStart(request.sourceFile),
+ node.end,
+ errorCodes,
+ { insertSpaceBeforeAndAfterBinaryOperators: true },
+ {},
+ );
};
diff --git a/src/mutations/codeFixes/noImplicitAny.ts b/src/mutations/codeFixes/noImplicitAny.ts
index 129fe82c4..6847561de 100644
--- a/src/mutations/codeFixes/noImplicitAny.ts
+++ b/src/mutations/codeFixes/noImplicitAny.ts
@@ -1,57 +1,69 @@
import { Mutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { getTypeAtLocationIfNotError } from "../../shared/types";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../shared/types.js";
+import { createCodeFixCreationMutation } from "./creation.js";
+import { getCodeFixIfMatchedByDiagnostic } from "./getCodeFixIfMatchedByDiagnostic.js";
-import { createCodeFixCreationMutation } from "./creation";
-import { getCodeFixIfMatchedByDiagnostic } from "./getCodeFixIfMatchedByDiagnostic";
+export type NoImplicitAnyNode =
+ | ts.ParameterDeclaration
+ | ts.PropertyDeclaration
+ | ts.VariableDeclaration;
-export type NoImplicitAnyNode = ts.ParameterDeclaration | ts.PropertyDeclaration | ts.VariableDeclaration;
-
-export type NoImplictAnyNodeToBeFixed = NoImplicitAnyNode & {
- initializer: undefined;
- type: undefined;
+export type NoImplicitAnyNodeToBeFixed = NoImplicitAnyNode & {
+ initializer: undefined;
+ type: undefined;
};
/**
* Error codes for the TypeScript language service to get --noImplicitAny code fixes.
*/
enum NoImplicitAnyErrorCode {
- Parameter = 7006,
- PropertyOrVariable = 7005,
+ Parameter = 7006,
+ PropertyOrVariable = 7005,
}
-export const canNodeBeFixedForNoImplicitAny = (node: NoImplicitAnyNode): node is NoImplictAnyNodeToBeFixed =>
- node.type === undefined &&
- node.initializer === undefined &&
- // TypeScript still provides --noImplicitAny fixes for variables that can't receive them
- // @see https://github.com/JoshuaKGoldberg/TypeStat/issues/77
- !ts.isCatchClause(node.parent) &&
- // TypeScript provides all parameters' --noImplicitAny fixes when asked for any parameter, so only request on the first
- (!ts.isParameter(node) || node === node.parent.parameters[0]);
-
-export const getNoImplicitAnyMutations = (node: NoImplictAnyNodeToBeFixed, request: FileMutationsRequest): Mutation | undefined => {
- // If the node is a parameter, make sure it doesn't already have an inferable type
- // (TypeScript will still suggest a codefix to make a redundant inferred type)
- if (ts.isParameter(node)) {
- const nodeType = getTypeAtLocationIfNotError(request, node);
- if (nodeType === undefined || !tsutils.isTypeFlagSet(nodeType, ts.TypeFlags.Any)) {
- return undefined;
- }
- }
-
- // Retrieve code fix suggestions for --noImplicitAny from the requesting language service
- const codeFixes = getCodeFixIfMatchedByDiagnostic(request, node, [
- ts.isParameter(node) ? NoImplicitAnyErrorCode.Parameter : NoImplicitAnyErrorCode.PropertyOrVariable,
- ]);
- if (!codeFixes?.length) {
- return undefined;
- }
-
- // Convert those code fix suggestions to our own mutations format
- return createCodeFixCreationMutation(request, codeFixes, {
- ignoreKnownBlankTypes: true,
- });
+export const canNodeBeFixedForNoImplicitAny = (
+ node: NoImplicitAnyNode,
+): node is NoImplicitAnyNodeToBeFixed =>
+ node.type === undefined &&
+ node.initializer === undefined &&
+ // TypeScript still provides --noImplicitAny fixes for variables that can't receive them
+ // @see https://github.com/JoshuaKGoldberg/TypeStat/issues/77
+ !ts.isCatchClause(node.parent) &&
+ // TypeScript provides all parameters' --noImplicitAny fixes when asked for any parameter, so only request on the first
+ (!ts.isParameter(node) || node === node.parent.parameters[0]);
+
+export const getNoImplicitAnyMutations = (
+ node: NoImplicitAnyNodeToBeFixed,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // If the node is a parameter, make sure it doesn't already have an inferable type
+ // (TypeScript will still suggest a codefix to make a redundant inferred type)
+ if (ts.isParameter(node)) {
+ const nodeType = getTypeAtLocationIfNotError(request, node);
+ if (
+ nodeType === undefined ||
+ !tsutils.isTypeFlagSet(nodeType, ts.TypeFlags.Any)
+ ) {
+ return undefined;
+ }
+ }
+
+ // Retrieve code fix suggestions for --noImplicitAny from the requesting language service
+ const codeFixes = getCodeFixIfMatchedByDiagnostic(request, node, [
+ ts.isParameter(node)
+ ? NoImplicitAnyErrorCode.Parameter
+ : NoImplicitAnyErrorCode.PropertyOrVariable,
+ ]);
+ if (!codeFixes?.length) {
+ return undefined;
+ }
+
+ // Convert those code fix suggestions to our own mutations format
+ return createCodeFixCreationMutation(codeFixes, {
+ ignoreKnownBlankTypes: true,
+ });
};
diff --git a/src/mutations/codeFixes/noImplicitThis.ts b/src/mutations/codeFixes/noImplicitThis.ts
index c0d6042af..803d071df 100644
--- a/src/mutations/codeFixes/noImplicitThis.ts
+++ b/src/mutations/codeFixes/noImplicitThis.ts
@@ -1,19 +1,27 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-
-import { createCodeFixCreationMutation } from "./creation";
-import { getCodeFixIfMatchedByDiagnostic } from "./getCodeFixIfMatchedByDiagnostic";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { createCodeFixCreationMutation } from "./creation.js";
+import { getCodeFixIfMatchedByDiagnostic } from "./getCodeFixIfMatchedByDiagnostic.js";
/**
* Error code for the TypeScript language service to get --noImplicitThis code fixes.
*/
const noImplicitThisErrorCodes = [2683];
-export const getNoImplicitThisMutations = (node: ts.ThisExpression, request: FileMutationsRequest): Mutation | undefined => {
- // Create a mutation for the code fixes if anything is available
- const codeFixes = getCodeFixIfMatchedByDiagnostic(request, node, noImplicitThisErrorCodes);
+export const getNoImplicitThisMutations = (
+ node: ts.ThisExpression,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Create a mutation for the code fixes if anything is available
+ const codeFixes = getCodeFixIfMatchedByDiagnostic(
+ request,
+ node,
+ noImplicitThisErrorCodes,
+ );
- return !codeFixes?.length ? undefined : createCodeFixCreationMutation(request, codeFixes);
+ return !codeFixes?.length
+ ? undefined
+ : createCodeFixCreationMutation(codeFixes);
};
diff --git a/src/mutations/collecting.ts b/src/mutations/collecting.ts
index 372369f63..49e5d584c 100644
--- a/src/mutations/collecting.ts
+++ b/src/mutations/collecting.ts
@@ -1,154 +1,175 @@
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../shared/fileMutator";
-import { isKnownGlobalBaseType } from "../shared/nodeTypes";
-import { setSubtract } from "../shared/sets";
-
-import { getApplicableTypeAliases } from "./aliasing/aliases";
-import { findMissingFlags, isTypeFlagSetRecursively } from "./collecting/flags";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
+import { isKnownGlobalBaseType } from "../shared/nodeTypes.js";
+import { setSubtract } from "../shared/sets.js";
+import { getApplicableTypeAliases } from "./aliasing/aliases.js";
+import {
+ findMissingFlags,
+ isTypeFlagSetRecursively,
+} from "./collecting/flags.js";
/**
* Collects assigned and missing flags and types, recursively accounting for type unions.
- *
* @param request Metadata and settings to collect mutations in a file.
* @param declaredType Original type declared on a node.
* @param allAssignedTypes All types immediately or later assigned to the node.
*/
export const collectUsageFlagsAndSymbols = (
- request: FileMutationsRequest,
- declaredType: ts.Type,
- allAssignedTypes: readonly ts.Type[],
+ request: FileMutationsRequest,
+ declaredType: ts.Type,
+ allAssignedTypes: readonly ts.Type[],
) => {
- // Collect which flags are later assigned to the type
- const [assignedFlags, assignedTypes] = collectFlagsAndTypesFromTypes(request, allAssignedTypes);
-
- // If the declared type is the general 'any', then we assume all are missing
- // Similarly, if it's a plain Function or Object, we'll want to replace its contents
- if (declaredType.flags & ts.TypeFlags.Any || isKnownGlobalBaseType(declaredType)) {
- return {
- assignedFlags,
- assignedTypes,
- missingFlags: assignedFlags,
- missingTypes: assignedTypes,
- };
- }
-
- // Otherwise, collect which flags and types are declared (as a type annotation)...
- const [declaredFlags, declaredTypes] = collectFlagsAndTypesFromTypes(request, [declaredType]);
-
- // Subtract the above to find any flags or types assigned but not declared
- return {
- assignedFlags,
- assignedTypes,
- missingFlags: findMissingFlags(declaredType, assignedFlags, declaredFlags),
- missingTypes: findMissingTypes(request, assignedTypes, declaredTypes),
- };
+ // Collect which flags are later assigned to the type
+ const [assignedFlags, assignedTypes] = collectFlagsAndTypesFromTypes(
+ request,
+ allAssignedTypes,
+ );
+
+ // If the declared type is the general 'any', then we assume all are missing
+ // Similarly, if it's a plain Function or Object, we'll want to replace its contents
+ if (
+ declaredType.flags & ts.TypeFlags.Any ||
+ isKnownGlobalBaseType(declaredType)
+ ) {
+ return {
+ assignedFlags,
+ assignedTypes,
+ missingFlags: assignedFlags,
+ missingTypes: assignedTypes,
+ };
+ }
+
+ // Otherwise, collect which flags and types are declared (as a type annotation)...
+ const [declaredFlags, declaredTypes] = collectFlagsAndTypesFromTypes(
+ request,
+ [declaredType],
+ );
+
+ // Subtract the above to find any flags or types assigned but not declared
+ return {
+ assignedFlags,
+ assignedTypes,
+ missingFlags: findMissingFlags(declaredType, assignedFlags, declaredFlags),
+ missingTypes: findMissingTypes(request, assignedTypes, declaredTypes),
+ };
};
/**
* Separates raw type node(s) into their contained flags and types.
- *
- * @param options Source file, metadata, and settings to collect mutations in the file.
+ * @param request Metadata and settings to collect mutations in a file.
* @param allTypes Any number of raw type nodes.
* @param allowStrictNullCheckAliases Whether to allow `null` and `undefined` aliases regardless of compiler strictness.
* @returns Flags and types found within the raw type nodes.
*/
export const collectFlagsAndTypesFromTypes = (
- request: FileMutationsRequest,
- allTypes: readonly ts.Type[],
- allowStrictNullCheckAliases?: boolean,
+ request: FileMutationsRequest,
+ allTypes: readonly ts.Type[],
+ allowStrictNullCheckAliases?: boolean,
): [Set, Set] => {
- const foundFlags = new Set();
- const foundTypes = new Set();
- const applicableTypeAliases = getApplicableTypeAliases(request, allowStrictNullCheckAliases);
-
- // Scan each type for undeclared type additions
- for (const type of allTypes) {
- // For any simple type flag we later will care about for aliasing, add it if it's in the type
- for (const [typeFlag] of applicableTypeAliases) {
- if (isTypeFlagSetRecursively(type, typeFlag)) {
- foundFlags.add(typeFlag);
- }
- }
-
- // If the type is a rich type (has a symbol), add it in directly
- if (type.getSymbol() !== undefined) {
- foundTypes.add(type);
- continue;
- }
-
- // If the type is a union, add any flags or types found within it
- if (tsutils.isUnionType(type)) {
- const subTypes = recursivelyCollectSubTypes(type);
- const [subFlags, deepSubTypes] = collectFlagsAndTypesFromTypes(request, subTypes);
-
- for (const subFlag of subFlags) {
- foundFlags.add(subFlag);
- }
-
- for (const deepSubType of deepSubTypes) {
- foundTypes.add(deepSubType);
- }
- }
- }
-
- return [foundFlags, foundTypes];
+ const foundFlags = new Set();
+ const foundTypes = new Set();
+ const applicableTypeAliases = getApplicableTypeAliases(
+ request,
+ allowStrictNullCheckAliases,
+ );
+
+ // Scan each type for undeclared type additions
+ for (const type of allTypes) {
+ // For any simple type flag we later will care about for aliasing, add it if it's in the type
+ for (const [typeFlag] of applicableTypeAliases) {
+ if (isTypeFlagSetRecursively(type, typeFlag)) {
+ foundFlags.add(typeFlag);
+ }
+ }
+
+ // If the type is a rich type (has a symbol), add it in directly
+ if (type.getSymbol() !== undefined) {
+ foundTypes.add(type);
+ continue;
+ }
+
+ // If the type is a union, add any flags or types found within it
+ if (tsutils.isUnionType(type)) {
+ const subTypes = recursivelyCollectSubTypes(type);
+ const [subFlags, deepSubTypes] = collectFlagsAndTypesFromTypes(
+ request,
+ subTypes,
+ );
+
+ for (const subFlag of subFlags) {
+ foundFlags.add(subFlag);
+ }
+
+ for (const deepSubType of deepSubTypes) {
+ foundTypes.add(deepSubType);
+ }
+ }
+ }
+
+ return [foundFlags, foundTypes];
};
export const recursivelyCollectSubTypes = (type: ts.UnionType): ts.Type[] => {
- const subTypes: ts.Type[] = [];
+ const subTypes: ts.Type[] = [];
- for (const subType of type.types) {
- if (tsutils.isUnionType(subType)) {
- subTypes.push(...recursivelyCollectSubTypes(subType));
- } else {
- subTypes.push(subType);
- }
- }
+ for (const subType of type.types) {
+ if (tsutils.isUnionType(subType)) {
+ subTypes.push(...recursivelyCollectSubTypes(subType));
+ } else {
+ subTypes.push(subType);
+ }
+ }
- return subTypes;
+ return subTypes;
};
const findMissingTypes = (
- request: FileMutationsRequest,
- assignedTypes: ReadonlySet,
- declaredTypes: ReadonlySet,
+ request: FileMutationsRequest,
+ assignedTypes: ReadonlySet,
+ declaredTypes: ReadonlySet,
): ReadonlySet => {
- // If anything is of type `any`, then bail out immediately: we have no idea what's missing
- for (const type of [...assignedTypes, ...declaredTypes]) {
- if (isTypeFlagSetRecursively(type, ts.TypeFlags.Any)) {
- return new Set();
- }
- }
-
- const declaredTypesContainFunction = Array.from(declaredTypes).some(typeContainsFunction);
- const remainingMissingTypes = new Set(assignedTypes);
-
- const isAssignedTypeMissingFromDeclared = (assignedType: ts.Type) => {
- // We ignore assigned function types when the declared type(s) include function(s).
- // These non-assigned function types are more likely what users would consider bugs.
- // For example, covariant functions might not be assignable, but should be fixed manually.
- if (declaredTypesContainFunction && typeContainsFunction(assignedType)) {
- return false;
- }
-
- for (const potentialParentType of declaredTypes) {
- if (request.services.program.getTypeChecker().isTypeAssignableTo(assignedType, potentialParentType)) {
- return false;
- }
- }
-
- return true;
- };
-
- for (const assignedType of assignedTypes) {
- if (!isAssignedTypeMissingFromDeclared(assignedType)) {
- remainingMissingTypes.delete(assignedType);
- }
- }
-
- return setSubtract(remainingMissingTypes, declaredTypes);
+ // If anything is of type `any`, then bail out immediately: we have no idea what's missing
+ for (const type of [...assignedTypes, ...declaredTypes]) {
+ if (isTypeFlagSetRecursively(type, ts.TypeFlags.Any)) {
+ return new Set();
+ }
+ }
+
+ const declaredTypesContainFunction =
+ Array.from(declaredTypes).some(typeContainsFunction);
+ const remainingMissingTypes = new Set(assignedTypes);
+
+ const isAssignedTypeMissingFromDeclared = (assignedType: ts.Type) => {
+ // We ignore assigned function types when the declared type(s) include function(s).
+ // These non-assigned function types are more likely what users would consider bugs.
+ // For example, covariant functions might not be assignable, but should be fixed manually.
+ if (declaredTypesContainFunction && typeContainsFunction(assignedType)) {
+ return false;
+ }
+
+ for (const potentialParentType of declaredTypes) {
+ if (
+ request.services.program
+ .getTypeChecker()
+ .isTypeAssignableTo(assignedType, potentialParentType)
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ for (const assignedType of assignedTypes) {
+ if (!isAssignedTypeMissingFromDeclared(assignedType)) {
+ remainingMissingTypes.delete(assignedType);
+ }
+ }
+
+ return setSubtract(remainingMissingTypes, declaredTypes);
};
-const typeContainsFunction = (type: ts.Type) => type.getCallSignatures().length !== 0;
+const typeContainsFunction = (type: ts.Type) =>
+ type.getCallSignatures().length !== 0;
diff --git a/src/mutations/collecting/flags.ts b/src/mutations/collecting/flags.ts
index 506f5a5db..6b233bc4f 100644
--- a/src/mutations/collecting/flags.ts
+++ b/src/mutations/collecting/flags.ts
@@ -1,62 +1,67 @@
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { setSubtract } from "../../shared/sets";
+import { setSubtract } from "../../shared/sets.js";
const knownTypeFlagEquivalents = new Map([
- [ts.TypeFlags.BigInt, ts.TypeFlags.BigIntLiteral],
- [ts.TypeFlags.BigIntLiteral, ts.TypeFlags.BigInt],
- [ts.TypeFlags.Number, ts.TypeFlags.NumberLiteral],
- [ts.TypeFlags.NumberLiteral, ts.TypeFlags.Number],
- [ts.TypeFlags.String, ts.TypeFlags.StringLiteral],
- [ts.TypeFlags.StringLiteral, ts.TypeFlags.String],
- [ts.TypeFlags.Undefined, ts.TypeFlags.Void],
- [ts.TypeFlags.Void, ts.TypeFlags.Undefined],
+ [ts.TypeFlags.BigInt, ts.TypeFlags.BigIntLiteral],
+ [ts.TypeFlags.BigIntLiteral, ts.TypeFlags.BigInt],
+ [ts.TypeFlags.Number, ts.TypeFlags.NumberLiteral],
+ [ts.TypeFlags.NumberLiteral, ts.TypeFlags.Number],
+ [ts.TypeFlags.String, ts.TypeFlags.StringLiteral],
+ [ts.TypeFlags.StringLiteral, ts.TypeFlags.String],
+ [ts.TypeFlags.Undefined, ts.TypeFlags.Void],
+ [ts.TypeFlags.Void, ts.TypeFlags.Undefined],
]);
export const findMissingFlags = (
- declaredType: ts.Type,
- assignedFlags: ReadonlySet,
- declaredFlags: ReadonlySet,
+ declaredType: ts.Type,
+ assignedFlags: ReadonlySet,
+ declaredFlags: ReadonlySet,
): Set => {
- // If the type is declared to allow `any`, it can't be missing anything
- if (isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Any)) {
- return new Set();
- }
-
- // Otherwise, it's all the flags assigned to it that weren't already declared
- const missingFlags = setSubtract(assignedFlags, declaredFlags);
-
- // Remove any flags that are just equivalents of the existing ones
- // For example, initial presense of `void` makes `undefined` unnecessary, and vice versa
- for (const [original, equivalent] of knownTypeFlagEquivalents) {
- if (missingFlags.has(equivalent) && isTypeFlagSetRecursively(declaredType, original)) {
- missingFlags.delete(equivalent);
- }
- }
-
- return missingFlags;
+ // If the type is declared to allow `any`, it can't be missing anything
+ if (isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Any)) {
+ return new Set();
+ }
+
+ // Otherwise, it's all the flags assigned to it that weren't already declared
+ const missingFlags = setSubtract(assignedFlags, declaredFlags);
+
+ // Remove any flags that are just equivalents of the existing ones
+ // For example, initial presence of `void` makes `undefined` unnecessary, and vice versa
+ for (const [original, equivalent] of knownTypeFlagEquivalents) {
+ if (
+ missingFlags.has(equivalent) &&
+ isTypeFlagSetRecursively(declaredType, original)
+ ) {
+ missingFlags.delete(equivalent);
+ }
+ }
+
+ return missingFlags;
};
/**
* Checks if a type contains a type flag, accounting for deep nested type unions.
- *
* @param parentType Parent type to check for the type flag.
* @param typeFlag Type flag to check within the parent type.
* @returns Whether the parent type contains the type flag.
*/
-export const isTypeFlagSetRecursively = (parentType: ts.Type, typeFlag: ts.TypeFlags): boolean => {
- if (tsutils.isTypeFlagSet(parentType, typeFlag)) {
- return true;
- }
-
- if (tsutils.isUnionOrIntersectionType(parentType)) {
- for (const childType of parentType.types) {
- if (isTypeFlagSetRecursively(childType, typeFlag)) {
- return true;
- }
- }
- }
-
- return false;
+export const isTypeFlagSetRecursively = (
+ parentType: ts.Type,
+ typeFlag: ts.TypeFlags,
+): boolean => {
+ if (tsutils.isTypeFlagSet(parentType, typeFlag)) {
+ return true;
+ }
+
+ if (tsutils.isUnionOrIntersectionType(parentType)) {
+ for (const childType of parentType.types) {
+ if (isTypeFlagSetRecursively(childType, typeFlag)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
};
diff --git a/src/mutations/creations/creationMutations.ts b/src/mutations/creations/creationMutations.ts
index 01356fca4..e7505207c 100644
--- a/src/mutations/creations/creationMutations.ts
+++ b/src/mutations/creations/creationMutations.ts
@@ -1,18 +1,22 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { printNewLine } from "../../shared/printing/newlines";
-import { printNamedTypeSummaries } from "../../shared/printing/nodePrinting";
-import { TypeSummariesByName } from "../expansions/summarization";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { printNewLine } from "../../shared/printing/newlines.js";
+import { printNamedTypeSummaries } from "../../shared/printing/nodePrinting.js";
+import { TypeSummariesByName } from "../expansions/summarization.js";
export const createDeclarationForTypeSummaries = (
- request: FileMutationsRequest,
- enclosingDeclaration: ts.Node | undefined,
- name: string,
- typeSummaries: TypeSummariesByName,
+ request: FileMutationsRequest,
+ enclosingDeclaration: ts.Node | undefined,
+ name: string,
+ typeSummaries: TypeSummariesByName,
) => {
- const printedSummaries = printNamedTypeSummaries(request, enclosingDeclaration, typeSummaries);
- const newLine = printNewLine(request.options.compilerOptions);
+ const printedSummaries = printNamedTypeSummaries(
+ request,
+ enclosingDeclaration,
+ typeSummaries,
+ );
+ const newLine = printNewLine(request.options.compilerOptions);
- return [`type ${name} = {`, newLine, printedSummaries, `};`].join("");
+ return [`type ${name} = {`, newLine, printedSummaries, `};`].join("");
};
diff --git a/src/mutations/creators.ts b/src/mutations/creators.ts
index 3e1362360..7fdc7a412 100644
--- a/src/mutations/creators.ts
+++ b/src/mutations/creators.ts
@@ -1,16 +1,18 @@
import { TextInsertMutation, TextSwapMutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../shared/fileMutator";
-import { isKnownGlobalBaseType, NodeWithAddableType, NodeWithCreatableType } from "../shared/nodeTypes";
-
-import { joinIntoType } from "./aliasing/joinIntoType";
-import { collectUsageFlagsAndSymbols } from "./collecting";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
+import {
+ NodeWithAddableType,
+ NodeWithCreatableType,
+ isKnownGlobalBaseType,
+} from "../shared/nodeTypes.js";
+import { joinIntoType } from "./aliasing/joinIntoType.js";
+import { collectUsageFlagsAndSymbols } from "./collecting.js";
/**
* Creates a mutation to add types to an existing type, if any are new.
- *
* @param request Source file, metadata, and settings to collect mutations in the file.
* @param node Original node with a type declaration to add to.
* @param declaredType Declared type from the node.
@@ -18,52 +20,61 @@ import { collectUsageFlagsAndSymbols } from "./collecting";
* @returns Mutation to add any new assigned types, if any are missing from the declared type.
*/
export const createTypeAdditionMutation = (
- request: FileMutationsRequest,
- node: NodeWithAddableType,
- declaredType: ts.Type,
- allAssignedTypes: readonly ts.Type[],
+ request: FileMutationsRequest,
+ node: NodeWithAddableType,
+ declaredType: ts.Type,
+ allAssignedTypes: readonly ts.Type[],
): TextInsertMutation | TextSwapMutation | undefined => {
- // Declared 'any' types inherently can't be incomplete
- if (tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)) {
- return undefined;
- }
+ // Declared 'any' types inherently can't be incomplete
+ if (tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)) {
+ return undefined;
+ }
- // Find any missing flags and symbols (a.k.a. types)
- const { missingFlags, missingTypes } = collectUsageFlagsAndSymbols(request, declaredType, allAssignedTypes);
+ // Find any missing flags and symbols (a.k.a. types)
+ const { missingFlags, missingTypes } = collectUsageFlagsAndSymbols(
+ request,
+ declaredType,
+ allAssignedTypes,
+ );
- // If nothing is missing, rejoice! The type was already fine.
- if (missingFlags.size === 0 && missingTypes.size === 0) {
- return undefined;
- }
+ // If nothing is missing, rejoice! The type was already fine.
+ if (missingFlags.size === 0 && missingTypes.size === 0) {
+ return undefined;
+ }
- // Join the missing types into a type string to declare
- const newTypeAlias = joinIntoType(missingFlags, missingTypes, request);
+ // Join the missing types into a type string to declare
+ const newTypeAlias = joinIntoType(missingFlags, missingTypes, request);
- // If the original type was a bottom type or just something like Function or Object, replace it entirely
- if (tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Never | ts.TypeFlags.Unknown) || isKnownGlobalBaseType(declaredType)) {
- return {
- insertion: ` ${newTypeAlias}`,
- range: {
- begin: node.type.pos,
- end: node.type.end,
- },
- type: "text-swap",
- };
- }
+ // If the original type was a bottom type or just something like Function or Object, replace it entirely
+ if (
+ tsutils.isTypeFlagSet(
+ declaredType,
+ ts.TypeFlags.Never | ts.TypeFlags.Unknown,
+ ) ||
+ isKnownGlobalBaseType(declaredType)
+ ) {
+ return {
+ insertion: ` ${newTypeAlias}`,
+ range: {
+ begin: node.type.pos,
+ end: node.type.end,
+ },
+ type: "text-swap",
+ };
+ }
- // Create a mutation insertion that adds the missing types in
- return {
- insertion: ` | ${newTypeAlias}`,
- range: {
- begin: node.type.end,
- },
- type: "text-insert",
- };
+ // Create a mutation insertion that adds the missing types in
+ return {
+ insertion: ` | ${newTypeAlias}`,
+ range: {
+ begin: node.type.end,
+ },
+ type: "text-insert",
+ };
};
/**
* Creates a mutation to add types to a node without a type, if any are new.
- *
* @param request Metadata and settings to collect mutations in a file.
* @param node Node to add the type annotation.
* @param declaredType Declared type from the node.
@@ -71,32 +82,29 @@ export const createTypeAdditionMutation = (
* @returns Mutation to add any new assigned types, if any are missing from the declared type.
*/
export const createTypeCreationMutation = (
- request: FileMutationsRequest,
- node: NodeWithCreatableType,
- declaredType: ts.Type,
- allAssignedTypes: readonly ts.Type[],
+ request: FileMutationsRequest,
+ node: NodeWithCreatableType,
+ declaredType: ts.Type,
+ allAssignedTypes: readonly ts.Type[],
): TextInsertMutation | undefined => {
- // Find the already assigned flags and symbols, as well as any missing ones
- const { assignedFlags, assignedTypes, missingFlags, missingTypes } = collectUsageFlagsAndSymbols(
- request,
- declaredType,
- allAssignedTypes,
- );
+ // Find the already assigned flags and symbols, as well as any missing ones
+ const { assignedFlags, assignedTypes, missingFlags, missingTypes } =
+ collectUsageFlagsAndSymbols(request, declaredType, allAssignedTypes);
- // If nothing is missing, rejoice! The type was already fine.
- if (missingFlags.size === 0 && missingTypes.size === 0) {
- return undefined;
- }
+ // If nothing is missing, rejoice! The type was already fine.
+ if (missingFlags.size === 0 && missingTypes.size === 0) {
+ return undefined;
+ }
- // Join the missing types into a type string to declare
- const newTypeAlias = joinIntoType(assignedFlags, assignedTypes, request);
+ // Join the missing types into a type string to declare
+ const newTypeAlias = joinIntoType(assignedFlags, assignedTypes, request);
- // Create a mutation insertion that adds the assigned types in
- return {
- insertion: `: ${newTypeAlias}`,
- range: {
- begin: node.name.end,
- },
- type: "text-insert",
- };
+ // Create a mutation insertion that adds the assigned types in
+ return {
+ insertion: `: ${newTypeAlias}`,
+ range: {
+ begin: node.name.end,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutations/expansions/addIncompleteTypesToType.ts b/src/mutations/expansions/addIncompleteTypesToType.ts
index 41d5bd6f6..55f050e2a 100644
--- a/src/mutations/expansions/addIncompleteTypesToType.ts
+++ b/src/mutations/expansions/addIncompleteTypesToType.ts
@@ -1,104 +1,115 @@
-import { combineMutations, MultipleMutations, Mutation, TextInsertMutation, TextSwapMutation } from "automutate";
-import * as ts from "typescript";
+import {
+ MultipleMutations,
+ Mutation,
+ TextInsertMutation,
+ TextSwapMutation,
+ combineMutations,
+} from "automutate";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { isKnownGlobalBaseType, isNeverAndOrUnknownType, PropertySignatureWithType } from "../../shared/nodeTypes";
-
-import { TypeSummary } from "./summarization";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import {
+ PropertySignatureWithType,
+ isKnownGlobalBaseType,
+ isNeverAndOrUnknownType,
+} from "../../shared/nodeTypes.js";
+import { TypeSummary } from "./summarization.js";
export type TypeSummariesPerNodeByName = Map;
export interface TypeSummaryWithNode {
- summary: TypeSummary;
- originalProperty: PropertySignatureWithType;
- originalPropertyType: ts.Type;
+ originalProperty: PropertySignatureWithType;
+ originalPropertyType: ts.Type;
+ summary: TypeSummary;
}
/**
* Appends new types as union type nodes to existing, apparently incomplete types.
*/
export const addIncompleteTypesToType = (
- request: FileMutationsRequest,
- incompleteTypes: TypeSummariesPerNodeByName,
+ request: FileMutationsRequest,
+ incompleteTypes: TypeSummariesPerNodeByName,
): Mutation | undefined => {
- const mutations: Mutation[] = [];
+ const mutations: Mutation[] = [];
- for (const summaryWithNode of incompleteTypes.values()) {
- const mutation = fillInIncompleteType(request, summaryWithNode);
+ for (const summaryWithNode of incompleteTypes.values()) {
+ const mutation = fillInIncompleteType(request, summaryWithNode);
- if (mutation !== undefined) {
- mutations.push(mutation);
- }
- }
+ if (mutation !== undefined) {
+ mutations.push(mutation);
+ }
+ }
- return mutations.length === 0 ? undefined : combineMutations(...mutations);
+ return mutations.length === 0 ? undefined : combineMutations(...mutations);
};
const fillInIncompleteType = (
- request: FileMutationsRequest,
- summaryWithNode: TypeSummaryWithNode,
+ request: FileMutationsRequest,
+ summaryWithNode: TypeSummaryWithNode,
): MultipleMutations | TextInsertMutation | TextSwapMutation | undefined => {
- // Create a new type name to add on that joins the types to be added
- let createdTypeName = request.services.printers.type(
- summaryWithNode.summary.types,
- summaryWithNode.originalProperty.type ?? summaryWithNode.originalProperty,
- );
+ // Create a new type name to add on that joins the types to be added
+ let createdTypeName = request.services.printers.type(
+ summaryWithNode.summary.types,
+ summaryWithNode.originalProperty.type,
+ );
- // For some reason, the enclosingNode option of printing isn't always applying...
- if (createdTypeName.includes("=>")) {
- createdTypeName = `(${createdTypeName})`;
- }
+ // For some reason, the enclosingNode option of printing isn't always applying...
+ if (createdTypeName.includes("=>")) {
+ createdTypeName = `(${createdTypeName})`;
+ }
- // Similar to createTypeAdditionMutation, if the node is a basic base type, we can just replace it
- if (
- summaryWithNode.originalProperty.type !== undefined &&
- (isKnownGlobalBaseType(summaryWithNode.originalPropertyType) || isNeverAndOrUnknownType(summaryWithNode.originalPropertyType))
- ) {
- return {
- insertion: `: ${createdTypeName}`,
- range: {
- begin: summaryWithNode.originalProperty.name.end,
- end: summaryWithNode.originalProperty.type.end,
- },
- type: "text-swap",
- };
- }
+ // Similar to createTypeAdditionMutation, if the node is a basic base type, we can just replace it
+ if (
+ isKnownGlobalBaseType(summaryWithNode.originalPropertyType) ||
+ isNeverAndOrUnknownType(summaryWithNode.originalPropertyType)
+ ) {
+ return {
+ insertion: `: ${createdTypeName}`,
+ range: {
+ begin: summaryWithNode.originalProperty.name.end,
+ end: summaryWithNode.originalProperty.type.end,
+ },
+ type: "text-swap",
+ };
+ }
- // If the original node type is a function type, wrap it in parenthesis
- const originalPropertyTypePrinted = request.services.printers.type(summaryWithNode.originalPropertyType);
- if (originalPropertyTypePrinted.includes("=>")) {
- const parenthesisInsertions: TextInsertMutation[] = [
- {
- insertion: "(",
- range: {
- begin: summaryWithNode.originalProperty.type.pos,
- },
- type: "text-insert",
- },
- {
- insertion: `) | ${createdTypeName}`,
- range: {
- begin: summaryWithNode.originalProperty.type.end,
- },
- type: "text-insert",
- },
- ];
- return {
- mutations: parenthesisInsertions,
- range: {
- begin: summaryWithNode.originalProperty.type.pos,
- end: summaryWithNode.originalProperty.type.end,
- },
- type: "multiple",
- };
- }
+ // If the original node type is a function type, wrap it in parenthesis
+ const originalPropertyTypePrinted = request.services.printers.type(
+ summaryWithNode.originalPropertyType,
+ );
+ if (originalPropertyTypePrinted.includes("=>")) {
+ const parenthesisInsertions: TextInsertMutation[] = [
+ {
+ insertion: "(",
+ range: {
+ begin: summaryWithNode.originalProperty.type.pos,
+ },
+ type: "text-insert",
+ },
+ {
+ insertion: `) | ${createdTypeName}`,
+ range: {
+ begin: summaryWithNode.originalProperty.type.end,
+ },
+ type: "text-insert",
+ },
+ ];
+ return {
+ mutations: parenthesisInsertions,
+ range: {
+ begin: summaryWithNode.originalProperty.type.pos,
+ end: summaryWithNode.originalProperty.type.end,
+ },
+ type: "multiple",
+ };
+ }
- // Otherwise we can stick with only the insertion of the new type as a union
- return {
- insertion: ` | ${createdTypeName}`,
- range: {
- begin: summaryWithNode.originalProperty.type.end,
- },
- type: "text-insert",
- };
+ // Otherwise we can stick with only the insertion of the new type as a union
+ return {
+ insertion: ` | ${createdTypeName}`,
+ range: {
+ begin: summaryWithNode.originalProperty.type.end,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutations/expansions/addMissingTypesToType.ts b/src/mutations/expansions/addMissingTypesToType.ts
index 1a8ee39b8..3bbcfc96c 100644
--- a/src/mutations/expansions/addMissingTypesToType.ts
+++ b/src/mutations/expansions/addMissingTypesToType.ts
@@ -1,44 +1,46 @@
import { TextInsertMutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { printNamedTypeSummary } from "../../shared/printing/nodePrinting";
-
-import { TypeSummariesByName } from "./summarization";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { printNamedTypeSummary } from "../../shared/printing/nodePrinting.js";
+import { TypeSummariesByName } from "./summarization.js";
/**
* Adds new named type properties to a declaration that is missing them.
*/
export const addMissingTypesToType = (
- request: FileMutationsRequest,
- node: ts.InterfaceDeclaration | ts.TypeLiteralNode,
- missingTypes: TypeSummariesByName,
+ request: FileMutationsRequest,
+ node: ts.InterfaceDeclaration | ts.TypeLiteralNode,
+ missingTypes: TypeSummariesByName,
): TextInsertMutation | undefined => {
- let insertion = "";
-
- for (const [name, summary] of missingTypes) {
- insertion += printNamedTypeSummary(request, node, name, summary);
- }
-
- if (!insertion) {
- return undefined;
- }
-
- return {
- insertion,
- range: {
- begin: getEndInsertionPoint(node),
- },
- type: "text-insert",
- };
+ let insertion = "";
+
+ for (const [name, summary] of missingTypes) {
+ insertion += printNamedTypeSummary(request, node, name, summary);
+ }
+
+ if (!insertion) {
+ return undefined;
+ }
+
+ return {
+ insertion,
+ range: {
+ begin: getEndInsertionPoint(node),
+ },
+ type: "text-insert",
+ };
};
-const getEndInsertionPoint = ({ end, members }: ts.InterfaceDeclaration | ts.TypeLiteralNode) => {
- if (members.length === 0) {
- return end - 1;
- }
+const getEndInsertionPoint = ({
+ end,
+ members,
+}: ts.InterfaceDeclaration | ts.TypeLiteralNode) => {
+ if (members.length === 0) {
+ return end - 1;
+ }
- const lastMember = members[members.length - 1];
+ const lastMember = members[members.length - 1];
- return Math.min(lastMember.end + 1, end);
+ return Math.min(lastMember.end + 1, end);
};
diff --git a/src/mutations/expansions/eliminations.ts b/src/mutations/expansions/eliminations.ts
index 8ea67ab68..c676d4202 100644
--- a/src/mutations/expansions/eliminations.ts
+++ b/src/mutations/expansions/eliminations.ts
@@ -1,66 +1,99 @@
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { isKnownGlobalBaseType, isNeverAndOrUnknownType } from "../../shared/nodeTypes";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import {
+ isKnownGlobalBaseType,
+ isNeverAndOrUnknownType,
+} from "../../shared/nodeTypes.js";
-const onlyTypes = (candidateTypes: ReadonlyArray): candidateTypes is ReadonlyArray =>
- !candidateTypes.some((candidateType) => typeof candidateType === "string");
+const onlyTypes = (
+ candidateTypes: readonly (string | ts.Type)[],
+): candidateTypes is readonly ts.Type[] =>
+ !candidateTypes.some((candidateType) => typeof candidateType === "string");
/**
* @returns Whether any of the extra types don't yet exist on an original type.
- * @remarks If any of the candidate types are strings, this unfortunately has to assume true.
+ * If any of the candidate types are strings, this unfortunately has to assume true.
*/
export const originalTypeHasIncompleteType = (
- request: FileMutationsRequest,
- originalType: ts.Type,
- candidateTypes: ReadonlyArray,
+ request: FileMutationsRequest,
+ originalType: ts.Type,
+ candidateTypes: readonly (string | ts.Type)[],
) => {
- if (!onlyTypes(candidateTypes)) {
- return true;
- }
+ if (!onlyTypes(candidateTypes)) {
+ return true;
+ }
- // If the original type is something like Function and at least one candidate type isn't,
- // consider the Function to be reporting not enough info (like a base type)
- if (isKnownGlobalBaseType(originalType) && !candidateTypes.every(isKnownGlobalBaseType)) {
- return true;
- }
+ // If the original type is something like Function and at least one candidate type isn't,
+ // consider the Function to be reporting not enough info (like a base type)
+ if (
+ isKnownGlobalBaseType(originalType) &&
+ !candidateTypes.every(isKnownGlobalBaseType)
+ ) {
+ return true;
+ }
- // If the original type is unknown or never, we can always assume it's missing info
- if (isNeverAndOrUnknownType(originalType)) {
- return true;
- }
+ // If the original type is unknown or never, we can always assume it's missing info
+ if (isNeverAndOrUnknownType(originalType)) {
+ return true;
+ }
- return candidateTypes.some((assignedType) => !candidateTypeIsAssignableToOriginal(request, assignedType, originalType));
+ return candidateTypes.some(
+ (assignedType) =>
+ !candidateTypeIsAssignableToOriginal(request, assignedType, originalType),
+ );
};
-const candidateTypeIsAssignableToOriginal = (request: FileMutationsRequest, candidateType: ts.Type, originalType: ts.Type) => {
- const typeChecker = request.services.program.getTypeChecker();
+const candidateTypeIsAssignableToOriginal = (
+ request: FileMutationsRequest,
+ candidateType: ts.Type,
+ originalType: ts.Type,
+) => {
+ const typeChecker = request.services.program.getTypeChecker();
- // The type checker things that functions with similar base return types are the same
- // e.g. () => boolean is marked as assignable to () => void
- // We know that's false, so if the two are functions
- const missingFunctionReturn = functionReturnIsIncomplete(request, candidateType, originalType);
- if (missingFunctionReturn !== undefined) {
- return !missingFunctionReturn;
- }
+ // The type checker things that functions with similar base return types are the same
+ // e.g. () => boolean is marked as assignable to () => void
+ // We know that's false, so if the two are functions
+ const missingFunctionReturn = functionReturnIsIncomplete(
+ request,
+ candidateType,
+ originalType,
+ );
+ if (missingFunctionReturn !== undefined) {
+ return !missingFunctionReturn;
+ }
- // Otherwise we can directly use isTypeAssignableTo checking
- return typeChecker.isTypeAssignableTo(candidateType, originalType);
+ // Otherwise we can directly use isTypeAssignableTo checking
+ return typeChecker.isTypeAssignableTo(candidateType, originalType);
};
-const functionReturnIsIncomplete = (request: FileMutationsRequest, candidateType: ts.Type, originalType: ts.Type) => {
- const typeChecker = request.services.program.getTypeChecker();
+const functionReturnIsIncomplete = (
+ request: FileMutationsRequest,
+ candidateType: ts.Type,
+ originalType: ts.Type,
+) => {
+ const typeChecker = request.services.program.getTypeChecker();
- // Skip this logic if neither of the types are actually functions that return void
- if (!anySignatureReturnsVoid(candidateType) && !anySignatureReturnsVoid(originalType)) {
- return undefined;
- }
+ // Skip this logic if neither of the types are actually functions that return void
+ if (
+ !anySignatureReturnsVoid(candidateType) &&
+ !anySignatureReturnsVoid(originalType)
+ ) {
+ return undefined;
+ }
- // Regardless of the original compiler options, factor in covariance checks to be super duper sure
- return !typeChecker.isTypeAssignableTo(candidateType, originalType) || !typeChecker.isTypeAssignableTo(originalType, candidateType);
+ // Regardless of the original compiler options, factor in covariance checks to be super duper sure
+ return (
+ !typeChecker.isTypeAssignableTo(candidateType, originalType) ||
+ !typeChecker.isTypeAssignableTo(originalType, candidateType)
+ );
};
function anySignatureReturnsVoid(type: ts.Type) {
- return type.getCallSignatures().some((callSignature) => tsutils.isTypeFlagSet(callSignature.getReturnType(), ts.TypeFlags.Void));
+ return type
+ .getCallSignatures()
+ .some((callSignature) =>
+ tsutils.isTypeFlagSet(callSignature.getReturnType(), ts.TypeFlags.Void),
+ );
}
diff --git a/src/mutations/expansions/expansionMutations.ts b/src/mutations/expansions/expansionMutations.ts
index fa4a1a364..33bc49e31 100644
--- a/src/mutations/expansions/expansionMutations.ts
+++ b/src/mutations/expansions/expansionMutations.ts
@@ -1,72 +1,108 @@
-import { combineMutations, Mutation } from "automutate";
-import * as ts from "typescript";
+import { Mutation, combineMutations } from "automutate";
+import ts from "typescript";
-import { AssignedTypesByName } from "../assignments";
-import { InterfaceOrTypeLiteral } from "../../mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/collectGenericNodeReferences";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { isNotUndefined } from "../../shared/arrays";
-import { getStaticNameOfProperty } from "../../shared/names";
-
-import { addIncompleteTypesToType, TypeSummariesPerNodeByName } from "./addIncompleteTypesToType";
-import { addMissingTypesToType } from "./addMissingTypesToType";
-import { originalTypeHasIncompleteType } from "./eliminations";
-import { summarizeAllAssignedTypes, TypeSummariesByName } from "./summarization";
-import { isNodeWithType, PropertySignatureWithType } from "../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../shared/types";
+import { InterfaceOrTypeLiteral } from "../../mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/collectGenericNodeReferences.js";
+import { isNotUndefined } from "../../shared/arrays.js";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { getStaticNameOfProperty } from "../../shared/names.js";
+import {
+ PropertySignatureWithType,
+ isNodeWithType,
+} from "../../shared/nodeTypes.js";
+import { getTypeAtLocationIfNotError } from "../../shared/types.js";
+import { AssignedTypesByName } from "../assignments.js";
+import {
+ TypeSummariesPerNodeByName,
+ addIncompleteTypesToType,
+} from "./addIncompleteTypesToType.js";
+import { addMissingTypesToType } from "./addMissingTypesToType.js";
+import { originalTypeHasIncompleteType } from "./eliminations.js";
+import {
+ TypeSummariesByName,
+ summarizeAllAssignedTypes,
+} from "./summarization.js";
/**
* Given an interface or type declaration and a set of later-assigned types,
* expands the original declaration to now also include the types.
*/
export const createTypeExpansionMutation = (
- request: FileMutationsRequest,
- node: InterfaceOrTypeLiteral,
- allAssignedTypes: AssignedTypesByName[],
+ request: FileMutationsRequest,
+ node: InterfaceOrTypeLiteral,
+ allAssignedTypes: AssignedTypesByName[],
): Mutation | undefined => {
- const originalPropertiesByName = groupPropertyDeclarationsByName(node);
- const summarizedAssignedTypes = summarizeAllAssignedTypes(request, allAssignedTypes);
- const incompleteTypes: TypeSummariesPerNodeByName = new Map();
- const missingTypes: TypeSummariesByName = new Map();
+ const originalPropertiesByName = groupPropertyDeclarationsByName(node);
+ const summarizedAssignedTypes = summarizeAllAssignedTypes(
+ request,
+ allAssignedTypes,
+ );
+ const incompleteTypes: TypeSummariesPerNodeByName = new Map();
+ const missingTypes: TypeSummariesByName = new Map();
- for (const [name, summary] of summarizedAssignedTypes) {
- // If the original type doesn't have the name at all, we'll need to add it in
- const originalProperty = originalPropertiesByName.get(name);
- if (originalProperty === undefined) {
- missingTypes.set(name, summary);
- continue;
- }
+ for (const [name, summary] of summarizedAssignedTypes) {
+ // If the original type doesn't have the name at all, we'll need to add it in
+ const originalProperty = originalPropertiesByName.get(name);
+ if (originalProperty === undefined) {
+ missingTypes.set(name, summary);
+ continue;
+ }
- // If the type matches an existing property in name but not in type, we'll add the new type in there
- const originalPropertyType = getTypeAtLocationIfNotError(request, originalProperty);
- if (originalPropertyType !== undefined && originalTypeHasIncompleteType(request, originalPropertyType, summary.types)) {
- incompleteTypes.set(name, { originalProperty, originalPropertyType, summary });
- }
- }
+ // If the type matches an existing property in name but not in type, we'll add the new type in there
+ const originalPropertyType = getTypeAtLocationIfNotError(
+ request,
+ originalProperty,
+ );
+ if (
+ originalPropertyType !== undefined &&
+ originalTypeHasIncompleteType(
+ request,
+ originalPropertyType,
+ summary.types,
+ )
+ ) {
+ incompleteTypes.set(name, {
+ originalProperty,
+ originalPropertyType,
+ summary,
+ });
+ }
+ }
- const incompleteTypesMutations = addIncompleteTypesToType(request, incompleteTypes);
- const missingTypesMutations = addMissingTypesToType(request, node, missingTypes);
- const mutations = [incompleteTypesMutations, missingTypesMutations].filter(isNotUndefined);
+ const incompleteTypesMutations = addIncompleteTypesToType(
+ request,
+ incompleteTypes,
+ );
+ const missingTypesMutations = addMissingTypesToType(
+ request,
+ node,
+ missingTypes,
+ );
+ const mutations = [incompleteTypesMutations, missingTypesMutations].filter(
+ isNotUndefined,
+ );
- return mutations.length === 0 ? undefined : combineMutations(...mutations);
+ return mutations.length === 0 ? undefined : combineMutations(...mutations);
};
-const groupPropertyDeclarationsByName = (node: ts.InterfaceDeclaration | ts.TypeLiteralNode) => {
- const propertiesByName: Map = new Map();
+const groupPropertyDeclarationsByName = (
+ node: ts.InterfaceDeclaration | ts.TypeLiteralNode,
+) => {
+ const propertiesByName = new Map();
- for (const member of node.members) {
- // Ignore non-existent or implicitly typed members
- if (!ts.isPropertySignature(member) || !isNodeWithType(member)) {
- continue;
- }
+ for (const member of node.members) {
+ // Ignore non-existent or implicitly typed members
+ if (!ts.isPropertySignature(member) || !isNodeWithType(member)) {
+ continue;
+ }
- // Ignore any property with a name that's not immediately convertable to a string
- const name = getStaticNameOfProperty(member.name);
- if (name === undefined) {
- continue;
- }
+ // Ignore any property with a name that's not immediately convertible to a string
+ const name = getStaticNameOfProperty(member.name);
+ if (name === undefined) {
+ continue;
+ }
- propertiesByName.set(name, member);
- }
+ propertiesByName.set(name, member);
+ }
- return propertiesByName;
+ return propertiesByName;
};
diff --git a/src/mutations/expansions/summarization.ts b/src/mutations/expansions/summarization.ts
index 17c5b3671..8b531c67d 100644
--- a/src/mutations/expansions/summarization.ts
+++ b/src/mutations/expansions/summarization.ts
@@ -1,71 +1,79 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
-import { AssignedTypesByName } from "../assignments";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
+import { AssignedTypesByName } from "../assignments.js";
export type TypeSummariesByName = Map;
export interface TypeSummary {
- alwaysProvided?: boolean;
- types: (ts.Type | string)[];
+ alwaysProvided?: boolean;
+ types: (string | ts.Type)[];
}
/**
* Groups a list of assignments into, for each property name, the possible types under it and whether it's always provided.
*/
-export const summarizeAllAssignedTypes = (request: FileMutationsRequest, allAssignedTypes: AssignedTypesByName[]): TypeSummariesByName => {
- const typeSummariesByName: TypeSummariesByName = new Map();
+export const summarizeAllAssignedTypes = (
+ request: FileMutationsRequest,
+ allAssignedTypes: AssignedTypesByName[],
+): TypeSummariesByName => {
+ const typeSummariesByName: TypeSummariesByName = new Map();
- // First, collect all assigned types from each usage into the list of types by name
- for (const assignedTypes of allAssignedTypes) {
- for (const [name, type] of assignedTypes) {
- // If this is the first time seeing the type, start a new entry for it
- const existingTypeSummary = typeSummariesByName.get(name);
- if (existingTypeSummary === undefined) {
- typeSummariesByName.set(name, { types: [type] });
- continue;
- }
+ // First, collect all assigned types from each usage into the list of types by name
+ for (const assignedTypes of allAssignedTypes) {
+ for (const [name, type] of assignedTypes) {
+ // If this is the first time seeing the type, start a new entry for it
+ const existingTypeSummary = typeSummariesByName.get(name);
+ if (existingTypeSummary === undefined) {
+ typeSummariesByName.set(name, { types: [type] });
+ continue;
+ }
- // Merge the existing types and the new type into the summary if possible
- mergeTypes(request, existingTypeSummary.types, type);
- }
- }
+ // Merge the existing types and the new type into the summary if possible
+ mergeTypes(request, existingTypeSummary.types, type);
+ }
+ }
- // For each of summarized type, mark it as `alwaysProvided` if every set of assigned types includes it
- for (const [name, typeSummary] of typeSummariesByName) {
- if (allAssignedTypes.every((assignedTypes) => assignedTypes.has(name))) {
- typeSummary.alwaysProvided = true;
- }
- }
+ // For each of summarized type, mark it as `alwaysProvided` if every set of assigned types includes it
+ for (const [name, typeSummary] of typeSummariesByName) {
+ if (allAssignedTypes.every((assignedTypes) => assignedTypes.has(name))) {
+ typeSummary.alwaysProvided = true;
+ }
+ }
- return typeSummariesByName;
+ return typeSummariesByName;
};
-const mergeTypes = (request: FileMutationsRequest, existingTypes: (ts.Type | string)[], potentialNewType: ts.Type | string) => {
- const typeChecker = request.services.program.getTypeChecker();
+const mergeTypes = (
+ request: FileMutationsRequest,
+ existingTypes: (string | ts.Type)[],
+ potentialNewType: string | ts.Type,
+) => {
+ const typeChecker = request.services.program.getTypeChecker();
- for (let i = 0; i < existingTypes.length; i += 1) {
- const existingType = existingTypes[i];
- if (typeof existingType === "string") {
- if (typeof potentialNewType === "string") {
- if (existingType === potentialNewType) {
- return;
- }
- }
- } else {
- if (typeof potentialNewType === "string") {
- continue;
- }
- if (typeChecker.isTypeAssignableTo(potentialNewType, existingType)) {
- return;
- }
+ for (let i = 0; i < existingTypes.length; i += 1) {
+ const existingType = existingTypes[i];
+ if (typeof existingType === "string") {
+ if (typeof potentialNewType === "string") {
+ if (existingType === potentialNewType) {
+ return;
+ }
+ }
+ } else {
+ if (typeof potentialNewType === "string") {
+ continue;
+ }
- if (typeChecker.isTypeAssignableTo(existingType, potentialNewType)) {
- existingTypes[i] = potentialNewType;
- return;
- }
- }
- }
+ if (typeChecker.isTypeAssignableTo(potentialNewType, existingType)) {
+ return;
+ }
- existingTypes.push(potentialNewType);
+ if (typeChecker.isTypeAssignableTo(existingType, potentialNewType)) {
+ existingTypes[i] = potentialNewType;
+ return;
+ }
+ }
+ }
+
+ existingTypes.push(potentialNewType);
};
diff --git a/src/mutations/generics.ts b/src/mutations/generics.ts
index 091d4e700..b9278362b 100644
--- a/src/mutations/generics.ts
+++ b/src/mutations/generics.ts
@@ -1,26 +1,34 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../shared/fileMutator";
-import { isTypeBuiltIn } from "../shared/types";
-
-import { constructArrayShorthand } from "./arrays";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
+import { isTypeBuiltIn } from "../shared/types.js";
+import { constructArrayShorthand } from "./arrays.js";
/**
* Creates a type like "string[]" or "Map" from a container and type arguments.
*/
-export const joinIntoGenericType = (request: FileMutationsRequest, containerType: ts.Type, allTypeArgumentTypes: ts.Type[][]) => {
- const containerTypeName = request.services.printers
- .type(containerType, undefined, ts.TypeFormatFlags.WriteArrayAsGenericType)
- // Names with parameters like Array and Map should ignore those parameters
- .split("<")[0];
+export const joinIntoGenericType = (
+ request: FileMutationsRequest,
+ containerType: ts.Type,
+ allTypeArgumentTypes: ts.Type[][],
+) => {
+ const containerTypeName = request.services.printers
+ .type(containerType, undefined, ts.TypeFormatFlags.WriteArrayAsGenericType)
+ // Names with parameters like Array and Map should ignore those parameters
+ .split("<")[0];
+
+ // By now we're assuming the generic types can all be named
- // By now we're assuming the generic types can all be named
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const genericTypeNames = allTypeArgumentTypes.map((genericTypes) => request.services.printers.type(genericTypes)!);
+ const genericTypeNames = allTypeArgumentTypes.map((genericTypes) =>
+ request.services.printers.type(genericTypes),
+ );
- if (containerTypeName.split("<")[0] === "Array" && isTypeBuiltIn(containerType)) {
- return constructArrayShorthand(genericTypeNames);
- }
+ if (
+ containerTypeName.split("<")[0] === "Array" &&
+ isTypeBuiltIn(containerType)
+ ) {
+ return constructArrayShorthand(genericTypeNames);
+ }
- return `${containerTypeName}<${genericTypeNames.join(", ")}>`;
+ return `${containerTypeName}<${genericTypeNames.join(", ")}>`;
};
diff --git a/src/mutations/naming.ts b/src/mutations/naming.ts
index 7d540a463..f0be56f4b 100644
--- a/src/mutations/naming.ts
+++ b/src/mutations/naming.ts
@@ -1,41 +1,51 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../shared/fileMutator";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
export const isUpperCaseLetter = (letter: string) => {
- return letter !== letter.toLowerCase();
+ return letter !== letter.toLowerCase();
};
-export const getPerceivedNameOfClass = (request: FileMutationsRequest, node: ts.ClassLikeDeclaration): string => {
- // Clases with their own names are the most common and mostly friendly case
- if (node.name !== undefined) {
- return node.name.text;
- }
-
- // If the class is directly within a named variable, use that name
- const { parent } = node;
- if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
- return parent.name.text;
- }
-
- // We could probably do fancier things at this point but why bother...
- return request.nameGenerator.generateName("Class");
+export const getPerceivedNameOfClass = (
+ request: FileMutationsRequest,
+ node: ts.ClassLikeDeclaration,
+): string => {
+ // Classes with their own names are the most common and mostly friendly case
+ if (node.name !== undefined) {
+ return node.name.text;
+ }
+
+ // If the class is directly within a named variable, use that name
+ const { parent } = node;
+ if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
+ return parent.name.text;
+ }
+
+ // We could probably do fancier things at this point but why bother...
+ return request.nameGenerator.generateName("Class");
};
export const getFriendlyTypeParameterDeclarationName = (
- baseTypeParameters: ts.NodeArray,
- typeParameter: ts.TypeParameterDeclaration,
+ baseTypeParameters: ts.NodeArray,
+ typeParameter: ts.TypeParameterDeclaration,
) => {
- const typeNameRaw = typeParameter.name.text;
- const typeNameFriendly =
- typeNameRaw.length > 1 && typeNameRaw.startsWith("T") && isUpperCaseLetter(typeNameRaw[1]) ? typeNameRaw.slice(1) : typeNameRaw;
-
- // If any sibling parameter actually happens to match the friendly name, use the raw instead
- for (const siblingParameter of baseTypeParameters) {
- if (siblingParameter !== typeParameter && siblingParameter.name.text === typeNameFriendly) {
- return typeNameRaw;
- }
- }
-
- return typeNameFriendly;
+ const typeNameRaw = typeParameter.name.text;
+ const typeNameFriendly =
+ typeNameRaw.length > 1 &&
+ typeNameRaw.startsWith("T") &&
+ isUpperCaseLetter(typeNameRaw[1])
+ ? typeNameRaw.slice(1)
+ : typeNameRaw;
+
+ // If any sibling parameter actually happens to match the friendly name, use the raw instead
+ for (const siblingParameter of baseTypeParameters) {
+ if (
+ siblingParameter !== typeParameter &&
+ siblingParameter.name.text === typeNameFriendly
+ ) {
+ return typeNameRaw;
+ }
+ }
+
+ return typeNameFriendly;
};
diff --git a/src/mutations/readCharactersOfFile.ts b/src/mutations/readCharactersOfFile.ts
index 602d44f16..6021fca9d 100644
--- a/src/mutations/readCharactersOfFile.ts
+++ b/src/mutations/readCharactersOfFile.ts
@@ -1,10 +1,13 @@
import * as fs from "fs";
-export const readCharactersOfFile = (fileName: string, length: number): string => {
- const fd = fs.openSync(fileName, "r");
- const buffer = Buffer.alloc(length);
+export const readCharactersOfFile = (
+ fileName: string,
+ length: number,
+): string => {
+ const fd = fs.openSync(fileName, "r");
+ const buffer = Buffer.alloc(length);
- fs.readSync(fd, buffer, 0, length, 0);
+ fs.readSync(fd, buffer, 0, length, 0);
- return buffer.toString();
+ return buffer.toString();
};
diff --git a/src/mutations/removals.ts b/src/mutations/removals.ts
index e017c28f6..8865ca4eb 100644
--- a/src/mutations/removals.ts
+++ b/src/mutations/removals.ts
@@ -1,14 +1,20 @@
import { TextDeleteMutation } from "automutate";
-import { NodeWithType } from "../shared/nodeTypes";
-import { FileMutationsRequest } from "../shared/fileMutator";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
+import { NodeWithType } from "../shared/nodeTypes.js";
-export const createTypeRemovalMutation = (request: FileMutationsRequest, node: NodeWithType): TextDeleteMutation => {
- return {
- range: {
- begin: node.type.getStart(request.sourceFile) - node.type.getLeadingTriviaWidth(request.sourceFile) - 1,
- end: node.type.end,
- },
- type: "text-delete",
- };
+export const createTypeRemovalMutation = (
+ request: FileMutationsRequest,
+ node: NodeWithType,
+): TextDeleteMutation => {
+ return {
+ range: {
+ begin:
+ node.type.getStart(request.sourceFile) -
+ node.type.getLeadingTriviaWidth(request.sourceFile) -
+ 1,
+ end: node.type.end,
+ },
+ type: "text-delete",
+ };
};
diff --git a/src/mutations/renames/createRequireMutation.ts b/src/mutations/renames/createRequireMutation.ts
index d09de0c73..aa8065241 100644
--- a/src/mutations/renames/createRequireMutation.ts
+++ b/src/mutations/renames/createRequireMutation.ts
@@ -1,21 +1,23 @@
import { TextSwapMutation } from "automutate";
-import { RequireRenameRequest } from "./findRequireRenameMutationsInFile";
-import { LocalImplicitRequireCallExpression } from "./isRequireToJsFile";
+import { RequireRenameRequest } from "./findRequireRenameMutationsInFile.js";
+import { LocalImplicitRequireCallExpression } from "./isRequireToJsFile.js";
export const createRequireMutation = (
- request: RequireRenameRequest,
- node: LocalImplicitRequireCallExpression,
+ request: RequireRenameRequest,
+ node: LocalImplicitRequireCallExpression,
): TextSwapMutation | undefined => {
- const newLocalFilePath = node.arguments[0].text.replace(/.js$/i, ".ts").replace(/.jsx$/i, ".tsx");
- const newLocalImportPath = newLocalFilePath.replace(/.tsx?$/i, "");
+ const newLocalFilePath = node.arguments[0].text
+ .replace(/.js$/i, ".ts")
+ .replace(/.jsx$/i, ".tsx");
+ const newLocalImportPath = newLocalFilePath.replace(/.tsx?$/i, "");
- return {
- insertion: `(${node.getText(request.sourceFile)} as typeof import("${newLocalImportPath}"))`,
- range: {
- begin: node.getStart(request.sourceFile),
- end: node.end,
- },
- type: "text-swap",
- };
+ return {
+ insertion: `(${node.getText(request.sourceFile)} as typeof import("${newLocalImportPath}"))`,
+ range: {
+ begin: node.getStart(request.sourceFile),
+ end: node.end,
+ },
+ type: "text-swap",
+ };
};
diff --git a/src/mutations/renames/findRequireRenameMutationsInFile.ts b/src/mutations/renames/findRequireRenameMutationsInFile.ts
index 4ae677071..906b04c5f 100644
--- a/src/mutations/renames/findRequireRenameMutationsInFile.ts
+++ b/src/mutations/renames/findRequireRenameMutationsInFile.ts
@@ -1,32 +1,33 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { TypeStatOptions } from "../../options/types";
-
-import { createRequireMutation } from "./createRequireMutation";
-import { isRequireToJsFile } from "./isRequireToJsFile";
+import { TypeStatOptions } from "../../options/types.js";
+import { createRequireMutation } from "./createRequireMutation.js";
+import { isRequireToJsFile } from "./isRequireToJsFile.js";
export interface RequireRenameRequest {
- allFileNames: ReadonlySet;
- options: TypeStatOptions;
- sourceFile: ts.SourceFile;
+ allFileNames: ReadonlySet;
+ options: TypeStatOptions;
+ sourceFile: ts.SourceFile;
}
-export const findRequireRenameMutationsInFile = (request: RequireRenameRequest) => {
- const mutations: Mutation[] = [];
- const visitNode = (node: ts.Node) => {
- if (isRequireToJsFile(node)) {
- const mutation = createRequireMutation(request, node);
+export const findRequireRenameMutationsInFile = (
+ request: RequireRenameRequest,
+) => {
+ const mutations: Mutation[] = [];
+ const visitNode = (node: ts.Node) => {
+ if (isRequireToJsFile(node)) {
+ const mutation = createRequireMutation(request, node);
- if (mutation !== undefined) {
- mutations.push(mutation);
- }
- }
+ if (mutation !== undefined) {
+ mutations.push(mutation);
+ }
+ }
- ts.forEachChild(node, visitNode);
- };
+ ts.forEachChild(node, visitNode);
+ };
- visitNode(request.sourceFile);
+ visitNode(request.sourceFile);
- return mutations;
+ return mutations;
};
diff --git a/src/mutations/renames/isRequireToJsFile.ts b/src/mutations/renames/isRequireToJsFile.ts
index 8d97dc272..fd2d6064b 100644
--- a/src/mutations/renames/isRequireToJsFile.ts
+++ b/src/mutations/renames/isRequireToJsFile.ts
@@ -1,20 +1,25 @@
-import * as ts from "typescript";
+import ts from "typescript";
export type LocalImplicitRequireCallExpression = ts.CallExpression & {
- arguments: [ts.StringLiteral];
+ arguments: [ts.StringLiteral];
};
-export const isRequireToJsFile = (node: ts.Node): node is LocalImplicitRequireCallExpression => {
- if (
- !ts.isCallExpression(node) ||
- ts.isAsExpression(node.parent) ||
- ts.isTypeAssertionExpression(node.parent) ||
- node.arguments.length !== 1
- ) {
- return false;
- }
+export const isRequireToJsFile = (
+ node: ts.Node,
+): node is LocalImplicitRequireCallExpression => {
+ if (
+ !ts.isCallExpression(node) ||
+ ts.isAsExpression(node.parent) ||
+ ts.isTypeAssertionExpression(node.parent) ||
+ node.arguments.length !== 1
+ ) {
+ return false;
+ }
- const firstArgument = node.arguments[0];
+ const firstArgument = node.arguments[0];
- return ts.isStringLiteral(firstArgument) && firstArgument.text.match(/\.(.*)\.jsx?$/i) !== null;
+ return (
+ ts.isStringLiteral(firstArgument) &&
+ firstArgument.text.match(/\.(.*)\.jsx?$/i) !== null
+ );
};
diff --git a/src/mutations/typeMutating/createNonNullAssertion.ts b/src/mutations/typeMutating/createNonNullAssertion.ts
index b6be238a4..c3fba4d87 100644
--- a/src/mutations/typeMutating/createNonNullAssertion.ts
+++ b/src/mutations/typeMutating/createNonNullAssertion.ts
@@ -1,7 +1,7 @@
import { TextInsertMutation, TextSwapMutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../shared/fileMutator";
+import { FileMutationsRequest } from "../../shared/fileMutator.js";
// The following node types need to be wrapped in parenthesis to stop the ! from being applied to the wrong (last) element:
// As expressions: foo as Bar
@@ -9,39 +9,44 @@ import { FileMutationsRequest } from "../../shared/fileMutator";
// Conditional expressions: foo ? bar : baz
// Void expressions: void 0
const wrappedKinds = new Set([
- ts.SyntaxKind.AsExpression,
- ts.SyntaxKind.AwaitExpression,
- ts.SyntaxKind.BinaryExpression,
- ts.SyntaxKind.ConditionalExpression,
- ts.SyntaxKind.VoidExpression,
+ ts.SyntaxKind.AsExpression,
+ ts.SyntaxKind.AwaitExpression,
+ ts.SyntaxKind.BinaryExpression,
+ ts.SyntaxKind.ConditionalExpression,
+ ts.SyntaxKind.VoidExpression,
]);
-export const createNonNullAssertion = (request: FileMutationsRequest, node: ts.Node): TextInsertMutation | TextSwapMutation => {
- // For property assignments (`key: value`), create a non-null assertion only for `value`.
- if (ts.isPropertyAssignment(node)) {
- node = node.initializer;
- }
+export const createNonNullAssertion = (
+ request: FileMutationsRequest,
+ node: ts.Node,
+): TextInsertMutation | TextSwapMutation => {
+ // For property assignments (`key: value`), create a non-null assertion only for `value`.
+ if (ts.isPropertyAssignment(node)) {
+ node = node.initializer;
+ }
- // If the node must be wrapped in parenthesis, replace all of it
- if (wrappedKinds.has(node.kind)) {
- return {
- insertion: `(${node.getText(request.sourceFile)})!`,
- range: {
- begin: node.getStart(request.sourceFile),
- end: node.end,
- },
- type: "text-swap",
- };
- }
+ // If the node must be wrapped in parenthesis, replace all of it
+ if (wrappedKinds.has(node.kind)) {
+ return {
+ insertion: `(${node.getText(request.sourceFile)})!`,
+ range: {
+ begin: node.getStart(request.sourceFile),
+ end: node.end,
+ },
+ type: "text-swap",
+ };
+ }
- // Shorthand assignments (`{ value }`) must be converted to non-shorthand (`{ value: value ! }`)
- const insertion = ts.isShorthandPropertyAssignment(node) ? `: ${node.getText(request.sourceFile)}!` : "!";
+ // Shorthand assignments (`{ value }`) must be converted to non-shorthand (`{ value: value ! }`)
+ const insertion = ts.isShorthandPropertyAssignment(node)
+ ? `: ${node.getText(request.sourceFile)}!`
+ : "!";
- return {
- insertion,
- range: {
- begin: node.end,
- },
- type: "text-insert",
- };
+ return {
+ insertion,
+ range: {
+ begin: node.end,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutators/builtIn/fixImportExtensions/README.md b/src/mutators/builtIn/fixImportExtensions/README.md
index 0c30f0a17..dee512673 100644
--- a/src/mutators/builtIn/fixImportExtensions/README.md
+++ b/src/mutators/builtIn/fixImportExtensions/README.md
@@ -4,15 +4,15 @@ Whether to add extensions to `export` and `import` declarations that refer to fi
## Use Cases
-* Your existing code uses a build tool to import from files without using extensions, but TypeScript's `declare module` syntax requires importing via extensions.
+- Your existing code uses a build tool to import from files without using extensions, but TypeScript's `declare module` syntax requires importing via extensions.
## Configuration
```json
{
- "fixes": {
- "importExtensions": true
- }
+ "fixes": {
+ "importExtensions": true
+ }
}
```
diff --git a/src/mutators/builtIn/fixImportExtensions/index.ts b/src/mutators/builtIn/fixImportExtensions/index.ts
index f598063bb..8e2b4232b 100644
--- a/src/mutators/builtIn/fixImportExtensions/index.ts
+++ b/src/mutators/builtIn/fixImportExtensions/index.ts
@@ -1,64 +1,85 @@
import { TextInsertMutation } from "automutate";
import { glob } from "glob";
-import * as path from "path";
-import * as ts from "typescript";
+import * as path from "node:path";
+import ts from "typescript";
-import { getTypeAtLocationIfNotError } from "../../../shared/types";
-import { collectMutationsFromNodes } from "../../collectMutationsFromNodes";
-import { FileMutator, FileMutationsRequest } from "../../../shared/fileMutator";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../collectMutationsFromNodes.js";
-type ExtensionlessExportOrImport = (ts.ExportDeclaration | ts.ImportDeclaration) & {
- moduleSpecifier: ts.StringLiteral;
+type ExtensionlessExportOrImport = (
+ | ts.ExportDeclaration
+ | ts.ImportDeclaration
+) & {
+ moduleSpecifier: ts.StringLiteral;
};
-export const fixImportExtensions: FileMutator = (request: FileMutationsRequest) =>
- request.options.fixes.importExtensions
- ? collectMutationsFromNodes(request, isExtensionlessExportOrImport, visitExportOrImportDeclaration)
- : undefined;
+export const fixImportExtensions: FileMutator = (
+ request: FileMutationsRequest,
+) =>
+ request.options.fixes.importExtensions
+ ? collectMutationsFromNodes(
+ request,
+ isExtensionlessExportOrImport,
+ visitExportOrImportDeclaration,
+ )
+ : undefined;
-const isExtensionlessExportOrImport = (node: ts.Node): node is ExtensionlessExportOrImport => {
- return (
- (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
- node.moduleSpecifier !== undefined &&
- ts.isStringLiteral(node.moduleSpecifier) &&
- !path.basename(node.moduleSpecifier.text).includes(".")
- );
+const isExtensionlessExportOrImport = (
+ node: ts.Node,
+): node is ExtensionlessExportOrImport => {
+ return (
+ (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
+ node.moduleSpecifier !== undefined &&
+ ts.isStringLiteral(node.moduleSpecifier) &&
+ !path.basename(node.moduleSpecifier.text).includes(".")
+ );
};
const visitExportOrImportDeclaration = (
- node: ExtensionlessExportOrImport,
- request: FileMutationsRequest,
+ node: ExtensionlessExportOrImport,
+ request: FileMutationsRequest,
): TextInsertMutation | undefined => {
- // If the type of the import is already known, we don't need to fix it
- if (getTypeAtLocationIfNotError(request, node.moduleSpecifier) !== undefined) {
- return undefined;
- }
+ // If the type of the import is already known, we don't need to fix it
+ if (
+ getTypeAtLocationIfNotError(request, node.moduleSpecifier) !== undefined
+ ) {
+ return undefined;
+ }
- // Try each path that the import could resolve to
- const basePath = path.join(path.dirname(request.sourceFile.fileName), node.moduleSpecifier.text);
+ // Try each path that the import could resolve to
+ const basePath = path.join(
+ path.dirname(request.sourceFile.fileName),
+ node.moduleSpecifier.text,
+ );
- for (const filePath of [basePath, path.join(basePath, "index")]) {
- // If no files exist under that path, ignore this possibility
- const possibilities = glob.sync(filePath + ".*");
- if (possibilities.length === 0) {
- continue;
- }
+ for (const filePath of [basePath, path.join(basePath, "index")]) {
+ // If no files exist under that path, ignore this possibility
+ const possibilities = glob.sync(filePath + ".*");
+ if (possibilities.length === 0) {
+ continue;
+ }
- // Figure out which extension might be relevant (i.e. anything but build artifacts)
- const mostLikely = possibilities.find((possibility) => !/\.(((j|t)sx?)|map)$/.test(possibility));
- if (mostLikely === undefined) {
- continue;
- }
+ // Figure out which extension might be relevant (i.e. anything but build artifacts)
+ const mostLikely = possibilities.find(
+ (possibility) => !/\.(?:(?:j|t)sx?|map)$/.test(possibility),
+ );
+ if (mostLikely === undefined) {
+ continue;
+ }
- // Add the file's full extension to the original module specifier
- return {
- insertion: "." + path.basename(mostLikely).split(".").slice(1).join("."),
- range: {
- begin: node.moduleSpecifier.end - 1,
- },
- type: "text-insert",
- };
- }
+ // Add the file's full extension to the original module specifier
+ return {
+ insertion: "." + path.basename(mostLikely).split(".").slice(1).join("."),
+ range: {
+ begin: node.moduleSpecifier.end - 1,
+ },
+ type: "text-insert",
+ };
+ }
- return undefined;
+ return undefined;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/README.md b/src/mutators/builtIn/fixIncompleteTypes/README.md
index 5d9b9ddce..ca6e96403 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/README.md
+++ b/src/mutators/builtIn/fixIncompleteTypes/README.md
@@ -4,16 +4,16 @@ Whether to augment type annotations that don't capture all values constructs can
## Use Cases
-* You're enabling `strictNullChecks` but existing types don't yet have `| null` or `| undefined` as appropriate
-* You're converting from JavaScript to TypeScript and adding React component types
+- You're enabling `strictNullChecks` but existing types don't yet have `| null` or `| undefined` as appropriate
+- You're converting from JavaScript to TypeScript and adding React component types
## Configuration
```json
{
- "fixes": {
- "incompleteTypes": true
- }
+ "fixes": {
+ "incompleteTypes": true
+ }
}
```
@@ -127,11 +127,11 @@ class ContainsValue {
React components can have types their props filled in using:
-* Component classes:
- * `static propTypes = ...` properties
- * Later-assigned `.propTypes = ...` properties
-* Functional components: `propTypes` properties
-* Both: regular usage in JSX
+- Component classes:
+ - `static propTypes = ...` properties
+ - Later-assigned `.propTypes = ...` properties
+- Functional components: `propTypes` properties
+- Both: regular usage in JSX
Component classes will generate `interface`s, while function components will generate `type`s.
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/additions.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/additions.ts
index 394f367fd..2e98b3456 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/additions.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/additions.ts
@@ -1,38 +1,46 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { printNewLine } from "../../../../shared/printing/newlines";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { printNewLine } from "../../../../shared/printing/newlines.js";
-export const addNewTypeNodes = (request: FileMutationsRequest, node: ts.ClassLikeDeclaration, createdTypes: string[]) => {
- const endline = printNewLine(request.options.compilerOptions);
+export const addNewTypeNodes = (
+ request: FileMutationsRequest,
+ node: ts.ClassLikeDeclaration,
+ createdTypes: string[],
+) => {
+ const endline = printNewLine(request.options.compilerOptions);
- return {
- insertion: `${endline}${createdTypes.join(endline)}`,
- range: {
- begin: node.pos,
- },
- type: "text-insert",
- };
+ return {
+ insertion: `${endline}${createdTypes.join(endline)}`,
+ range: {
+ begin: node.pos,
+ },
+ type: "text-insert",
+ };
};
-export const addMissingTemplateTypes = (extension: ts.ExpressionWithTypeArguments, templateTypeNames: string[]) => {
- if (extension.typeArguments === undefined) {
- return {
- insertion: `<${templateTypeNames.join(", ")}>`,
- range: {
- begin: extension.end,
- },
- type: "text-insert",
- };
- }
+export const addMissingTemplateTypes = (
+ extension: ts.ExpressionWithTypeArguments,
+ templateTypeNames: string[],
+) => {
+ if (extension.typeArguments === undefined) {
+ return {
+ insertion: `<${templateTypeNames.join(", ")}>`,
+ range: {
+ begin: extension.end,
+ },
+ type: "text-insert",
+ };
+ }
- const lastExistingTypeArgument = extension.typeArguments[extension.typeArguments.length - 1];
+ const lastExistingTypeArgument =
+ extension.typeArguments[extension.typeArguments.length - 1];
- return {
- insertion: `, ${templateTypeNames.slice(extension.typeArguments.length).join(", ")}`,
- range: {
- begin: lastExistingTypeArgument.end,
- },
- type: "text-insert",
- };
+ return {
+ insertion: `, ${templateTypeNames.slice(extension.typeArguments.length).join(", ")}`,
+ range: {
+ begin: lastExistingTypeArgument.end,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/collectTypeParameterReferences.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/collectTypeParameterReferences.ts
index 1f5d27e49..ddc063def 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/collectTypeParameterReferences.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/collectTypeParameterReferences.ts
@@ -1,70 +1,84 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { isNotUndefined } from "../../../../shared/arrays";
-import { getCloseAncestorCallOrNewExpression, getExpressionWithin } from "../../../../shared/nodes";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
+import { isNotUndefined } from "../../../../shared/arrays.js";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import {
+ getCloseAncestorCallOrNewExpression,
+ getExpressionWithin,
+} from "../../../../shared/nodes.js";
/**
* Finds all the nodes that could indicate the type of a base type parameter,
* by finding all references to the class's declaration nodes of that type parameter.
*/
export const collectTypeParameterReferences = (
- request: FileMutationsRequest,
- childClass: ts.Node,
- baseClass: ts.Node,
- baseTypeParameter: ts.Node,
+ request: FileMutationsRequest,
+ childClass: ts.Node,
+ baseClass: ts.Node,
+ baseTypeParameter: ts.Node,
) => {
- // Find nodes that reference (and therefore indicate type information for) the base type
- const referencingNodes = request.fileInfoCache.getNodeReferencesAsNodes(baseTypeParameter);
- if (referencingNodes === undefined) {
- return undefined;
- }
+ // Find nodes that reference (and therefore indicate type information for) the base type
+ const referencingNodes =
+ request.fileInfoCache.getNodeReferencesAsNodes(baseTypeParameter);
+ if (referencingNodes === undefined) {
+ return undefined;
+ }
- const expandedReferences: ts.Node[] = [];
+ const expandedReferences: ts.Node[] = [];
- // For each node, find *its* references to see what types it may be
- for (const referencingNode of referencingNodes) {
- const { parent } = referencingNode;
- const expandedParentReferences = findParentExpandedReferences(request, parent);
- if (expandedParentReferences !== undefined) {
- expandedReferences.push(...expandedParentReferences);
- }
- }
+ // For each node, find *its* references to see what types it may be
+ for (const referencingNode of referencingNodes) {
+ const { parent } = referencingNode;
+ const expandedParentReferences = findParentExpandedReferences(
+ request,
+ parent,
+ );
+ if (expandedParentReferences !== undefined) {
+ expandedReferences.push(...expandedParentReferences);
+ }
+ }
- return expandedReferences;
+ return expandedReferences;
};
-const findParentExpandedReferences = (request: FileMutationsRequest, node: ts.Node) => {
- node = getEquivalentContainingTypeNode(node);
+const findParentExpandedReferences = (
+ request: FileMutationsRequest,
+ node: ts.Node,
+) => {
+ node = getEquivalentContainingTypeNode(node);
- // Property and variable declarations can be directly searched for as references
- if (ts.isParameterPropertyDeclaration(node, node.parent) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
- return request.fileInfoCache.getNodeReferencesAsNodes(node);
- }
+ // Property and variable declarations can be directly searched for as references
+ if (
+ ts.isParameterPropertyDeclaration(node, node.parent) ||
+ ts.isPropertyDeclaration(node) ||
+ ts.isVariableDeclaration(node)
+ ) {
+ return request.fileInfoCache.getNodeReferencesAsNodes(node);
+ }
- // Parameters need to check the equivalent index of their function's calls
- if (ts.isParameter(node) && ts.isFunctionLike(node.parent)) {
- const calls = request.fileInfoCache.getNodeReferencesAsNodes(node.parent);
- if (calls === undefined) {
- return undefined;
- }
+ // Parameters need to check the equivalent index of their function's calls
+ if (ts.isParameter(node) && ts.isFunctionLike(node.parent)) {
+ const calls = request.fileInfoCache.getNodeReferencesAsNodes(node.parent);
+ if (calls === undefined) {
+ return undefined;
+ }
- const parentIndex = node.parent.parameters.indexOf(node);
- return calls
- .map(getExpressionWithin)
- .map(getCloseAncestorCallOrNewExpression)
- .filter(isNotUndefined)
- .map((call) => call.arguments?.[parentIndex])
- .filter(isNotUndefined);
- }
+ const parentIndex = node.parent.parameters.indexOf(node);
+ return calls
+ .map(getExpressionWithin)
+ .map(getCloseAncestorCallOrNewExpression)
+ .filter(isNotUndefined)
+ .map((call) => call.arguments?.[parentIndex])
+ .filter(isNotUndefined);
+ }
- return undefined;
+ return undefined;
};
const getEquivalentContainingTypeNode = (node: ts.Node) => {
- while (ts.isIntersectionTypeNode(node.parent)) {
- node = node.parent.parent;
- }
+ while (ts.isIntersectionTypeNode(node.parent)) {
+ node = node.parent.parent;
+ }
- return node;
+ return node;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitClassGenerics/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitClassGenerics/index.ts
index 696d547d0..050ecb0ec 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitClassGenerics/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitClassGenerics/index.ts
@@ -1,41 +1,66 @@
-import { combineMutations, Mutation } from "automutate";
-import * as ts from "typescript";
-
-import { isNotUndefined } from "../../../../../shared/arrays";
-import { getBaseClassDeclaration, getClassExtendsExpression } from "../../../../../shared/nodeExtensions";
-import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../../shared/fileMutator";
-import { addMissingTemplateTypes, addNewTypeNodes } from "../additions";
-import { findMissingTemplateTypes } from "../templateCollecting";
-import { fillInMissingTemplateTypes } from "../templateMutating";
-
-export const fixIncompleteImplicitClassGenerics: FileMutator = (request: FileMutationsRequest) =>
- collectMutationsFromNodes(request, ts.isClassLike, visitClassLike);
-
-const visitClassLike = (node: ts.ClassLikeDeclaration, request: FileMutationsRequest): Mutation | undefined => {
- // We'll want a class node that extends some base class
- const extension = getClassExtendsExpression(node);
- if (extension === undefined) {
- return undefined;
- }
-
- // If that base class doesn't include type parameters, there's nothing to fill out
- const baseClass = getBaseClassDeclaration(request, extension);
- if (baseClass === undefined || baseClass.typeParameters === undefined) {
- return undefined;
- }
-
- // If that class declares any templated types, check the node's types assigned as them
- const missingTemplateTypes = findMissingTemplateTypes(request, node, baseClass);
-
- // We can skip performing any mutation if none of the parameter types had missing types
- if (missingTemplateTypes.length === 0 || !missingTemplateTypes.some(isNotUndefined)) {
- return undefined;
- }
-
- // Collect type names to fill in and their corresponding new type declarations
- const { createdTypes, templateTypeNames } = fillInMissingTemplateTypes(request, node, baseClass.typeParameters, missingTemplateTypes);
-
- // Print the new types above the class and fill in the new template types
- return combineMutations(addNewTypeNodes(request, node, createdTypes), addMissingTemplateTypes(extension, templateTypeNames));
+import { Mutation, combineMutations } from "automutate";
+import ts from "typescript";
+
+import { isNotUndefined } from "../../../../../shared/arrays.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../../shared/fileMutator.js";
+import {
+ getBaseClassDeclaration,
+ getClassExtendsExpression,
+} from "../../../../../shared/nodeExtensions.js";
+import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes.js";
+import { addMissingTemplateTypes, addNewTypeNodes } from "../additions.js";
+import { findMissingTemplateTypes } from "../templateCollecting.js";
+import { fillInMissingTemplateTypes } from "../templateMutating.js";
+
+export const fixIncompleteImplicitClassGenerics: FileMutator = (
+ request: FileMutationsRequest,
+) => collectMutationsFromNodes(request, ts.isClassLike, visitClassLike);
+
+const visitClassLike = (
+ node: ts.ClassLikeDeclaration,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // We'll want a class node that extends some base class
+ const extension = getClassExtendsExpression(node);
+ if (extension === undefined) {
+ return undefined;
+ }
+
+ // If that base class doesn't include type parameters, there's nothing to fill out
+ const baseClass = getBaseClassDeclaration(request, extension);
+ if (baseClass?.typeParameters === undefined) {
+ return undefined;
+ }
+
+ // If that class declares any templated types, check the node's types assigned as them
+ const missingTemplateTypes = findMissingTemplateTypes(
+ request,
+ node,
+ baseClass,
+ );
+
+ // We can skip performing any mutation if none of the parameter types had missing types
+ if (
+ missingTemplateTypes.length === 0 ||
+ !missingTemplateTypes.some(isNotUndefined)
+ ) {
+ return undefined;
+ }
+
+ // Collect type names to fill in and their corresponding new type declarations
+ const { createdTypes, templateTypeNames } = fillInMissingTemplateTypes(
+ request,
+ node,
+ baseClass.typeParameters,
+ missingTemplateTypes,
+ );
+
+ // Print the new types above the class and fill in the new template types
+ return combineMutations(
+ addNewTypeNodes(request, node, createdTypes),
+ addMissingTemplateTypes(extension, templateTypeNames),
+ );
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/collectGenericUses.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/collectGenericUses.ts
index 690455a60..182258bd0 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/collectGenericUses.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/collectGenericUses.ts
@@ -1,88 +1,100 @@
-import * as ts from "typescript";
-import { getTypeAtLocationIfNotError } from "../../../../../shared/types";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-
-import { GenericClassDetails } from "./getGenericClassDetails";
-import { VariableWithImplicitGeneric } from "./implicitGenericTypes";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../../../../shared/types.js";
+import { GenericClassDetails } from "./getGenericClassDetails.js";
+import { VariableWithImplicitGeneric } from "./implicitGenericTypes.js";
/**
* @returns Map of the names of a class' generic template types to the types passed to them.
*/
export const collectGenericUses = (
- request: FileMutationsRequest,
- node: VariableWithImplicitGeneric,
- genericClassDetails: GenericClassDetails,
+ request: FileMutationsRequest,
+ node: VariableWithImplicitGeneric,
+ genericClassDetails: GenericClassDetails,
): Map | undefined => {
- const references = request.fileInfoCache.getNodeReferencesAsNodes(node);
- if (references === undefined) {
- return undefined;
- }
-
- const assignedParameterTypes = new Map();
-
- const addAssignmentToTypeParameter = (typeParameterName: string, argumentType: ts.Type) => {
- const existing = assignedParameterTypes.get(typeParameterName);
-
- if (existing === undefined) {
- assignedParameterTypes.set(typeParameterName, [argumentType]);
- } else {
- existing.push(argumentType);
- }
- };
-
- // Each reference might contain a call expression to a member of the generic container
- for (const reference of references) {
- if (!ts.isExpressionStatement(reference)) {
- continue;
- }
-
- const callExpression = reference.expression;
- if (!ts.isCallExpression(callExpression)) {
- continue;
- }
-
- const callArguments = callExpression.arguments;
- if (callArguments.length === 0) {
- continue;
- }
-
- const propertyAccessExpression = callExpression.expression;
- if (!ts.isPropertyAccessExpression(propertyAccessExpression)) {
- continue;
- }
-
- // Only look at members that are known to have the generic parameters, like `indexOf(item: T)`
- const memberName = propertyAccessExpression.name.text;
- const memberDetails = genericClassDetails.membersWithGenericParameters.get(memberName);
- if (memberDetails === undefined) {
- continue;
- }
-
- for (const [parameterIndex, { parameterName, parameterType }] of memberDetails) {
- if (parameterIndex >= callArguments.length) {
- continue;
- }
-
- const parameterIndexType = getTypeAtLocationIfNotError(request, callArguments[parameterIndex]);
- if (parameterIndexType === undefined) {
- continue;
- }
-
- // For each parameter passed to the generic use, we'll record its assignment type
- addAssignmentToTypeParameter(parameterName, parameterIndexType);
-
- // If the parameter is a rest parameter, also add assignment types for any following arguments
- if (parameterType.parent.dotDotDotToken !== undefined) {
- for (const callArgument of callArguments.slice(parameterIndex + 1)) {
- const callArgumentType = getTypeAtLocationIfNotError(request, callArgument);
- if (callArgumentType !== undefined) {
- addAssignmentToTypeParameter(parameterName, callArgumentType);
- }
- }
- }
- }
- }
-
- return assignedParameterTypes;
+ const references = request.fileInfoCache.getNodeReferencesAsNodes(node);
+ if (references === undefined) {
+ return undefined;
+ }
+
+ const assignedParameterTypes = new Map();
+
+ const addAssignmentToTypeParameter = (
+ typeParameterName: string,
+ argumentType: ts.Type,
+ ) => {
+ const existing = assignedParameterTypes.get(typeParameterName);
+
+ if (existing === undefined) {
+ assignedParameterTypes.set(typeParameterName, [argumentType]);
+ } else {
+ existing.push(argumentType);
+ }
+ };
+
+ // Each reference might contain a call expression to a member of the generic container
+ for (const reference of references) {
+ if (!ts.isExpressionStatement(reference)) {
+ continue;
+ }
+
+ const callExpression = reference.expression;
+ if (!ts.isCallExpression(callExpression)) {
+ continue;
+ }
+
+ const callArguments = callExpression.arguments;
+ if (callArguments.length === 0) {
+ continue;
+ }
+
+ const propertyAccessExpression = callExpression.expression;
+ if (!ts.isPropertyAccessExpression(propertyAccessExpression)) {
+ continue;
+ }
+
+ // Only look at members that are known to have the generic parameters, like `indexOf(item: T)`
+ const memberName = propertyAccessExpression.name.text;
+ const memberDetails =
+ genericClassDetails.membersWithGenericParameters.get(memberName);
+ if (memberDetails === undefined) {
+ continue;
+ }
+
+ for (const [
+ parameterIndex,
+ { parameterName, parameterType },
+ ] of memberDetails) {
+ if (parameterIndex >= callArguments.length) {
+ continue;
+ }
+
+ const parameterIndexType = getTypeAtLocationIfNotError(
+ request,
+ callArguments[parameterIndex],
+ );
+ if (parameterIndexType === undefined) {
+ continue;
+ }
+
+ // For each parameter passed to the generic use, we'll record its assignment type
+ addAssignmentToTypeParameter(parameterName, parameterIndexType);
+
+ // If the parameter is a rest parameter, also add assignment types for any following arguments
+ if (parameterType.parent.dotDotDotToken !== undefined) {
+ for (const callArgument of callArguments.slice(parameterIndex + 1)) {
+ const callArgumentType = getTypeAtLocationIfNotError(
+ request,
+ callArgument,
+ );
+ if (callArgumentType !== undefined) {
+ addAssignmentToTypeParameter(parameterName, callArgumentType);
+ }
+ }
+ }
+ }
+ }
+
+ return assignedParameterTypes;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/createExplicitGenericType.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/createExplicitGenericType.ts
index daede0473..632942f5e 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/createExplicitGenericType.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/createExplicitGenericType.ts
@@ -1,90 +1,107 @@
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { joinIntoGenericType } from "../../../../../mutations/generics";
-import { isTypeArgumentsType } from "../../../../../shared/typeNodes";
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-
-import { GenericClassDetails } from "./getGenericClassDetails";
-import { VariableWithImplicitGeneric } from "./implicitGenericTypes";
+import { joinIntoGenericType } from "../../../../../mutations/generics.js";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
+import { isTypeArgumentsType } from "../../../../../shared/typeNodes.js";
+import { GenericClassDetails } from "./getGenericClassDetails.js";
+import { VariableWithImplicitGeneric } from "./implicitGenericTypes.js";
/**
* @returns Test insertion mutation if a generic type should be made explicit.
*/
export const createExplicitGenericType = (
- request: FileMutationsRequest,
- node: VariableWithImplicitGeneric,
- genericClassDetails: GenericClassDetails,
- allAssignedGenericTypes: Map,
+ request: FileMutationsRequest,
+ node: VariableWithImplicitGeneric,
+ genericClassDetails: GenericClassDetails,
+ allAssignedGenericTypes: Map,
) => {
- const allTypeArgumentTypes: ts.Type[][] = [];
-
- // For each type parameter, collect the types assigned to it
- for (const typeParameterName of genericClassDetails.typeParameterNames) {
- const typeArgumentTypes = allAssignedGenericTypes.get(typeParameterName);
- if (typeArgumentTypes === undefined) {
- return undefined;
- }
-
- allTypeArgumentTypes.push(typeArgumentTypes);
- }
-
- // If we couldn't find any types, there's nothing to do here
- if (allTypeArgumentTypes.length === 0) {
- return undefined;
- }
-
- // If the node's inferred generic type already contains the later types, don't change anything
- if (allTypeArgumentTypesMatch(request, allTypeArgumentTypes, node)) {
- return undefined;
- }
-
- // Convert the container and its type assignments into a labeled type
- const joinedGenericType = joinIntoGenericType(request, genericClassDetails.containerType, allTypeArgumentTypes);
- if (joinedGenericType === undefined) {
- return undefined;
- }
-
- return {
- insertion: `: ${joinedGenericType}`,
- range: {
- begin: node.name.end,
- },
- type: "text-insert",
- };
+ const allTypeArgumentTypes: ts.Type[][] = [];
+
+ // For each type parameter, collect the types assigned to it
+ for (const typeParameterName of genericClassDetails.typeParameterNames) {
+ const typeArgumentTypes = allAssignedGenericTypes.get(typeParameterName);
+ if (typeArgumentTypes === undefined) {
+ return undefined;
+ }
+
+ allTypeArgumentTypes.push(typeArgumentTypes);
+ }
+
+ // If we couldn't find any types, there's nothing to do here
+ if (allTypeArgumentTypes.length === 0) {
+ return undefined;
+ }
+
+ // If the node's inferred generic type already contains the later types, don't change anything
+ if (allTypeArgumentTypesMatch(request, allTypeArgumentTypes, node)) {
+ return undefined;
+ }
+
+ // Convert the container and its type assignments into a labeled type
+ const joinedGenericType = joinIntoGenericType(
+ request,
+ genericClassDetails.containerType,
+ allTypeArgumentTypes,
+ );
+
+ return {
+ insertion: `: ${joinedGenericType}`,
+ range: {
+ begin: node.name.end,
+ },
+ type: "text-insert",
+ };
};
-const allTypeArgumentTypesMatch = (request: FileMutationsRequest, allTypeArgumentTypes: ts.Type[][], node: ts.Node) => {
- const typeChecker = request.services.program.getTypeChecker();
-
- // If the original type doesn't have type arguments, bail out immediately
- const originalType = typeChecker.getTypeAtLocation(node);
- if (!isTypeArgumentsType(originalType)) {
- return false;
- }
-
- // If the implicit type has defaulted to any, ignore it (assume a non-match)
- if (originalType.typeArguments.some((typeArgument) => tsutils.isTypeFlagSet(typeArgument, ts.TypeFlags.Any))) {
- return false;
- }
-
- // If the implicit types are all unknown, assume a non-match for being unknown
- if (originalType.typeArguments.every((typeArgument) => tsutils.isTypeFlagSet(typeArgument, ts.TypeFlags.Unknown))) {
- return false;
- }
-
- // Otherwise, check that all type arguments sub-types match the original type at the same index
- for (const typeArgumentTypes of allTypeArgumentTypes) {
- if (typeArgumentTypes.length !== originalType.typeArguments.length) {
- return false;
- }
-
- for (let i = 0; i < typeArgumentTypes.length; i += 1) {
- if (!typeChecker.isTypeAssignableTo(typeArgumentTypes[i], originalType.typeArguments[i])) {
- return false;
- }
- }
- }
-
- return true;
+const allTypeArgumentTypesMatch = (
+ request: FileMutationsRequest,
+ allTypeArgumentTypes: ts.Type[][],
+ node: ts.Node,
+) => {
+ const typeChecker = request.services.program.getTypeChecker();
+
+ // If the original type doesn't have type arguments, bail out immediately
+ const originalType = typeChecker.getTypeAtLocation(node);
+ if (!isTypeArgumentsType(originalType)) {
+ return false;
+ }
+
+ // If the implicit type has defaulted to any, ignore it (assume a non-match)
+ if (
+ originalType.typeArguments.some((typeArgument) =>
+ tsutils.isTypeFlagSet(typeArgument, ts.TypeFlags.Any),
+ )
+ ) {
+ return false;
+ }
+
+ // If the implicit types are all unknown, assume a non-match for being unknown
+ if (
+ originalType.typeArguments.every((typeArgument) =>
+ tsutils.isTypeFlagSet(typeArgument, ts.TypeFlags.Unknown),
+ )
+ ) {
+ return false;
+ }
+
+ // Otherwise, check that all type arguments sub-types match the original type at the same index
+ for (const typeArgumentTypes of allTypeArgumentTypes) {
+ if (typeArgumentTypes.length !== originalType.typeArguments.length) {
+ return false;
+ }
+
+ for (let i = 0; i < typeArgumentTypes.length; i += 1) {
+ if (
+ !typeChecker.isTypeAssignableTo(
+ typeArgumentTypes[i],
+ originalType.typeArguments[i],
+ )
+ ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/getGenericClassDetails.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/getGenericClassDetails.ts
index 138eb0e69..c069f2883 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/getGenericClassDetails.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/getGenericClassDetails.ts
@@ -1,151 +1,183 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { getTypeAtLocationIfNotError, typeHasLocalTypeParameters } from "../../../../../shared/types";
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-
-import { VariableWithImplicitGeneric } from "./implicitGenericTypes";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
+import {
+ getTypeAtLocationIfNotError,
+ typeHasLocalTypeParameters,
+} from "../../../../../shared/types.js";
+import { VariableWithImplicitGeneric } from "./implicitGenericTypes.js";
/**
* For a generic type, its type parameter names and member functions that use them.
*/
export interface GenericClassDetails {
- /**
- * Type of the underlying class (often an interface).
- */
- containerType: ts.InterfaceType;
-
- /**
- * Maps from member names to the parameter index and types associated with a type parameter.
- * For example, in Array, that would be `{ "push" => { 0 => (T) } }`
- */
- membersWithGenericParameters: Map>;
-
- /**
- * Ordered names of (local) type parameters on the type.
- */
- typeParameterNames: ReadonlyArray;
+ /**
+ * Type of the underlying class (often an interface).
+ */
+ containerType: ts.InterfaceType;
+
+ /**
+ * Maps from member names to the parameter index and types associated with a type parameter.
+ * For example, in Array, that would be `{ "push" => { 0 => (T) } }`
+ */
+ membersWithGenericParameters: Map<
+ string,
+ Map
+ >;
+
+ /**
+ * Ordered names of (local) type parameters on the type.
+ */
+ typeParameterNames: readonly string[];
}
export type ParameterTypeNode = ts.TypeNode & {
- parent: ts.ParameterDeclaration;
+ parent: ts.ParameterDeclaration;
};
export interface ParameterTypeNodeSummary {
- parameterName: string;
- parameterType: ParameterTypeNode;
+ parameterName: string;
+ parameterType: ParameterTypeNode;
}
-export const getGenericClassDetails = (request: FileMutationsRequest, node: VariableWithImplicitGeneric) => {
- // Get the backing type of the variable's initializer
- const initializerType = getTypeAtLocationIfNotError(request, node.initializer);
- const initializerSymbol = initializerType?.getSymbol();
- if (initializerSymbol === undefined) {
- return undefined;
- }
-
- // We'll be looking at the list of members available on that type
- const initializerMembers = initializerSymbol.members;
- if (initializerMembers === undefined || initializerMembers.size === 0) {
- return undefined;
- }
-
- // Only care about types that have at least one (local?) type parameter
- const typeChecker = request.services.program.getTypeChecker();
- const containerType = typeChecker.getDeclaredTypeOfSymbol(initializerSymbol);
- if (
- !typeHasLocalTypeParameters(containerType) ||
- containerType.localTypeParameters === undefined ||
- containerType.localTypeParameters.length === 0
- ) {
- return undefined;
- }
-
- // Create the summary of type parameter names with relevant member functions
- return fillMembersWithGenericParameters(
- containerType,
- containerType.localTypeParameters.map((typeParameter) => typeParameter.symbol.name),
- initializerMembers,
- );
+export const getGenericClassDetails = (
+ request: FileMutationsRequest,
+ node: VariableWithImplicitGeneric,
+) => {
+ // Get the backing type of the variable's initializer
+ const initializerType = getTypeAtLocationIfNotError(
+ request,
+ node.initializer,
+ );
+ const initializerSymbol = initializerType?.getSymbol();
+ if (initializerSymbol === undefined) {
+ return undefined;
+ }
+
+ // We'll be looking at the list of members available on that type
+ const initializerMembers = initializerSymbol.members;
+ if (initializerMembers === undefined || initializerMembers.size === 0) {
+ return undefined;
+ }
+
+ // Only care about types that have at least one (local?) type parameter
+ const typeChecker = request.services.program.getTypeChecker();
+ const containerType = typeChecker.getDeclaredTypeOfSymbol(initializerSymbol);
+ if (
+ !typeHasLocalTypeParameters(containerType) ||
+ containerType.localTypeParameters === undefined ||
+ containerType.localTypeParameters.length === 0
+ ) {
+ return undefined;
+ }
+
+ // Create the summary of type parameter names with relevant member functions
+ return fillMembersWithGenericParameters(
+ containerType,
+ containerType.localTypeParameters.map(
+ (typeParameter) => typeParameter.symbol.name,
+ ),
+ initializerMembers,
+ );
};
/**
* @returns For the container type, type parameter names with member functions that use them
*/
const fillMembersWithGenericParameters = (
- containerType: ts.InterfaceType,
- typeParameterNames: ReadonlyArray,
- initializerMembers: ts.UnderscoreEscapedMap,
+ containerType: ts.InterfaceType,
+ typeParameterNames: readonly string[],
+ initializerMembers: Map,
): GenericClassDetails => {
- const membersWithGenericParameters = new Map>();
- const typeParameterNamesSet = new Set(typeParameterNames);
-
- /**
- * If a parameter's type name is a reference to a local parameter, adds it to the mapping.
- */
- const setMemberWithGenericParameterIfMatched = (
- memberName: string,
- parameterIndex: number,
- typeName: ts.Node,
- parameterType: ParameterTypeNode,
- ) => {
- if (!ts.isIdentifier(typeName)) {
- return;
- }
-
- const parameterName = typeName.text;
- if (!typeParameterNamesSet.has(parameterName)) {
- return;
- }
-
- const existing = membersWithGenericParameters.get(memberName);
- const summary = { parameterName, parameterType };
-
- if (existing === undefined) {
- membersWithGenericParameters.set(memberName, new Map([[parameterIndex, summary]]));
- } else {
- existing.set(parameterIndex, summary);
- }
- };
-
- // We'll be looking through all members declared on the backing initializer's type
- initializerMembers.forEach((memberSymbol) => {
- // Skip the member if it's the type itself, as that might be included in .members
- const memberName = memberSymbol.name;
- if (typeParameterNamesSet.has(memberName)) {
- return;
- }
-
- // We only care about parameters that can receive instances of the generic type
- const { valueDeclaration } = memberSymbol;
- if (!ts.isFunctionLike(valueDeclaration)) {
- return;
- }
-
- for (let i = 0; i < valueDeclaration.parameters.length; i += 1) {
- const parameter = valueDeclaration.parameters[i];
- const parameterType = parameter.type as ParameterTypeNode | undefined;
- if (parameterType === undefined) {
- continue;
- }
-
- // Case: indexOf(item: T)
- // Add the parameter if the direct T type matches
- if (ts.isTypeReferenceNode(parameterType)) {
- setMemberWithGenericParameterIfMatched(memberName, i, parameterType.typeName, parameterType);
- continue;
- }
-
- // Case: push(...items: T[])
- // Add the parameter if the T within the array type matches
- if (ts.isArrayTypeNode(parameterType) && ts.isTypeReferenceNode(parameterType.elementType)) {
- setMemberWithGenericParameterIfMatched(memberName, i, parameterType.elementType.typeName, parameterType);
- continue;
- }
-
- // There could probably be more cases here, such as `concat(...items: ConcatArray[])`,
- // For now the `item: T` and `...items: T[]` cases capture most uses of built-in generics
- }
- });
-
- return { containerType, membersWithGenericParameters, typeParameterNames };
+ const membersWithGenericParameters = new Map<
+ string,
+ Map
+ >();
+ const typeParameterNamesSet = new Set(typeParameterNames);
+
+ /**
+ * If a parameter's type name is a reference to a local parameter, adds it to the mapping.
+ */
+ const setMemberWithGenericParameterIfMatched = (
+ memberName: string,
+ parameterIndex: number,
+ typeName: ts.Node,
+ parameterType: ParameterTypeNode,
+ ) => {
+ if (!ts.isIdentifier(typeName)) {
+ return;
+ }
+
+ const parameterName = typeName.text;
+ if (!typeParameterNamesSet.has(parameterName)) {
+ return;
+ }
+
+ const existing = membersWithGenericParameters.get(memberName);
+ const summary = { parameterName, parameterType };
+
+ if (existing === undefined) {
+ membersWithGenericParameters.set(
+ memberName,
+ new Map([[parameterIndex, summary]]),
+ );
+ } else {
+ existing.set(parameterIndex, summary);
+ }
+ };
+
+ // We'll be looking through all members declared on the backing initializer's type
+ initializerMembers.forEach((memberSymbol) => {
+ // Skip the member if it's the type itself, as that might be included in .members
+ const memberName = memberSymbol.name;
+ if (typeParameterNamesSet.has(memberName)) {
+ return;
+ }
+
+ // We only care about parameters that can receive instances of the generic type
+ const { valueDeclaration } = memberSymbol;
+ if (!ts.isFunctionLike(valueDeclaration)) {
+ return;
+ }
+
+ for (let i = 0; i < valueDeclaration.parameters.length; i += 1) {
+ const parameter = valueDeclaration.parameters[i];
+ const parameterType = parameter.type as ParameterTypeNode | undefined;
+ if (parameterType === undefined) {
+ continue;
+ }
+
+ // Case: indexOf(item: T)
+ // Add the parameter if the direct T type matches
+ if (ts.isTypeReferenceNode(parameterType)) {
+ setMemberWithGenericParameterIfMatched(
+ memberName,
+ i,
+ parameterType.typeName,
+ parameterType,
+ );
+ continue;
+ }
+
+ // Case: push(...items: T[])
+ // Add the parameter if the T within the array type matches
+ if (
+ ts.isArrayTypeNode(parameterType) &&
+ ts.isTypeReferenceNode(parameterType.elementType)
+ ) {
+ setMemberWithGenericParameterIfMatched(
+ memberName,
+ i,
+ parameterType.elementType.typeName,
+ parameterType,
+ );
+ continue;
+ }
+
+ // There could probably be more cases here, such as `concat(...items: ConcatArray[])`,
+ // For now the `item: T` and `...items: T[]` cases capture most uses of built-in generics
+ }
+ });
+
+ return { containerType, membersWithGenericParameters, typeParameterNames };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/implicitGenericTypes.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/implicitGenericTypes.ts
index adaa8d1c9..23318bd7c 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/implicitGenericTypes.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/implicitGenericTypes.ts
@@ -1,33 +1,37 @@
-import * as ts from "typescript";
+import ts from "typescript";
export type VariableWithImplicitGeneric = ts.VariableDeclaration & {
- initializer: GenericCapableInitializer;
- type: undefined;
+ initializer: GenericCapableInitializer;
+ type: undefined;
};
type GenericCapableInitializer = ts.ArrayLiteralExpression | ts.NewExpression;
-export const isVariableWithImplicitGeneric = (node: ts.Node): node is VariableWithImplicitGeneric =>
- // We'll be looking at variable declarations...
- ts.isVariableDeclaration(node) &&
- // ...without a predeclared type...
- node.type === undefined &&
- // ...but with an initially declared value...
- node.initializer !== undefined &&
- // ...that's a value we know can have a generic added
- isGenericCapableInitializer(node.initializer);
+export const isVariableWithImplicitGeneric = (
+ node: ts.Node,
+): node is VariableWithImplicitGeneric =>
+ // We'll be looking at variable declarations...
+ ts.isVariableDeclaration(node) &&
+ // ...without a predeclared type...
+ node.type === undefined &&
+ // ...but with an initially declared value...
+ node.initializer !== undefined &&
+ // ...that's a value we know can have a generic added
+ isGenericCapableInitializer(node.initializer);
-const isGenericCapableInitializer = (initializer: ts.Expression): initializer is GenericCapableInitializer => {
- // Array literals can always be generic
- if (ts.isArrayLiteralExpression(initializer)) {
- return true;
- }
+const isGenericCapableInitializer = (
+ initializer: ts.Expression,
+): initializer is GenericCapableInitializer => {
+ // Array literals can always be generic
+ if (ts.isArrayLiteralExpression(initializer)) {
+ return true;
+ }
- // New expressions are only valid if they don't already declare generics
- if (ts.isNewExpression(initializer)) {
- return initializer.typeArguments === undefined;
- }
+ // New expressions are only valid if they don't already declare generics
+ if (ts.isNewExpression(initializer)) {
+ return initializer.typeArguments === undefined;
+ }
- // So far, no other initializers are known to be generic capable
- return false;
+ // So far, no other initializers are known to be generic capable
+ return false;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/index.ts
index 58be11f18..c2f2a47c3 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/fixIncompleteImplicitVariableGenerics/index.ts
@@ -1,29 +1,52 @@
-import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../../shared/fileMutator";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes.js";
+import { collectGenericUses } from "./collectGenericUses.js";
+import { createExplicitGenericType } from "./createExplicitGenericType.js";
+import { getGenericClassDetails } from "./getGenericClassDetails.js";
+import {
+ VariableWithImplicitGeneric,
+ isVariableWithImplicitGeneric,
+} from "./implicitGenericTypes.js";
-import { collectGenericUses } from "./collectGenericUses";
-import { createExplicitGenericType } from "./createExplicitGenericType";
-import { getGenericClassDetails } from "./getGenericClassDetails";
-import { isVariableWithImplicitGeneric, VariableWithImplicitGeneric } from "./implicitGenericTypes";
+export const fixIncompleteImplicitVariableGenerics: FileMutator = (
+ request: FileMutationsRequest,
+) =>
+ collectMutationsFromNodes(
+ request,
+ isVariableWithImplicitGeneric,
+ visitVariableWithImplicitGeneric,
+ );
-export const fixIncompleteImplicitVariableGenerics: FileMutator = (request: FileMutationsRequest) =>
- collectMutationsFromNodes(request, isVariableWithImplicitGeneric, visitVariableWithImplicitGeneric);
+const visitVariableWithImplicitGeneric = (
+ node: VariableWithImplicitGeneric,
+ request: FileMutationsRequest,
+) => {
+ // Get the type of class the variable is an instance of, such as [] (Array) or Map
+ // If the variable's class didn't have generics, we can ignore this
+ const genericClassDetails = getGenericClassDetails(request, node);
+ if (genericClassDetails === undefined) {
+ return undefined;
+ }
-const visitVariableWithImplicitGeneric = (node: VariableWithImplicitGeneric, request: FileMutationsRequest) => {
- // Get the type of class the variable is an instance of, such as [] (Array) or Map
- // If the variable's class didn't have generics, we can ignore this
- const genericClassDetails = getGenericClassDetails(request, node);
- if (genericClassDetails === undefined) {
- return undefined;
- }
+ // Find places where the node was either assigned a known type or its method was called with a type
+ // If the node is never used with a (non-any) type, there's nothing we can (or would want) to do
+ const assignedGenericTypes = collectGenericUses(
+ request,
+ node,
+ genericClassDetails,
+ );
+ if (assignedGenericTypes === undefined || assignedGenericTypes.size === 0) {
+ return undefined;
+ }
- // Find places where the node was either assigned a known type or its method was called with a type
- // If the node is never used with a (non-any) type, there's nothing we can (or would want) to do
- const assignedGenericTypes = collectGenericUses(request, node, genericClassDetails);
- if (assignedGenericTypes === undefined || assignedGenericTypes.size === 0) {
- return undefined;
- }
-
- // Combine those type uses into a new explicit generic type on the node
- return createExplicitGenericType(request, node, genericClassDetails, assignedGenericTypes);
+ // Combine those type uses into a new explicit generic type on the node
+ return createExplicitGenericType(
+ request,
+ node,
+ genericClassDetails,
+ assignedGenericTypes,
+ );
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/index.ts
index 8b467e0d8..0c6da0929 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/index.ts
@@ -1,11 +1,18 @@
-import { findFirstMutations } from "../../../../shared/runtime";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../../shared/runtime.js";
+import { fixIncompleteImplicitClassGenerics } from "./fixIncompleteImplicitClassGenerics/index.js";
+import { fixIncompleteImplicitVariableGenerics } from "./fixIncompleteImplicitVariableGenerics/index.js";
-import { fixIncompleteImplicitClassGenerics } from "./fixIncompleteImplicitClassGenerics";
-import { fixIncompleteImplicitVariableGenerics } from "./fixIncompleteImplicitVariableGenerics";
-
-export const fixIncompleteImplicitGenerics: FileMutator = (request: FileMutationsRequest) =>
- findFirstMutations(request, [
- ["fixIncompleteImplicitClassGenerics", fixIncompleteImplicitClassGenerics],
- ["fixIncompleteImplicitVariableGenerics", fixIncompleteImplicitVariableGenerics],
- ]);
+export const fixIncompleteImplicitGenerics: FileMutator = (
+ request: FileMutationsRequest,
+) =>
+ findFirstMutations(request, [
+ ["fixIncompleteImplicitClassGenerics", fixIncompleteImplicitClassGenerics],
+ [
+ "fixIncompleteImplicitVariableGenerics",
+ fixIncompleteImplicitVariableGenerics,
+ ],
+ ]);
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateCollecting.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateCollecting.ts
index e396bae80..1abd3650b 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateCollecting.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateCollecting.ts
@@ -1,223 +1,279 @@
-import * as ts from "typescript";
-
-import { AssignedTypesByName, AssignedTypeValue, joinAssignedTypesByName } from "../../../../mutations/assignments";
-import { getCallExpressionType } from "../../../../shared/calls";
-import { getStaticNameOfProperty } from "../../../../shared/names";
-import { isNodeAssigningBinaryExpression, isNodeWithinNode } from "../../../../shared/nodes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
-
-import { collectTypeParameterReferences } from "./collectTypeParameterReferences";
+import ts from "typescript";
+
+import {
+ AssignedTypeValue,
+ AssignedTypesByName,
+ joinAssignedTypesByName,
+} from "../../../../mutations/assignments.js";
+import { getCallExpressionType } from "../../../../shared/calls.js";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { getStaticNameOfProperty } from "../../../../shared/names.js";
+import {
+ isNodeAssigningBinaryExpression,
+ isNodeWithinNode,
+} from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectTypeParameterReferences } from "./collectTypeParameterReferences.js";
export const findMissingTemplateTypes = (
- request: FileMutationsRequest,
- childClass: ts.ClassLikeDeclaration,
- baseClass: ts.ClassLikeDeclaration,
-): (string | AssignedTypesByName | undefined)[] => {
- // If the base class doesn't define any type parameters, we have nothing to do
- const baseTypeParameters = baseClass.typeParameters;
- if (baseTypeParameters === undefined) {
- return [];
- }
-
- const missingTemplateTypes: (string | AssignedTypesByName | undefined)[] = [];
- let i = 0;
-
- // Ignore any type parameters already declared on the class
- if (childClass.heritageClauses !== undefined) {
- for (const heritageClause of childClass.heritageClauses) {
- if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
- for (const heritageType of heritageClause.types) {
- if (heritageType.typeArguments !== undefined) {
- for (i; i < heritageType.typeArguments.length; i += 1) {
- missingTemplateTypes.push(undefined);
- }
- }
- }
- }
- }
- }
-
- // For each remaining base type parameter, collect any extra types not yet declared on it
- // For example, if it defaults to `{ exists: boolean }` but is given `.extra = 1;`, collect `extra: number`
- for (const baseTypeParameter of baseTypeParameters.slice(i)) {
- missingTemplateTypes.push(collectMissingParameterTypes(request, childClass, baseClass, baseTypeParameter));
- }
-
- return missingTemplateTypes;
+ request: FileMutationsRequest,
+ childClass: ts.ClassLikeDeclaration,
+ baseClass: ts.ClassLikeDeclaration,
+): (AssignedTypesByName | string | undefined)[] => {
+ // If the base class doesn't define any type parameters, we have nothing to do
+ const baseTypeParameters = baseClass.typeParameters;
+ if (baseTypeParameters === undefined) {
+ return [];
+ }
+
+ const missingTemplateTypes: (AssignedTypesByName | string | undefined)[] = [];
+ let i = 0;
+
+ // Ignore any type parameters already declared on the class
+ if (childClass.heritageClauses !== undefined) {
+ for (const heritageClause of childClass.heritageClauses) {
+ if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
+ for (const heritageType of heritageClause.types) {
+ if (heritageType.typeArguments !== undefined) {
+ for (i; i < heritageType.typeArguments.length; i += 1) {
+ missingTemplateTypes.push(undefined);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // For each remaining base type parameter, collect any extra types not yet declared on it
+ // For example, if it defaults to `{ exists: boolean }` but is given `.extra = 1;`, collect `extra: number`
+ for (const baseTypeParameter of baseTypeParameters.slice(i)) {
+ missingTemplateTypes.push(
+ collectMissingParameterTypes(
+ request,
+ childClass,
+ baseClass,
+ baseTypeParameter,
+ ),
+ );
+ }
+
+ return missingTemplateTypes;
};
const collectMissingParameterTypes = (
- request: FileMutationsRequest,
- childClass: ts.ClassLikeDeclaration,
- baseClass: ts.ClassLikeDeclaration,
- baseTypeParameter: ts.TypeParameterDeclaration,
-): string | AssignedTypesByName | undefined => {
- // Each usage of the base type parameter might introduce new assigned types
- const typeParameterReferences = collectTypeParameterReferences(request, childClass, baseClass, baseTypeParameter);
- if (typeParameterReferences === undefined) {
- return undefined;
- }
-
- // Collect all types assigned by those uses that don't already exist on the template's default
- const missingAssignedTypeValues = collectMissingAssignedParameterTypes(request, childClass, baseTypeParameter, typeParameterReferences);
-
- // If we found known names for the node, use them as a raw string
- if (missingAssignedTypeValues instanceof Set) {
- return Array.from(missingAssignedTypeValues).join(" | ");
- }
-
- // If we've found nothing, the parameter checks out and shouldn't be filled in
- if (missingAssignedTypeValues.length === 0) {
- return undefined;
- }
-
- // If we've found missing type members, return them to indicate they should be filled in
- return joinAssignedTypesByName(request, missingAssignedTypeValues);
+ request: FileMutationsRequest,
+ childClass: ts.ClassLikeDeclaration,
+ baseClass: ts.ClassLikeDeclaration,
+ baseTypeParameter: ts.TypeParameterDeclaration,
+): AssignedTypesByName | string | undefined => {
+ // Each usage of the base type parameter might introduce new assigned types
+ const typeParameterReferences = collectTypeParameterReferences(
+ request,
+ childClass,
+ baseClass,
+ baseTypeParameter,
+ );
+ if (typeParameterReferences === undefined) {
+ return undefined;
+ }
+
+ // Collect all types assigned by those uses that don't already exist on the template's default
+ const missingAssignedTypeValues = collectMissingAssignedParameterTypes(
+ request,
+ childClass,
+ baseTypeParameter,
+ typeParameterReferences,
+ );
+
+ // If we found known names for the node, use them as a raw string
+ if (missingAssignedTypeValues instanceof Set) {
+ return Array.from(missingAssignedTypeValues).join(" | ");
+ }
+
+ // If we've found nothing, the parameter checks out and shouldn't be filled in
+ if (missingAssignedTypeValues.length === 0) {
+ return undefined;
+ }
+
+ // If we've found missing type members, return them to indicate they should be filled in
+ return joinAssignedTypesByName(request, missingAssignedTypeValues);
};
const collectMissingAssignedParameterTypes = (
- request: FileMutationsRequest,
- childClass: ts.ClassLikeDeclaration,
- baseTypeParameter: ts.TypeParameterDeclaration,
- typeParameterReferences: ts.Node[],
+ request: FileMutationsRequest,
+ childClass: ts.ClassLikeDeclaration,
+ baseTypeParameter: ts.TypeParameterDeclaration,
+ typeParameterReferences: ts.Node[],
) => {
- const knownNames = new Set();
- const assignedTypeValues: AssignedTypeValue[] = [];
- const childClassType = getTypeAtLocationIfNotError(request, childClass);
- if (childClassType === undefined) {
- return knownNames;
- }
-
- const defaultTypeParameterType =
- baseTypeParameter.default === undefined ? undefined : getTypeAtLocationIfNotError(request, baseTypeParameter.default);
-
- for (const typeParameterReference of typeParameterReferences) {
- // For now, we only look at nodes whose usage is declared *within* the child class
- // In theory this could be expanded to check target instances, but that'd be more work...
- // e.g. new ClassWithGeneric().setGenericValue('it is a string');
- if (!isNodeWithinNode(request.sourceFile, typeParameterReference, childClass)) {
- continue;
- }
-
- const discoveredAssignedTypes = collectMissingAssignedTypesOnChildClassNode(
- request,
- childClassType,
- defaultTypeParameterType,
- typeParameterReference,
- );
-
- if (typeof discoveredAssignedTypes === "string") {
- knownNames.add(discoveredAssignedTypes);
- } else if (discoveredAssignedTypes !== undefined) {
- assignedTypeValues.push(discoveredAssignedTypes);
- }
- }
-
- // If we have any number of known names found (e.g. 'string'), use them directly
- // Otherwise use the raw descriptions of what members should go on the types
- return knownNames.size === 0 ? assignedTypeValues : knownNames;
+ const knownNames = new Set();
+ const assignedTypeValues: AssignedTypeValue[] = [];
+ const childClassType = getTypeAtLocationIfNotError(request, childClass);
+ if (childClassType === undefined) {
+ return knownNames;
+ }
+
+ const defaultTypeParameterType =
+ baseTypeParameter.default === undefined
+ ? undefined
+ : getTypeAtLocationIfNotError(request, baseTypeParameter.default);
+
+ for (const typeParameterReference of typeParameterReferences) {
+ // For now, we only look at nodes whose usage is declared *within* the child class
+ // In theory this could be expanded to check target instances, but that'd be more work...
+ // e.g. new ClassWithGeneric().setGenericValue('it is a string');
+ if (
+ !isNodeWithinNode(request.sourceFile, typeParameterReference, childClass)
+ ) {
+ continue;
+ }
+
+ const discoveredAssignedTypes = collectMissingAssignedTypesOnChildClassNode(
+ request,
+ childClassType,
+ defaultTypeParameterType,
+ typeParameterReference,
+ );
+
+ if (typeof discoveredAssignedTypes === "string") {
+ knownNames.add(discoveredAssignedTypes);
+ } else if (discoveredAssignedTypes !== undefined) {
+ assignedTypeValues.push(discoveredAssignedTypes);
+ }
+ }
+
+ // If we have any number of known names found (e.g. 'string'), use them directly
+ // Otherwise use the raw descriptions of what members should go on the types
+ return knownNames.size === 0 ? assignedTypeValues : knownNames;
};
const collectMissingAssignedTypesOnChildClassNode = (
- request: FileMutationsRequest,
- childClassType: ts.Type,
- defaultTypeParameterType: ts.Type | undefined,
- typeParameterReference: ts.Node,
+ request: FileMutationsRequest,
+ childClassType: ts.Type,
+ defaultTypeParameterType: ts.Type | undefined,
+ typeParameterReference: ts.Node,
) => {
- // If the reference is a property declaration with an initial type, use that
- if (ts.isPropertyDeclaration(typeParameterReference)) {
- return collectMissingAssignedTypeOnPropertyDeclaration(request, defaultTypeParameterType, typeParameterReference);
- }
-
- const parentPropertyAccess = typeParameterReference.parent;
-
- // If the parent is a call, treat the reference as a parameter, and use its type directly
- if (ts.isCallOrNewExpression(parentPropertyAccess)) {
- return getMissingAssignedType(request, defaultTypeParameterType, typeParameterReference, true /* asStandaloneProperty */);
- }
-
- // Otherwise, for now, we'll only look at references that directly access the property on some container
- if (!ts.isPropertyAccessExpression(parentPropertyAccess)) {
- return undefined;
- }
-
- // We only care about this node if the instance it's referencing is (or generally is a subtype of) the child class
- const expressionType = getTypeAtLocationIfNotError(request, parentPropertyAccess.expression);
- if (expressionType === undefined || !request.services.program.getTypeChecker().isTypeAssignableTo(expressionType, childClassType)) {
- return undefined;
- }
-
- // If the grandparent is an assigning binary expression, add the right side as a full new type
- if (isNodeAssigningBinaryExpression(parentPropertyAccess.parent)) {
- return getMissingAssignedType(
- request,
- defaultTypeParameterType,
- parentPropertyAccess.parent.right,
- true /* asStandaloneProperty */,
- );
- }
-
- // If we're calling the member reference as a function, grab the perceived function type
- if (ts.isCallExpression(parentPropertyAccess.parent.parent) && ts.isPropertyAccessExpression(parentPropertyAccess.parent)) {
- return {
- name: parentPropertyAccess.parent.name.text,
- type: getCallExpressionType(request, parentPropertyAccess.parent.parent),
- };
- }
-
- // Otherwise we ignore any other types
- // Eventually this will likely expand to types like property access expressions and captured identifier references
- return undefined;
+ // If the reference is a property declaration with an initial type, use that
+ if (ts.isPropertyDeclaration(typeParameterReference)) {
+ return collectMissingAssignedTypeOnPropertyDeclaration(
+ request,
+ defaultTypeParameterType,
+ typeParameterReference,
+ );
+ }
+
+ const parentPropertyAccess = typeParameterReference.parent;
+
+ // If the parent is a call, treat the reference as a parameter, and use its type directly
+ if (ts.isCallOrNewExpression(parentPropertyAccess)) {
+ return getMissingAssignedType(
+ request,
+ defaultTypeParameterType,
+ typeParameterReference,
+ true /* asStandaloneProperty */,
+ );
+ }
+
+ // Otherwise, for now, we'll only look at references that directly access the property on some container
+ if (!ts.isPropertyAccessExpression(parentPropertyAccess)) {
+ return undefined;
+ }
+
+ // We only care about this node if the instance it's referencing is (or generally is a subtype of) the child class
+ const expressionType = getTypeAtLocationIfNotError(
+ request,
+ parentPropertyAccess.expression,
+ );
+ if (
+ expressionType === undefined ||
+ !request.services.program
+ .getTypeChecker()
+ .isTypeAssignableTo(expressionType, childClassType)
+ ) {
+ return undefined;
+ }
+
+ // If the grandparent is an assigning binary expression, add the right side as a full new type
+ if (isNodeAssigningBinaryExpression(parentPropertyAccess.parent)) {
+ return getMissingAssignedType(
+ request,
+ defaultTypeParameterType,
+ parentPropertyAccess.parent.right,
+ true /* asStandaloneProperty */,
+ );
+ }
+
+ // If we're calling the member reference as a function, grab the perceived function type
+ if (
+ ts.isCallExpression(parentPropertyAccess.parent.parent) &&
+ ts.isPropertyAccessExpression(parentPropertyAccess.parent)
+ ) {
+ return {
+ name: parentPropertyAccess.parent.name.text,
+ type: getCallExpressionType(request, parentPropertyAccess.parent.parent),
+ };
+ }
+
+ // Otherwise we ignore any other types
+ // Eventually this will likely expand to types like property access expressions and captured identifier references
+ return undefined;
};
const collectMissingAssignedTypeOnPropertyDeclaration = (
- request: FileMutationsRequest,
- defaultTypeParameterType: ts.Type | undefined,
- typeParameterReference: ts.PropertyDeclaration,
+ request: FileMutationsRequest,
+ defaultTypeParameterType: ts.Type | undefined,
+ typeParameterReference: ts.PropertyDeclaration,
) => {
- // Our happiest case is a member that already has a named type
- if (
- typeParameterReference.type !== undefined &&
- ts.isTypeReferenceNode(typeParameterReference.type) &&
- ts.isIdentifier(typeParameterReference.type.typeName)
- ) {
- return typeParameterReference.type.typeName.escapedText.toString();
- }
-
- // Otherwise, we'll have to manually craft a type for it
- return getMissingAssignedType(request, defaultTypeParameterType, typeParameterReference, /* asStandaloneProperty */ true);
+ // Our happiest case is a member that already has a named type
+ if (
+ typeParameterReference.type !== undefined &&
+ ts.isTypeReferenceNode(typeParameterReference.type) &&
+ ts.isIdentifier(typeParameterReference.type.typeName)
+ ) {
+ return typeParameterReference.type.typeName.escapedText.toString();
+ }
+
+ // Otherwise, we'll have to manually craft a type for it
+ return getMissingAssignedType(
+ request,
+ defaultTypeParameterType,
+ typeParameterReference,
+ /* asStandaloneProperty */ true,
+ );
};
const getMissingAssignedType = (
- request: FileMutationsRequest,
- defaultTypeParameterType: ts.Type | undefined,
- assigningNode: ts.Node,
- asStandaloneProperty: boolean,
+ request: FileMutationsRequest,
+ defaultTypeParameterType: ts.Type | undefined,
+ assigningNode: ts.Node,
+ asStandaloneProperty: boolean,
) => {
- const assigningType = getTypeAtLocationIfNotError(request, assigningNode);
- if (assigningType === undefined) {
- return undefined;
- }
-
- // If the type parameter came with a default, ignore types already equivalent to it
- if (
- defaultTypeParameterType !== undefined &&
- request.services.program.getTypeChecker().isTypeAssignableTo(defaultTypeParameterType, assigningType)
- ) {
- return undefined;
- }
-
- // Nodes that reach here are either 'standalone' declarations (the full type) or members thereof...
- // For a full type, go through the normal hoops to figure out its name
- if (asStandaloneProperty) {
- const standaloneType = getTypeAtLocationIfNotError(request, assigningNode);
- return standaloneType === undefined ? undefined : request.services.printers.type(standaloneType);
- }
-
- // For a property, just grab the basic name and type, so we can join them all together later
- return {
- name: getStaticNameOfProperty(assigningNode),
- type: assigningType,
- };
+ const assigningType = getTypeAtLocationIfNotError(request, assigningNode);
+ if (assigningType === undefined) {
+ return undefined;
+ }
+
+ // If the type parameter came with a default, ignore types already equivalent to it
+ if (
+ defaultTypeParameterType !== undefined &&
+ request.services.program
+ .getTypeChecker()
+ .isTypeAssignableTo(defaultTypeParameterType, assigningType)
+ ) {
+ return undefined;
+ }
+
+ // Nodes that reach here are either 'standalone' declarations (the full type) or members thereof...
+ // For a full type, go through the normal hoops to figure out its name
+ if (asStandaloneProperty) {
+ const standaloneType = getTypeAtLocationIfNotError(request, assigningNode);
+ return standaloneType === undefined
+ ? undefined
+ : request.services.printers.type(standaloneType);
+ }
+
+ // For a property, just grab the basic name and type, so we can join them all together later
+ return {
+ name: getStaticNameOfProperty(assigningNode),
+ type: assigningType,
+ };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateMutating.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateMutating.ts
index bb3bd797e..b4f235b9f 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateMutating.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/templateMutating.ts
@@ -1,82 +1,110 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { AssignedTypesByName, joinAssignedTypesByName } from "../../../../mutations/assignments";
-import { createDeclarationForTypeSummaries } from "../../../../mutations/creations/creationMutations";
-import { summarizeAllAssignedTypes } from "../../../../mutations/expansions/summarization";
-import { getFriendlyTypeParameterDeclarationName, getPerceivedNameOfClass } from "../../../../mutations/naming";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
+import {
+ AssignedTypesByName,
+ joinAssignedTypesByName,
+} from "../../../../mutations/assignments.js";
+import { createDeclarationForTypeSummaries } from "../../../../mutations/creations/creationMutations.js";
+import { summarizeAllAssignedTypes } from "../../../../mutations/expansions/summarization.js";
+import {
+ getFriendlyTypeParameterDeclarationName,
+ getPerceivedNameOfClass,
+} from "../../../../mutations/naming.js";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
export const fillInMissingTemplateTypes = (
- request: FileMutationsRequest,
- childClass: ts.ClassLikeDeclaration,
- baseTypeParameters: ts.NodeArray,
- templateTypeLists: (string | AssignedTypesByName | undefined)[],
+ request: FileMutationsRequest,
+ childClass: ts.ClassLikeDeclaration,
+ baseTypeParameters: ts.NodeArray,
+ templateTypeLists: (AssignedTypesByName | string | undefined)[],
) => {
- const createdTypes: string[] = [];
- const templateTypeNames: string[] = [];
- const childClassName = getPerceivedNameOfClass(request, childClass);
+ const createdTypes: string[] = [];
+ const templateTypeNames: string[] = [];
+ const childClassName = getPerceivedNameOfClass(request, childClass);
- // Template types will be marked on the node up through the last missing type
- for (let i = 0; i < templateTypeLists.length; i += 1) {
- const templateTypes = templateTypeLists[i];
+ // Template types will be marked on the node up through the last missing type
+ for (let i = 0; i < templateTypeLists.length; i += 1) {
+ const templateTypes = templateTypeLists[i];
- // If the template type is fine on the node but missing, use the default from the generic
- // Example: a React component's props are {} but its state needs a new type
- if (templateTypes === undefined) {
- const defaultTemplateValue = findDefaultTemplateValue(request, baseTypeParameters[i]);
- if (defaultTemplateValue !== undefined) {
- templateTypeNames.push(defaultTemplateValue);
- }
- continue;
- }
+ // If the template type is fine on the node but missing, use the default from the generic
+ // Example: a React component's props are {} but its state needs a new type
+ if (templateTypes === undefined) {
+ const defaultTemplateValue = findDefaultTemplateValue(
+ request,
+ baseTypeParameters[i],
+ );
+ if (defaultTemplateValue !== undefined) {
+ templateTypeNames.push(defaultTemplateValue);
+ }
- // If the template type is already a known name, directly use it
- if (typeof templateTypes === "string") {
- templateTypeNames.push(templateTypes);
- continue;
- }
+ continue;
+ }
- // In this case, the template type is missing: create a new type to fill the missing template type
- // That new type will need a name, which we'll generate from the class and relevant type parameter
- const newTemplateTypeName = createTemplateTypeName(childClassName, baseTypeParameters, baseTypeParameters[i]);
+ // If the template type is already a known name, directly use it
+ if (typeof templateTypes === "string") {
+ templateTypeNames.push(templateTypes);
+ continue;
+ }
- // Properties on that template type are collected from uses of the type in the node
- const assignedTypeValues = Array.from(templateTypes).map(([name, type]) => ({ name, type }));
- const allAssignedTypes = joinAssignedTypesByName(request, assignedTypeValues);
- const newType = createDeclarationForTypeSummaries(
- request,
- undefined /* enclosingDeclaration */,
- newTemplateTypeName,
- summarizeAllAssignedTypes(request, [allAssignedTypes]),
- );
+ // In this case, the template type is missing: create a new type to fill the missing template type
+ // That new type will need a name, which we'll generate from the class and relevant type parameter
+ const newTemplateTypeName = createTemplateTypeName(
+ childClassName,
+ baseTypeParameters,
+ baseTypeParameters[i],
+ );
- createdTypes.push(newType);
- templateTypeNames.push(newTemplateTypeName);
- }
+ // Properties on that template type are collected from uses of the type in the node
+ const assignedTypeValues = Array.from(templateTypes).map(
+ ([name, type]) => ({ name, type }),
+ );
+ const allAssignedTypes = joinAssignedTypesByName(
+ request,
+ assignedTypeValues,
+ );
+ const newType = createDeclarationForTypeSummaries(
+ request,
+ undefined /* enclosingDeclaration */,
+ newTemplateTypeName,
+ summarizeAllAssignedTypes(request, [allAssignedTypes]),
+ );
- return { createdTypes, templateTypeNames };
+ createdTypes.push(newType);
+ templateTypeNames.push(newTemplateTypeName);
+ }
+
+ return { createdTypes, templateTypeNames };
};
-const findDefaultTemplateValue = (request: FileMutationsRequest, baseTypeParameter: ts.TypeParameterDeclaration) => {
- if (baseTypeParameter.default === undefined) {
- return "{}";
- }
+const findDefaultTemplateValue = (
+ request: FileMutationsRequest,
+ baseTypeParameter: ts.TypeParameterDeclaration,
+) => {
+ if (baseTypeParameter.default === undefined) {
+ return "{}";
+ }
- const baseTypeDefault = getTypeAtLocationIfNotError(request, baseTypeParameter.default);
- if (baseTypeDefault === undefined) {
- return undefined;
- }
+ const baseTypeDefault = getTypeAtLocationIfNotError(
+ request,
+ baseTypeParameter.default,
+ );
+ if (baseTypeDefault === undefined) {
+ return undefined;
+ }
- return request.services.printers.type(baseTypeDefault);
+ return request.services.printers.type(baseTypeDefault);
};
const createTemplateTypeName = (
- childClassName: string,
- baseTypeParameters: ts.NodeArray,
- baseTypeParameter: ts.TypeParameterDeclaration,
+ childClassName: string,
+ baseTypeParameters: ts.NodeArray,
+ baseTypeParameter: ts.TypeParameterDeclaration,
) => {
- const friendlyName = getFriendlyTypeParameterDeclarationName(baseTypeParameters, baseTypeParameter);
+ const friendlyName = getFriendlyTypeParameterDeclarationName(
+ baseTypeParameters,
+ baseTypeParameter,
+ );
- return childClassName + friendlyName[0].toUpperCase() + friendlyName.slice(1);
+ return childClassName + friendlyName[0].toUpperCase() + friendlyName.slice(1);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/collectGenericNodeReferences.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/collectGenericNodeReferences.ts
index 2cdccd860..d0228db78 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/collectGenericNodeReferences.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/collectGenericNodeReferences.ts
@@ -1,229 +1,290 @@
-import * as ts from "typescript";
+import ts from "typescript";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
import {
- getIdentifyingTypeLiteralParent,
- isNodeWithDefinedTypeArguments,
- isNodeWithDefinedTypeParameters,
- isNodeWithIdentifierName,
-} from "../../../../shared/nodeTypes";
-import { isTypeArgumentsType } from "../../../../shared/typeNodes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
-
-export type InterfaceOrTypeLiteral = ts.InterfaceDeclaration | ts.TypeLiteralNode;
-
-export const collectGenericNodeReferences = (request: FileMutationsRequest, node: InterfaceOrTypeLiteral) => {
- // Find all generic references purported to be of this type
- const referencingNodes = collectDirectNodeReferences(request, node);
- if (referencingNodes === undefined) {
- return undefined;
- }
-
- // For any reference that uses the node as a generic type,
- // expand the node's references to include references to that generic type
- return expandReferencesForGenericTypes(request, node, referencingNodes);
+ getIdentifyingTypeLiteralParent,
+ isNodeWithDefinedTypeArguments,
+ isNodeWithDefinedTypeParameters,
+ isNodeWithIdentifierName,
+} from "../../../../shared/nodeTypes.js";
+import { isTypeArgumentsType } from "../../../../shared/typeNodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+
+export type InterfaceOrTypeLiteral =
+ | ts.InterfaceDeclaration
+ | ts.TypeLiteralNode;
+
+export const collectGenericNodeReferences = (
+ request: FileMutationsRequest,
+ node: InterfaceOrTypeLiteral,
+) => {
+ // Find all generic references purported to be of this type
+ const referencingNodes = collectDirectNodeReferences(request, node);
+ if (referencingNodes === undefined) {
+ return undefined;
+ }
+
+ // For any reference that uses the node as a generic type,
+ // expand the node's references to include references to that generic type
+ return expandReferencesForGenericTypes(request, node, referencingNodes);
};
-const collectDirectNodeReferences = (request: FileMutationsRequest, node: InterfaceOrTypeLiteral) => {
- // Interfaces are referenced by themselves, as they provide their own name
- // Type literals are referenced by their parent, which is often a type alias or variable
- const identifyingNode = ts.isInterfaceDeclaration(node) ? node : getIdentifyingTypeLiteralParent(node);
+const collectDirectNodeReferences = (
+ request: FileMutationsRequest,
+ node: InterfaceOrTypeLiteral,
+) => {
+ // Interfaces are referenced by themselves, as they provide their own name
+ // Type literals are referenced by their parent, which is often a type alias or variable
+ const identifyingNode = ts.isInterfaceDeclaration(node)
+ ? node
+ : getIdentifyingTypeLiteralParent(node);
- return request.fileInfoCache.getNodeReferencesAsNodes(identifyingNode);
+ return request.fileInfoCache.getNodeReferencesAsNodes(identifyingNode);
};
export const expandReferencesForGenericTypes = (
- request: FileMutationsRequest,
- interfaceOrTypeLiteral: InterfaceOrTypeLiteral,
- referencingNodes: ReadonlyArray,
+ request: FileMutationsRequest,
+ interfaceOrTypeLiteral: InterfaceOrTypeLiteral,
+ referencingNodes: readonly ts.Node[],
) => {
- const expandedReferences: ts.Node[] = [];
-
- // For each of the references we'll look at, there are two relevant nodes we need to map together:
- // * The templated declaration with type parameters: e.g. class Container { ... }
- // * The templated instantiation with type arguments: e.g. new Container() { ... }
- for (const referencingNode of referencingNodes) {
- // We only care about type references within generics
- if (!ts.isTypeReferenceNode(referencingNode)) {
- continue;
- }
-
- // Nodes with a "typeArguments" are the only ones we care about
- const templatedParentInstantiation = referencingNode.parent;
- if (!isNodeWithDefinedTypeArguments(templatedParentInstantiation)) {
- continue;
- }
-
- // Find the corresponding type node in the templated parent's type arguments
- // Note that call expressions (e.g. `container({})`) store the type in the expression (e.g. `container`),
- // while other types (e.g. `container.value = {};`) store the type on themselves
- const relevantNodeWithTypeSignatures = ts.isCallExpression(templatedParentInstantiation)
- ? templatedParentInstantiation.expression
- : templatedParentInstantiation;
- const templatedDeclarationSymbol = getTypeAtLocationIfNotError(request, relevantNodeWithTypeSignatures)?.getSymbol();
- if (templatedDeclarationSymbol === undefined) {
- continue;
- }
-
- // The templated declaration is the backing value declaration for the instantiation's symbol
- const templatedDeclaration = templatedDeclarationSymbol.valueDeclaration;
- if (
- templatedDeclaration === undefined ||
- !isNodeWithDefinedTypeParameters(templatedDeclaration) ||
- templatedParentInstantiation.typeArguments === undefined
- ) {
- continue;
- }
-
- // Find the index of the corresponding type argument in the instantation of the node,
- // and finally use that to grab the node for the template parameter from the type argument's index
- const typeArgumentIndex = templatedParentInstantiation.typeArguments.indexOf(referencingNode);
- const templateDeclaredTypeNode = templatedDeclaration.typeParameters[typeArgumentIndex];
-
- // Collect all nodes that are of the template declared type node when its value is
- // the interface or type alias we're considering expanding
- expandedReferences.push(...collectGenericReferencesOfType(request, interfaceOrTypeLiteral, templateDeclaredTypeNode));
- }
-
- return expandedReferences;
+ const expandedReferences: ts.Node[] = [];
+
+ // For each of the references we'll look at, there are two relevant nodes we need to map together:
+ // * The templated declaration with type parameters: e.g. class Container { ... }
+ // * The templated instantiation with type arguments: e.g. new Container() { ... }
+ for (const referencingNode of referencingNodes) {
+ // We only care about type references within generics
+ if (!ts.isTypeReferenceNode(referencingNode)) {
+ continue;
+ }
+
+ // Nodes with a "typeArguments" are the only ones we care about
+ const templatedParentInstantiation = referencingNode.parent;
+ if (!isNodeWithDefinedTypeArguments(templatedParentInstantiation)) {
+ continue;
+ }
+
+ // Find the corresponding type node in the templated parent's type arguments
+ // Note that call expressions (e.g. `container({})`) store the type in the expression (e.g. `container`),
+ // while other types (e.g. `container.value = {};`) store the type on themselves
+ const relevantNodeWithTypeSignatures = ts.isCallExpression(
+ templatedParentInstantiation,
+ )
+ ? templatedParentInstantiation.expression
+ : templatedParentInstantiation;
+ const templatedDeclarationSymbol = getTypeAtLocationIfNotError(
+ request,
+ relevantNodeWithTypeSignatures,
+ )?.getSymbol();
+ if (templatedDeclarationSymbol === undefined) {
+ continue;
+ }
+
+ // The templated declaration is the backing value declaration for the instantiation's symbol
+ const templatedDeclaration = templatedDeclarationSymbol.valueDeclaration;
+ if (
+ templatedDeclaration === undefined ||
+ !isNodeWithDefinedTypeParameters(templatedDeclaration) ||
+ templatedParentInstantiation.typeArguments === undefined
+ ) {
+ continue;
+ }
+
+ // Find the index of the corresponding type argument in the instantiation of the node,
+ // and finally use that to grab the node for the template parameter from the type argument's index
+ const typeArgumentIndex =
+ templatedParentInstantiation.typeArguments.indexOf(referencingNode);
+ const templateDeclaredTypeNode =
+ templatedDeclaration.typeParameters[typeArgumentIndex];
+
+ // Collect all nodes that are of the template declared type node when its value is
+ // the interface or type alias we're considering expanding
+ expandedReferences.push(
+ ...collectGenericReferencesOfType(
+ request,
+ interfaceOrTypeLiteral,
+ templateDeclaredTypeNode,
+ ),
+ );
+ }
+
+ return expandedReferences;
};
const collectGenericReferencesOfType = (
- request: FileMutationsRequest,
- interfaceOrTypeLiteral: InterfaceOrTypeLiteral,
- templateDeclaredTypeNode: ts.TypeNode,
+ request: FileMutationsRequest,
+ interfaceOrTypeLiteral: InterfaceOrTypeLiteral,
+ templateDeclaredTypeNode: ts.TypeNode,
) => {
- const genericNodeReferences: ts.Node[] = [];
- const originalType = getTypeAtLocationIfNotError(request, interfaceOrTypeLiteral);
-
- // Find all the references to the declared template type within its declaration
- // For example, in `class Container { member: T; }`, that would be the T in `member: T;`
- const referencingTypeNodes = request.fileInfoCache.getNodeReferencesAsNodes(templateDeclaredTypeNode);
- if (referencingTypeNodes === undefined) {
- return genericNodeReferences;
- }
-
- for (const referencingTypeNode of referencingTypeNodes) {
- // From the referencing type node, grab the node it's declared as the type of
- if (!ts.isTypeNode(referencingTypeNode)) {
- continue;
- }
-
- // The parent node of the referencing type node will typically be something like a parameter or variable declaration
- // For example, in `class Container { member: T; }`, that would be the `member: T;`
- const parent = referencingTypeNode.parent;
- if (!isNodeWithIdentifierName(parent)) {
- continue;
- }
-
- // Try finding all references to the name of the parent (declaration)
- // For example, if the parent is `member: T;`, that would be `member`
- const allReferencingInstantiationNodes = request.fileInfoCache.getNodeReferencesAsNodes(parent.name);
- if (allReferencingInstantiationNodes !== undefined) {
- for (const referencingInstantiationNode of allReferencingInstantiationNodes) {
- if (getTypeAtLocationIfNotError(request, referencingInstantiationNode) === originalType) {
- genericNodeReferences.push(referencingInstantiationNode);
- }
- }
- }
-
- // If the is a parameter, try all objects passed into its containing signature
- if (ts.isParameter(parent) || ts.isParameterPropertyDeclaration(parent, parent.parent)) {
- genericNodeReferences.push(...findProvidedTypesForParameter(request, interfaceOrTypeLiteral, parent.parent, parent));
- }
- }
-
- return genericNodeReferences;
+ const genericNodeReferences: ts.Node[] = [];
+ const originalType = getTypeAtLocationIfNotError(
+ request,
+ interfaceOrTypeLiteral,
+ );
+
+ // Find all the references to the declared template type within its declaration
+ // For example, in `class Container { member: T; }`, that would be the T in `member: T;`
+ const referencingTypeNodes = request.fileInfoCache.getNodeReferencesAsNodes(
+ templateDeclaredTypeNode,
+ );
+ if (referencingTypeNodes === undefined) {
+ return genericNodeReferences;
+ }
+
+ for (const referencingTypeNode of referencingTypeNodes) {
+ // From the referencing type node, grab the node it's declared as the type of
+ if (!ts.isTypeNode(referencingTypeNode)) {
+ continue;
+ }
+
+ // The parent node of the referencing type node will typically be something like a parameter or variable declaration
+ // For example, in `class Container { member: T; }`, that would be the `member: T;`
+ const parent = referencingTypeNode.parent;
+ if (!isNodeWithIdentifierName(parent)) {
+ continue;
+ }
+
+ // Try finding all references to the name of the parent (declaration)
+ // For example, if the parent is `member: T;`, that would be `member`
+ const allReferencingInstantiationNodes =
+ request.fileInfoCache.getNodeReferencesAsNodes(parent.name);
+ if (allReferencingInstantiationNodes !== undefined) {
+ for (const referencingInstantiationNode of allReferencingInstantiationNodes) {
+ if (
+ getTypeAtLocationIfNotError(request, referencingInstantiationNode) ===
+ originalType
+ ) {
+ genericNodeReferences.push(referencingInstantiationNode);
+ }
+ }
+ }
+
+ // If the is a parameter, try all objects passed into its containing signature
+ if (
+ ts.isParameter(parent) ||
+ ts.isParameterPropertyDeclaration(parent, parent.parent)
+ ) {
+ genericNodeReferences.push(
+ ...findProvidedTypesForParameter(
+ request,
+ interfaceOrTypeLiteral,
+ parent.parent,
+ parent,
+ ),
+ );
+ }
+ }
+
+ return genericNodeReferences;
};
const findProvidedTypesForParameter = (
- request: FileMutationsRequest,
- interfaceOrTypeLiteral: InterfaceOrTypeLiteral,
- signature: ts.SignatureDeclaration,
- parameter: ts.ParameterDeclaration | ts.ParameterPropertyDeclaration,
+ request: FileMutationsRequest,
+ interfaceOrTypeLiteral: InterfaceOrTypeLiteral,
+ signature: ts.SignatureDeclaration,
+ parameter: ts.ParameterDeclaration | ts.ParameterPropertyDeclaration,
) => {
- const providedNodes: ts.Node[] = [];
- const allReferencingNodes = request.fileInfoCache.getNodeReferencesAsNodes(signature);
- if (allReferencingNodes === undefined) {
- return providedNodes;
- }
-
- const originalType = getTypeAtLocationIfNotError(request, interfaceOrTypeLiteral);
- if (originalType === undefined) {
- return providedNodes;
- }
-
- const parameterIndex = signature.parameters.indexOf(parameter);
-
- for (let referencingNode of allReferencingNodes) {
- // Call signatures might be found to be referenced by an expression, e.g. `container({});`
- // We want the call expression within, e.g. `container({})` (note the lack of `;`)
- if (ts.isExpressionStatement(referencingNode)) {
- referencingNode = referencingNode.expression;
- }
-
- for (const potentialCallOrNewExpression of [
- // Direct call expressions will have arguments on themselves, e.g. `container({})`
- referencingNode,
- // New expressions will have arguments on their parents, e.g. `new Container({})`
- referencingNode.parent,
- // Method expressions will have arguments on their grandparents, e.g. `container.setValues({})`
- referencingNode.parent.parent,
- ]) {
- if (!ts.isCallOrNewExpression(potentialCallOrNewExpression)) {
- continue;
- }
-
- const providedArguments = potentialCallOrNewExpression.arguments;
- if (providedArguments === undefined) {
- continue;
- }
-
- if (expressionRefersToOriginalType(request, originalType, potentialCallOrNewExpression)) {
- providedNodes.push(providedArguments[parameterIndex]);
- break;
- }
- }
- }
-
- return providedNodes;
+ const providedNodes: ts.Node[] = [];
+ const allReferencingNodes =
+ request.fileInfoCache.getNodeReferencesAsNodes(signature);
+ if (allReferencingNodes === undefined) {
+ return providedNodes;
+ }
+
+ const originalType = getTypeAtLocationIfNotError(
+ request,
+ interfaceOrTypeLiteral,
+ );
+ if (originalType === undefined) {
+ return providedNodes;
+ }
+
+ const parameterIndex = signature.parameters.indexOf(parameter);
+
+ for (let referencingNode of allReferencingNodes) {
+ // Call signatures might be found to be referenced by an expression, e.g. `container({});`
+ // We want the call expression within, e.g. `container({})` (note the lack of `;`)
+ if (ts.isExpressionStatement(referencingNode)) {
+ referencingNode = referencingNode.expression;
+ }
+
+ for (const potentialCallOrNewExpression of [
+ // Direct call expressions will have arguments on themselves, e.g. `container({})`
+ referencingNode,
+ // New expressions will have arguments on their parents, e.g. `new Container({})`
+ referencingNode.parent,
+ // Method expressions will have arguments on their grandparents, e.g. `container.setValues({})`
+ referencingNode.parent.parent,
+ ]) {
+ if (!ts.isCallOrNewExpression(potentialCallOrNewExpression)) {
+ continue;
+ }
+
+ const providedArguments = potentialCallOrNewExpression.arguments;
+ if (providedArguments === undefined) {
+ continue;
+ }
+
+ if (
+ expressionRefersToOriginalType(
+ request,
+ originalType,
+ potentialCallOrNewExpression,
+ )
+ ) {
+ providedNodes.push(providedArguments[parameterIndex]);
+ break;
+ }
+ }
+ }
+
+ return providedNodes;
};
/**
* Given:
- * * Declaration of a call or construct signature with a type argument (on it or a parent)
- * * Usage of that same signature
- * * An original interface or type literal
+ * Declaration of a call or construct signature with a type argument (on it or a parent)
+ * Usage of that same signature
+ * An original interface or type literal
* How can we determine whether the signature usage is on that same type argument?
* These are definitely not the right ways to do this...
* ...but I spent three hours wrangling with it and don't know how...
*/
const expressionRefersToOriginalType = (
- request: FileMutationsRequest,
- originalType: ts.Type,
- potentialCallOrNewExpression: ts.CallExpression | ts.NewExpression,
+ request: FileMutationsRequest,
+ originalType: ts.Type,
+ potentialCallOrNewExpression: ts.CallExpression | ts.NewExpression,
) => {
- const expressionNodeType = getTypeAtLocationIfNotError(request, potentialCallOrNewExpression);
- if (expressionNodeType === undefined) {
- return false;
- }
-
- // If the expression node's type already has type arguments, do they match the original type?
- // This is more likely with classes that are instantiated with a type
- // This can go wrong easily: e.g. with multiple type arguments that have intermixed usages
- if (isTypeArgumentsType(expressionNodeType) && expressionNodeType.typeArguments?.includes(originalType)) {
- return true;
- }
-
- // Alternately, what about functions that themselves have types?
- // Again, this can go wrong: e.g. with multiple type arguments that have intermixed usages
- if (isNodeWithDefinedTypeArguments(potentialCallOrNewExpression)) {
- for (const typeArgument of potentialCallOrNewExpression.typeArguments || []) {
- if (getTypeAtLocationIfNotError(request, typeArgument) === originalType) {
- return true;
- }
- }
- }
-
- return false;
+ const expressionNodeType = getTypeAtLocationIfNotError(
+ request,
+ potentialCallOrNewExpression,
+ );
+ if (expressionNodeType === undefined) {
+ return false;
+ }
+
+ // If the expression node's type already has type arguments, do they match the original type?
+ // This is more likely with classes that are instantiated with a type
+ // This can go wrong easily: e.g. with multiple type arguments that have intermixed usages
+ if (
+ isTypeArgumentsType(expressionNodeType) &&
+ expressionNodeType.typeArguments.includes(originalType)
+ ) {
+ return true;
+ }
+
+ // Alternately, what about functions that themselves have types?
+ // Again, this can go wrong: e.g. with multiple type arguments that have intermixed usages
+ if (
+ isNodeWithDefinedTypeArguments(potentialCallOrNewExpression) &&
+ potentialCallOrNewExpression.typeArguments
+ ) {
+ for (const typeArgument of potentialCallOrNewExpression.typeArguments) {
+ if (getTypeAtLocationIfNotError(request, typeArgument) === originalType) {
+ return true;
+ }
+ }
+ }
+
+ return false;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/expandValuesAssignedToReferenceNodes.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/expandValuesAssignedToReferenceNodes.ts
index ac31d4932..8c32dbf1b 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/expandValuesAssignedToReferenceNodes.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/expandValuesAssignedToReferenceNodes.ts
@@ -1,82 +1,100 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { AssignedTypeValue } from "../../../../mutations/assignments";
-import { isNodeAssigningBinaryExpression } from "../../../../shared/nodes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
+import { AssignedTypeValue } from "../../../../mutations/assignments.js";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { isNodeAssigningBinaryExpression } from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
export const expandValuesAssignedToReferenceNodes = (
- request: FileMutationsRequest,
- originalType: ts.Type,
- genericReferenceNodes: ts.Node[],
+ request: FileMutationsRequest,
+ originalType: ts.Type,
+ genericReferenceNodes: ts.Node[],
) => {
- const assignedValues = new Set();
+ const assignedValues = new Set();
- for (const genericReferenceNode of genericReferenceNodes) {
- const assignedGenericValue = getAssignedGenericValue(request, originalType, genericReferenceNode);
- if (assignedGenericValue !== undefined) {
- assignedValues.add(assignedGenericValue);
- }
- }
+ for (const genericReferenceNode of genericReferenceNodes) {
+ const assignedGenericValue = getAssignedGenericValue(
+ request,
+ originalType,
+ genericReferenceNode,
+ );
+ if (assignedGenericValue !== undefined) {
+ assignedValues.add(assignedGenericValue);
+ }
+ }
- return Array.from(assignedValues);
+ return Array.from(assignedValues);
};
-const getAssignedGenericValue = (request: FileMutationsRequest, originalType: ts.Type, node: ts.Node): AssignedTypeValue | undefined => {
- // Case:
- // function container(values: T) { }
- // type Values = {};
- // container({ laterAssigned: true, });
- // Case:
- // declare class Container { values: t; }
- // type Values = {};
- // new Container({ laterAssigned: true, });
- // Case:
- // declare class Container { setValues(values: t): void; }
- // type Values = {};
- // new Container({}).setValues({ laterAssigned: true });
- if (ts.isObjectLiteralExpression(node)) {
- return assignedTypeOrUndefined({
- type: getTypeAtLocationIfNotError(request, node),
- });
- }
+const getAssignedGenericValue = (
+ request: FileMutationsRequest,
+ originalType: ts.Type,
+ node: ts.Node,
+): AssignedTypeValue | undefined => {
+ // Case:
+ // function container(values: T) { }
+ // type Values = {};
+ // container({ laterAssigned: true, });
+ // Case:
+ // declare class Container { values: t; }
+ // type Values = {};
+ // new Container({ laterAssigned: true, });
+ // Case:
+ // declare class Container { setValues(values: t): void; }
+ // type Values = {};
+ // new Container({}).setValues({ laterAssigned: true });
+ if (ts.isObjectLiteralExpression(node)) {
+ return assignedTypeOrUndefined({
+ type: getTypeAtLocationIfNotError(request, node),
+ });
+ }
- if (ts.isIdentifier(node) && ts.isPropertyAccessExpression(node.parent)) {
- // Case:
- // declare class Container { values: t; }
- // type Values = {};
- // const container = new Container({});
- // container.values = { laterAssigned: true, };
- if (isNodeAssigningBinaryExpression(node.parent.parent) && getTypeAtLocationIfNotError(request, node.parent) === originalType) {
- return assignedTypeOrUndefined({
- type: getTypeAtLocationIfNotError(request, node.parent.parent.right),
- });
- }
+ if (ts.isIdentifier(node) && ts.isPropertyAccessExpression(node.parent)) {
+ // Case:
+ // declare class Container { values: t; }
+ // type Values = {};
+ // const container = new Container({});
+ // container.values = { laterAssigned: true, };
+ if (
+ isNodeAssigningBinaryExpression(node.parent.parent) &&
+ getTypeAtLocationIfNotError(request, node.parent) === originalType
+ ) {
+ return assignedTypeOrUndefined({
+ type: getTypeAtLocationIfNotError(request, node.parent.parent.right),
+ });
+ }
- // Case:
- // declare class Container { values: T; }
- // type Values = {};
- // const container = new Container({});
- // container.values.laterAssigned = true;
- // Case:
- // declare class Container { values: T; }
- // type Values = {};
- // new Container({}).values.quicklyAssigned = true;
- if (
- ts.isPropertyAccessExpression(node.parent.parent) &&
- ts.isIdentifier(node.parent.parent.name) &&
- isNodeAssigningBinaryExpression(node.parent.parent.parent) &&
- getTypeAtLocationIfNotError(request, node.parent) === originalType
- ) {
- return assignedTypeOrUndefined({
- name: node.parent.parent.name.getText(),
- type: getTypeAtLocationIfNotError(request, node.parent.parent.parent.right),
- });
- }
- }
+ // Case:
+ // declare class Container { values: T; }
+ // type Values = {};
+ // const container = new Container({});
+ // container.values.laterAssigned = true;
+ // Case:
+ // declare class Container { values: T; }
+ // type Values = {};
+ // new Container({}).values.quicklyAssigned = true;
+ if (
+ ts.isPropertyAccessExpression(node.parent.parent) &&
+ ts.isIdentifier(node.parent.parent.name) &&
+ isNodeAssigningBinaryExpression(node.parent.parent.parent) &&
+ getTypeAtLocationIfNotError(request, node.parent) === originalType
+ ) {
+ return assignedTypeOrUndefined({
+ name: node.parent.parent.name.getText(),
+ type: getTypeAtLocationIfNotError(
+ request,
+ node.parent.parent.parent.right,
+ ),
+ });
+ }
+ }
- return undefined;
+ return undefined;
};
-const assignedTypeOrUndefined = (assignedType: Partial): AssignedTypeValue | undefined =>
- assignedType.type === undefined ? undefined : (assignedType as AssignedTypeValue);
+const assignedTypeOrUndefined = (
+ assignedType: Partial,
+): AssignedTypeValue | undefined =>
+ assignedType.type === undefined
+ ? undefined
+ : (assignedType as AssignedTypeValue);
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/index.ts
index 1e13a6d96..9cc516e34 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteInterfaceOrTypeLiteralGenerics/index.ts
@@ -1,39 +1,62 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { joinAssignedTypesByName } from "../../../../mutations/assignments";
-import { createTypeExpansionMutation } from "../../../../mutations/expansions/expansionMutations";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { joinAssignedTypesByName } from "../../../../mutations/assignments.js";
+import { createTypeExpansionMutation } from "../../../../mutations/expansions/expansionMutations.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+import {
+ InterfaceOrTypeLiteral,
+ collectGenericNodeReferences,
+} from "./collectGenericNodeReferences.js";
+import { expandValuesAssignedToReferenceNodes } from "./expandValuesAssignedToReferenceNodes.js";
-import { collectGenericNodeReferences, InterfaceOrTypeLiteral } from "./collectGenericNodeReferences";
-import { expandValuesAssignedToReferenceNodes } from "./expandValuesAssignedToReferenceNodes";
+export const fixIncompleteInterfaceOrTypeLiteralGenerics: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isInterfaceOrTypeLiteral,
+ visitInterfaceOrTypeLiteral,
+ );
-export const fixIncompleteInterfaceOrTypeLiteralGenerics: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isInterfaceOrTypeLiteral, visitInterfaceOrTypeLiteral);
+const isInterfaceOrTypeLiteral = (
+ node: ts.Node,
+): node is InterfaceOrTypeLiteral =>
+ ts.isInterfaceDeclaration(node) || ts.isTypeLiteralNode(node);
-const isInterfaceOrTypeLiteral = (node: ts.Node): node is InterfaceOrTypeLiteral =>
- ts.isInterfaceDeclaration(node) || ts.isTypeLiteralNode(node);
+const visitInterfaceOrTypeLiteral = (
+ node: InterfaceOrTypeLiteral,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Find all nodes that seem like they could possibly reference the generic
+ const genericReferenceNodes = collectGenericNodeReferences(request, node);
+ if (genericReferenceNodes === undefined) {
+ return undefined;
+ }
-const visitInterfaceOrTypeLiteral = (node: InterfaceOrTypeLiteral, request: FileMutationsRequest): Mutation | undefined => {
- // Find all nodes that seem like they could possibly reference the generic
- const genericReferenceNodes = collectGenericNodeReferences(request, node);
- if (genericReferenceNodes === undefined) {
- return undefined;
- }
+ // Given all those generic references, find all the types being assigned to those nodes
+ const originalType = getTypeAtLocationIfNotError(request, node);
+ if (originalType === undefined) {
+ return undefined;
+ }
- // Given all those generic references, find all the types being assigned to those nodes
- const originalType = getTypeAtLocationIfNotError(request, node);
- if (originalType === undefined) {
- return undefined;
- }
- const valuesAssignedToReferenceNodes = expandValuesAssignedToReferenceNodes(request, originalType, genericReferenceNodes);
- if (valuesAssignedToReferenceNodes.length === 0) {
- return undefined;
- }
+ const valuesAssignedToReferenceNodes = expandValuesAssignedToReferenceNodes(
+ request,
+ originalType,
+ genericReferenceNodes,
+ );
+ if (valuesAssignedToReferenceNodes.length === 0) {
+ return undefined;
+ }
- // Join those types into a mapping that keys them by property name
- // That mapping is directly translatable into a mutation to add those properties
- return createTypeExpansionMutation(request, node, [joinAssignedTypesByName(request, valuesAssignedToReferenceNodes)]);
+ // Join those types into a mapping that keys them by property name
+ // That mapping is directly translatable into a mutation to add those properties
+ return createTypeExpansionMutation(request, node, [
+ joinAssignedTypesByName(request, valuesAssignedToReferenceNodes),
+ ]);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteParameterTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteParameterTypes/index.ts
index 502972a36..89fc95737 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteParameterTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteParameterTypes/index.ts
@@ -1,78 +1,120 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { createTypeAdditionMutation, createTypeCreationMutation } from "../../../../mutations/creators";
-import { isNodeWithType, NodeWithType } from "../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import {
+ createTypeAdditionMutation,
+ createTypeCreationMutation,
+} from "../../../../mutations/creators.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { NodeWithType, isNodeWithType } from "../../../../shared/nodeTypes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixIncompleteParameterTypes: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isParameterWithType, visitParameterDeclaration);
+export const fixIncompleteParameterTypes: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isParameterWithType,
+ visitParameterDeclaration,
+ );
-const isParameterWithType = (node: ts.Node): node is ts.ParameterDeclaration & NodeWithType => ts.isParameter(node) && isNodeWithType(node);
+const isParameterWithType = (
+ node: ts.Node,
+): node is ts.ParameterDeclaration & NodeWithType =>
+ ts.isParameter(node) && isNodeWithType(node);
-const visitParameterDeclaration = (node: ts.ParameterDeclaration, request: FileMutationsRequest): Mutation | undefined => {
- // Collect types initially assigned or later called with as the parameter
- const callingTypes = getCallingTypesFromReferencedSymbols(node, request);
+const visitParameterDeclaration = (
+ node: ts.ParameterDeclaration,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Collect types initially assigned or later called with as the parameter
+ const callingTypes = getCallingTypesFromReferencedSymbols(node, request);
- // Collect the type(s) initially declared on the parameter
- const declaredType = getTypeAtLocationIfNotError(request, node);
- if (declaredType === undefined) {
- return undefined;
- }
+ // Collect the type(s) initially declared on the parameter
+ const declaredType = getTypeAtLocationIfNotError(request, node);
+ if (declaredType === undefined) {
+ return undefined;
+ }
- // If the parameter already has a declared type, add assigned types to it if necessary
- if (isNodeWithType(node)) {
- return createTypeAdditionMutation(request, node, declaredType, callingTypes);
- }
+ // If the parameter already has a declared type, add assigned types to it if necessary
+ if (isNodeWithType(node)) {
+ return createTypeAdditionMutation(
+ request,
+ node,
+ declaredType,
+ callingTypes,
+ );
+ }
- // Since the parameter doesn't have its own type, give it one if necessary
- return createTypeCreationMutation(request, node, declaredType, callingTypes);
+ // Since the parameter doesn't have its own type, give it one if necessary
+ return createTypeCreationMutation(request, node, declaredType, callingTypes);
};
-const getCallingTypesFromReferencedSymbols = (node: ts.ParameterDeclaration, request: FileMutationsRequest): ReadonlyArray => {
- const callingTypes: ts.Type[] = [];
+const getCallingTypesFromReferencedSymbols = (
+ node: ts.ParameterDeclaration,
+ request: FileMutationsRequest,
+): readonly ts.Type[] => {
+ const callingTypes: ts.Type[] = [];
- // If the parameter has a default, also consider that a calling type
- const initializerType = getTypeAtLocationIfNotError(request, node.initializer);
- if (initializerType !== undefined) {
- callingTypes.push(initializerType);
- }
+ // If the parameter has a default, also consider that a calling type
+ const initializerType = getTypeAtLocationIfNotError(
+ request,
+ node.initializer,
+ );
+ if (initializerType !== undefined) {
+ callingTypes.push(initializerType);
+ }
- // Find all locations the containing method is called
- const references = request.fileInfoCache.getNodeReferencesAsNodes(node.parent);
- if (references !== undefined) {
- const parameterIndex = node.parent.parameters.indexOf(node);
+ // Find all locations the containing method is called
+ const references = request.fileInfoCache.getNodeReferencesAsNodes(
+ node.parent,
+ );
+ if (references !== undefined) {
+ const parameterIndex = node.parent.parameters.indexOf(node);
- // For each calling location, add any types it's called with there
- for (const reference of references) {
- updateCallingTypesForReference(parameterIndex, reference, callingTypes, request);
- }
- }
+ // For each calling location, add any types it's called with there
+ for (const reference of references) {
+ updateCallingTypesForReference(
+ parameterIndex,
+ reference,
+ callingTypes,
+ request,
+ );
+ }
+ }
- return callingTypes;
+ return callingTypes;
};
const updateCallingTypesForReference = (
- parameterIndex: number,
- callingNode: ts.Node,
- callingTypes: ts.Type[],
- request: FileMutationsRequest,
+ parameterIndex: number,
+ callingNode: ts.Node,
+ callingTypes: ts.Type[],
+ request: FileMutationsRequest,
): void => {
- // In order to be calling with this parameter, the referencing node should be an expression...
- if (!ts.isExpressionStatement(callingNode)) {
- return;
- }
+ // In order to be calling with this parameter, the referencing node should be an expression...
+ if (!ts.isExpressionStatement(callingNode)) {
+ return;
+ }
- // ...that calls to the parameter we're looking at
- if (!ts.isCallExpression(callingNode.expression) || callingNode.expression.arguments.length <= parameterIndex) {
- return;
- }
+ // ...that calls to the parameter we're looking at
+ if (
+ !ts.isCallExpression(callingNode.expression) ||
+ callingNode.expression.arguments.length <= parameterIndex
+ ) {
+ return;
+ }
- // Mark the type of parameter at our index as being called with
- const callingType = getTypeAtLocationIfNotError(request, callingNode.expression.arguments[parameterIndex]);
- if (callingType !== undefined) {
- callingTypes.push(callingType);
- }
+ // Mark the type of parameter at our index as being called with
+ const callingType = getTypeAtLocationIfNotError(
+ request,
+ callingNode.expression.arguments[parameterIndex],
+ );
+ if (callingType !== undefined) {
+ callingTypes.push(callingType);
+ }
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompletePropertyDeclarationTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompletePropertyDeclarationTypes/index.ts
index df578d1f5..5a31a5951 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompletePropertyDeclarationTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompletePropertyDeclarationTypes/index.ts
@@ -1,105 +1,153 @@
import { Mutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
-
-import { createTypeAdditionMutation, createTypeCreationMutation } from "../../../../mutations/creators";
-import { isNodeAssigningBinaryExpression } from "../../../../shared/nodes";
-import { isNodeWithType, NodeWithType } from "../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
-
-export const fixIncompletePropertyDeclarationTypes: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isPropertyDeclarationWithType, visitPropertyDeclaration);
-
-const isPropertyDeclarationWithType = (node: ts.Node): node is ts.PropertyDeclaration & NodeWithType =>
- ts.isPropertyDeclaration(node) && isNodeWithType(node);
-
-const visitPropertyDeclaration = (node: ts.PropertyDeclaration, request: FileMutationsRequest): Mutation | undefined => {
- // Collect types later assigned to the property, and types initially declared by or inferred on the property
- const assignedTypes = collectPropertyAssignedTypes(node, request);
- const declaredType = getTypeAtLocationIfNotError(request, node);
- if (declaredType === undefined || tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)) {
- return undefined;
- }
-
- // If the property already has a declared type, add assigned types to it if necessary
- if (isNodeWithType(node)) {
- return createTypeAdditionMutation(request, node, declaredType, assignedTypes);
- }
-
- // Since the parameter doesn't have its own type, give it one if necessary
- return createTypeCreationMutation(request, node, declaredType, assignedTypes);
+import ts from "typescript";
+
+import {
+ createTypeAdditionMutation,
+ createTypeCreationMutation,
+} from "../../../../mutations/creators.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { NodeWithType, isNodeWithType } from "../../../../shared/nodeTypes.js";
+import { isNodeAssigningBinaryExpression } from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+
+export const fixIncompletePropertyDeclarationTypes: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isPropertyDeclarationWithType,
+ visitPropertyDeclaration,
+ );
+
+const isPropertyDeclarationWithType = (
+ node: ts.Node,
+): node is ts.PropertyDeclaration & NodeWithType =>
+ ts.isPropertyDeclaration(node) && isNodeWithType(node);
+
+const visitPropertyDeclaration = (
+ node: ts.PropertyDeclaration,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Collect types later assigned to the property, and types initially declared by or inferred on the property
+ const assignedTypes = collectPropertyAssignedTypes(node, request);
+ const declaredType = getTypeAtLocationIfNotError(request, node);
+ if (
+ declaredType === undefined ||
+ tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)
+ ) {
+ return undefined;
+ }
+
+ // If the property already has a declared type, add assigned types to it if necessary
+ if (isNodeWithType(node)) {
+ return createTypeAdditionMutation(
+ request,
+ node,
+ declaredType,
+ assignedTypes,
+ );
+ }
+
+ // Since the parameter doesn't have its own type, give it one if necessary
+ return createTypeCreationMutation(request, node, declaredType, assignedTypes);
};
-const collectPropertyAssignedTypes = (node: ts.PropertyDeclaration, request: FileMutationsRequest): ReadonlyArray => {
- const assignedTypes: ts.Type[] = [];
-
- // If the property has an initial value, consider that an assignment
- if (node.initializer !== undefined) {
- const initializerType = getTypeAtLocationIfNotError(request, node.initializer);
- if (initializerType !== undefined) {
- assignedTypes.push(initializerType);
- }
- }
-
- // If the property is marked as readonly, don't bother checking for more types
- if (tsutils.isModifierFlagSet(node, ts.ModifierFlags.Readonly)) {
- return assignedTypes;
- }
-
- // Find everything else referencing the property
- const references = request.fileInfoCache.getNodeReferencesAsNodes(node);
- if (references !== undefined) {
- // For each referencing location, update types if the type is assigned to there
- for (const reference of references) {
- updateAssignedTypesForReference(node.parent, reference, assignedTypes, request);
- }
- }
-
- return assignedTypes;
+const collectPropertyAssignedTypes = (
+ node: ts.PropertyDeclaration,
+ request: FileMutationsRequest,
+): readonly ts.Type[] => {
+ const assignedTypes: ts.Type[] = [];
+
+ // If the property has an initial value, consider that an assignment
+ if (node.initializer !== undefined) {
+ const initializerType = getTypeAtLocationIfNotError(
+ request,
+ node.initializer,
+ );
+ if (initializerType !== undefined) {
+ assignedTypes.push(initializerType);
+ }
+ }
+
+ // If the property is marked as readonly, don't bother checking for more types
+ if (tsutils.isModifierFlagSet(node, ts.ModifierFlags.Readonly)) {
+ return assignedTypes;
+ }
+
+ // Find everything else referencing the property
+ const references = request.fileInfoCache.getNodeReferencesAsNodes(node);
+ if (references !== undefined) {
+ // For each referencing location, update types if the type is assigned to there
+ for (const reference of references) {
+ updateAssignedTypesForReference(
+ node.parent,
+ reference,
+ assignedTypes,
+ request,
+ );
+ }
+ }
+
+ return assignedTypes;
};
/**
* Adds missing types for a reference to a property.
- *
+ * @param targetClass Class whose properties are being referenced.
* @param identifier Node referencing the property.
* @param assignedTypes In-progress collection of types assigned to a property.
* @param request Metadata and settings to collect mutations in a file.
*/
const updateAssignedTypesForReference = (
- targetClass: ts.ClassLikeDeclaration,
- identifier: ts.Node,
- assignedTypes: ts.Type[],
- request: FileMutationsRequest,
+ targetClass: ts.ClassLikeDeclaration,
+ identifier: ts.Node,
+ assignedTypes: ts.Type[],
+ request: FileMutationsRequest,
): void => {
- // In order to write a new type, the referencing node should be an identifier...
- if (!ts.isIdentifier(identifier)) {
- return;
- }
-
- // ...contained as a name inside a property access...
- const propertyAccess = identifier.parent;
- if (!ts.isPropertyAccessExpression(propertyAccess) || propertyAccess.name !== identifier) {
- return;
- }
-
- // ...contained as the left-hand side of an "=" binary expression...
- const binaryExpression = propertyAccess.parent;
- if (!isNodeAssigningBinaryExpression(binaryExpression) || binaryExpression.left !== propertyAccess) {
- return;
- }
-
- // ...and where the original property access expression refers to the target class
- // (this is important when multiple child classes of a single base class redeclare a member, such as React.Component's state)
- const assigneeType = getTypeAtLocationIfNotError(request, propertyAccess.expression);
- if (assigneeType?.getSymbol()?.valueDeclaration !== targetClass) {
- return;
- }
-
- // Mark the type of the right-hand side of the "=" expression as being assigned
- const assignmentType = getTypeAtLocationIfNotError(request, binaryExpression.right);
- if (assignmentType !== undefined) {
- assignedTypes.push(assignmentType);
- }
+ // In order to write a new type, the referencing node should be an identifier...
+ if (!ts.isIdentifier(identifier)) {
+ return;
+ }
+
+ // ...contained as a name inside a property access...
+ const propertyAccess = identifier.parent;
+ if (
+ !ts.isPropertyAccessExpression(propertyAccess) ||
+ propertyAccess.name !== identifier
+ ) {
+ return;
+ }
+
+ // ...contained as the left-hand side of an "=" binary expression...
+ const binaryExpression = propertyAccess.parent;
+ if (
+ !isNodeAssigningBinaryExpression(binaryExpression) ||
+ binaryExpression.left !== propertyAccess
+ ) {
+ return;
+ }
+
+ // ...and where the original property access expression refers to the target class
+ // (this is important when multiple child classes of a single base class redeclare a member, such as React.Component's state)
+ const assigneeType = getTypeAtLocationIfNotError(
+ request,
+ propertyAccess.expression,
+ );
+ if (assigneeType?.getSymbol()?.valueDeclaration !== targetClass) {
+ return;
+ }
+
+ // Mark the type of the right-hand side of the "=" expression as being assigned
+ const assignmentType = getTypeAtLocationIfNotError(
+ request,
+ binaryExpression.right,
+ );
+ if (assignmentType !== undefined) {
+ assignedTypes.push(assignmentType);
+ }
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/collectAllFunctionCallTypes.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/collectAllFunctionCallTypes.ts
index 647b18193..138024ce9 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/collectAllFunctionCallTypes.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/collectAllFunctionCallTypes.ts
@@ -1,89 +1,113 @@
-import * as ts from "typescript";
-import { getDeclaredTypesOfArgument } from "../../../../../shared/calls";
-import { isPropertySignatureWithStaticName, PropertySignatureWithStaticName } from "../../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../../shared/types";
-
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-import { ReactComponentPropsNode } from "../getComponentPropsNode";
-import { getPropNodeFromReference } from "../getPropNodeFromReference";
+import ts from "typescript";
+
+import { getDeclaredTypesOfArgument } from "../../../../../shared/calls.js";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
+import {
+ PropertySignatureWithStaticName,
+ isPropertySignatureWithStaticName,
+} from "../../../../../shared/nodeTypes.js";
+import { getTypeAtLocationIfNotError } from "../../../../../shared/types.js";
+import { ReactComponentPropsNode } from "../getComponentPropsNode.js";
+import { getPropNodeFromReference } from "../getPropNodeFromReference.js";
export interface FunctionCallType {
- parameters?: (ts.Type | undefined)[];
- returnValue?: ts.Type;
+ parameters?: (ts.Type | undefined)[];
+ returnValue?: ts.Type;
}
-export const collectAllFunctionCallTypes = (request: FileMutationsRequest, propsNode: ReactComponentPropsNode) => {
- const allFunctionCallTypes = new Map();
-
- for (const member of propsNode.members) {
- // Don't look at properties without obvious names and types explicitly set to Function
- if (
- !isPropertySignatureWithStaticName(member) ||
- member.type === undefined ||
- !ts.isTypeReferenceNode(member.type) ||
- !ts.isIdentifier(member.type.typeName) ||
- member.type.typeName.text !== "Function"
- ) {
- continue;
- }
-
- collectFunctionCallsTypes(request, member, allFunctionCallTypes);
- }
-
- return allFunctionCallTypes;
+export const collectAllFunctionCallTypes = (
+ request: FileMutationsRequest,
+ propsNode: ReactComponentPropsNode,
+) => {
+ const allFunctionCallTypes = new Map<
+ PropertySignatureWithStaticName,
+ FunctionCallType[]
+ >();
+
+ for (const member of propsNode.members) {
+ // Don't look at properties without obvious names and types explicitly set to Function
+ if (
+ !isPropertySignatureWithStaticName(member) ||
+ member.type === undefined ||
+ !ts.isTypeReferenceNode(member.type) ||
+ !ts.isIdentifier(member.type.typeName) ||
+ member.type.typeName.text !== "Function"
+ ) {
+ continue;
+ }
+
+ collectFunctionCallsTypes(request, member, allFunctionCallTypes);
+ }
+
+ return allFunctionCallTypes;
};
const collectFunctionCallsTypes = (
- request: FileMutationsRequest,
- member: PropertySignatureWithStaticName,
- allFunctionCallTypes: Map,
+ request: FileMutationsRequest,
+ member: PropertySignatureWithStaticName,
+ allFunctionCallTypes: Map<
+ PropertySignatureWithStaticName,
+ FunctionCallType[]
+ >,
) => {
- // Find all references to the name of the type
- const references = request.fileInfoCache.getNodeReferencesAsNodes(member.name);
- if (references === undefined) {
- return;
- }
-
- const functionCallTypes: FunctionCallType[] = [];
-
- // For each reference, try to infer the type from its usage...
- for (const reference of references) {
- // (except for the original member we're looking around)
- if (reference === member || !ts.isExpression(reference)) {
- continue;
- }
-
- const call = getCallForReference(reference);
- if (call !== undefined) {
- collectFunctionCallTypes(request, functionCallTypes, call);
- }
- }
-
- allFunctionCallTypes.set(member, functionCallTypes);
+ // Find all references to the name of the type
+ const references = request.fileInfoCache.getNodeReferencesAsNodes(
+ member.name,
+ );
+ if (references === undefined) {
+ return;
+ }
+
+ const functionCallTypes: FunctionCallType[] = [];
+
+ // For each reference, try to infer the type from its usage...
+ for (const reference of references) {
+ // (except for the original member we're looking around)
+ if (reference === member || !ts.isExpression(reference)) {
+ continue;
+ }
+
+ const call = getCallForReference(reference);
+ if (call !== undefined) {
+ collectFunctionCallTypes(request, functionCallTypes, call);
+ }
+ }
+
+ allFunctionCallTypes.set(member, functionCallTypes);
};
const getCallForReference = (reference: ts.Expression) => {
- reference = getPropNodeFromReference(reference);
+ reference = getPropNodeFromReference(reference);
- return ts.isCallExpression(reference.parent) ? reference.parent : undefined;
+ return ts.isCallExpression(reference.parent) ? reference.parent : undefined;
};
-const collectFunctionCallTypes = (request: FileMutationsRequest, functionCallTypes: FunctionCallType[], call: ts.CallExpression) => {
- // Case: the return value is directly passed to a function
- if (ts.isCallExpression(call.parent) || ts.isNewExpression(call.parent)) {
- const declaredTypes = getDeclaredTypesOfArgument(request, call.parent, call);
-
- for (const declaredType of declaredTypes) {
- functionCallTypes.push({
- returnValue: declaredType,
- });
- }
- }
-
- // If the prop function is passed arguments, infer types from them
- if (call.arguments.length !== 0) {
- functionCallTypes.push({
- parameters: call.arguments.map((callArgument) => getTypeAtLocationIfNotError(request, callArgument)),
- });
- }
+const collectFunctionCallTypes = (
+ request: FileMutationsRequest,
+ functionCallTypes: FunctionCallType[],
+ call: ts.CallExpression,
+) => {
+ // Case: the return value is directly passed to a function
+ if (ts.isCallExpression(call.parent) || ts.isNewExpression(call.parent)) {
+ const declaredTypes = getDeclaredTypesOfArgument(
+ request,
+ call.parent,
+ call,
+ );
+
+ for (const declaredType of declaredTypes) {
+ functionCallTypes.push({
+ returnValue: declaredType,
+ });
+ }
+ }
+
+ // If the prop function is passed arguments, infer types from them
+ if (call.arguments.length !== 0) {
+ functionCallTypes.push({
+ parameters: call.arguments.map((callArgument) =>
+ getTypeAtLocationIfNotError(request, callArgument),
+ ),
+ });
+ }
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/createFunctionCallTypesMutation.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/createFunctionCallTypesMutation.ts
index 8c45355c6..fb74e1d68 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/createFunctionCallTypesMutation.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/createFunctionCallTypesMutation.ts
@@ -1,88 +1,116 @@
-import { combineMutations, TextSwapMutation } from "automutate";
-import * as ts from "typescript";
+import { TextSwapMutation, combineMutations } from "automutate";
+import ts from "typescript";
-import { collectOptionals, isNotUndefined } from "../../../../../shared/arrays";
-import { PropertySignatureWithStaticName } from "../../../../../shared/nodeTypes";
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-import { FunctionCallType } from "./collectAllFunctionCallTypes";
+import {
+ collectOptionals,
+ isNotUndefined,
+} from "../../../../../shared/arrays.js";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
+import { PropertySignatureWithStaticName } from "../../../../../shared/nodeTypes.js";
+import { FunctionCallType } from "./collectAllFunctionCallTypes.js";
-type CombinedFunctionType = {
- parameters: ts.Type[][];
- returnValue?: ts.Type[];
-};
+interface CombinedFunctionType {
+ parameters: ts.Type[][];
+ returnValue?: ts.Type[];
+}
export const createFunctionCallTypesMutation = (
- request: FileMutationsRequest,
- allFunctionCallTypes: Map,
+ request: FileMutationsRequest,
+ allFunctionCallTypes: Map<
+ PropertySignatureWithStaticName,
+ FunctionCallType[]
+ >,
) => {
- const mutations = Array.from(allFunctionCallTypes).map(([member, functionCallTypes]) => {
- return createFunctionCallTypeMutation(request, member, functionCallTypes);
- });
+ const mutations = Array.from(allFunctionCallTypes).map(
+ ([member, functionCallTypes]) => {
+ return createFunctionCallTypeMutation(request, member, functionCallTypes);
+ },
+ );
- return mutations === undefined || mutations.length === 0 ? undefined : combineMutations(...mutations);
+ return mutations.length === 0 ? undefined : combineMutations(...mutations);
};
const createFunctionCallTypeMutation = (
- request: FileMutationsRequest,
- member: PropertySignatureWithStaticName,
- functionCallTypes: FunctionCallType[],
+ request: FileMutationsRequest,
+ member: PropertySignatureWithStaticName,
+ functionCallTypes: FunctionCallType[],
): TextSwapMutation => {
- const combinedType = functionCallTypes.reduce(
- (accum, functionCallType) => {
- return {
- parameters: combineParameters(request, accum.parameters, functionCallType.parameters),
- returnValue: collectOptionals(accum.returnValue, [functionCallType.returnValue]).filter(isNotUndefined),
- };
- },
- {
- parameters: [],
- returnValue: [],
- },
- );
+ const combinedType = functionCallTypes.reduce(
+ (accumulator, functionCallType) => {
+ return {
+ parameters: combineParameters(
+ request,
+ accumulator.parameters,
+ functionCallType.parameters,
+ ),
+ returnValue: collectOptionals(accumulator.returnValue, [
+ functionCallType.returnValue,
+ ]).filter(isNotUndefined),
+ };
+ },
+ {
+ parameters: [],
+ returnValue: [],
+ },
+ );
- return {
- insertion: `${member.name.text}: ${printFunctionType(request, combinedType)}`,
- range: {
- begin: member.getStart(request.sourceFile),
- end: member.end,
- },
- type: "text-swap",
- };
+ return {
+ insertion: `${member.name.text}: ${printFunctionType(request, combinedType)}`,
+ range: {
+ begin: member.getStart(request.sourceFile),
+ end: member.end,
+ },
+ type: "text-swap",
+ };
};
-const combineParameters = (request: FileMutationsRequest, previous: ts.Type[][], next: (ts.Type | undefined)[] | undefined) => {
- if (next === undefined) {
- return previous;
- }
+const combineParameters = (
+ request: FileMutationsRequest,
+ previous: ts.Type[][],
+ next: (ts.Type | undefined)[] | undefined,
+) => {
+ if (next === undefined) {
+ return previous;
+ }
- const combined: ts.Type[][] = [];
- let i: number;
+ const combined: ts.Type[][] = [];
+ let i: number;
- for (i = 0; i < previous.length; i += 1) {
- combined.push([...previous[i]]);
+ for (i = 0; i < previous.length; i += 1) {
+ combined.push([...previous[i]]);
- if (i < next.length && next[i] !== undefined) {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- combined[i].push(next[i]!);
- }
- }
+ if (i < next.length && next[i] !== undefined) {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ combined[i].push(next[i]!);
+ }
+ }
- for (i; i < next.length; i += 1) {
- if (next[i] !== undefined) {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- combined.push([next[i]!]);
- }
- }
+ for (i; i < next.length; i += 1) {
+ if (next[i] !== undefined) {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ combined.push([next[i]!]);
+ }
+ }
- return combined;
+ return combined;
};
-const printFunctionType = (request: FileMutationsRequest, combinedType: CombinedFunctionType) => {
- return [
- "(",
- combinedType.parameters?.map((parameter, index) => `arg${index}: ${request.services.printers.type(parameter)}`).join(", "),
- ") => ",
- combinedType.returnValue?.length ? request.services.printers.type(combinedType.returnValue) : "void",
- ";",
- ].join("");
+const printFunctionType = (
+ request: FileMutationsRequest,
+ combinedType: CombinedFunctionType,
+) => {
+ return [
+ "(",
+ combinedType.parameters
+ .map(
+ (parameter, index) =>
+ `arg${index}: ${request.services.printers.type(parameter)}`,
+ )
+ .join(", "),
+ ") => ",
+ combinedType.returnValue?.length
+ ? request.services.printers.type(combinedType.returnValue)
+ : "void",
+ ";",
+ ].join("");
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/index.ts
index 1fb22d482..43d6e2aa6 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropFunctionsFromCalls/index.ts
@@ -1,30 +1,39 @@
-import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../../shared/fileMutator";
-import { isReactComponentNode, ReactComponentNode } from "../reactFiltering/isReactComponentNode";
-
-import { getComponentPropsNode } from "../getComponentPropsNode";
-import { collectAllFunctionCallTypes } from "./collectAllFunctionCallTypes";
-import { createFunctionCallTypesMutation } from "./createFunctionCallTypesMutation";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes.js";
+import { getComponentPropsNode } from "../getComponentPropsNode.js";
+import {
+ ReactComponentNode,
+ isReactComponentNode,
+} from "../reactFiltering/isReactComponentNode.js";
+import { collectAllFunctionCallTypes } from "./collectAllFunctionCallTypes.js";
+import { createFunctionCallTypesMutation } from "./createFunctionCallTypesMutation.js";
/**
* Expands a component's props declared as Function to be more specific types.
*/
export const fixReactPropFunctionsFromCalls: FileMutator = (request) => {
- return collectMutationsFromNodes(request, isReactComponentNode, visitReactComponentNode);
+ return collectMutationsFromNodes(
+ request,
+ isReactComponentNode,
+ visitReactComponentNode,
+ );
};
-const visitReactComponentNode = (node: ReactComponentNode, request: FileMutationsRequest) => {
- // Grab the node used to declare the node's props type, if it exists
- const propsNode = getComponentPropsNode(request, node);
- if (propsNode === undefined) {
- return undefined;
- }
+const visitReactComponentNode = (
+ node: ReactComponentNode,
+ request: FileMutationsRequest,
+) => {
+ // Grab the node used to declare the node's props type, if it exists
+ const propsNode = getComponentPropsNode(request, node);
+ if (propsNode === undefined) {
+ return undefined;
+ }
- // Find all Function prop calls used internally within the node
- const allFunctionCallTypes = collectAllFunctionCallTypes(request, propsNode);
- if (allFunctionCallTypes === undefined) {
- return undefined;
- }
+ // Find all Function prop calls used internally within the node
+ const allFunctionCallTypes = collectAllFunctionCallTypes(request, propsNode);
- return createFunctionCallTypesMutation(request, allFunctionCallTypes);
+ return createFunctionCallTypesMutation(request, allFunctionCallTypes);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/getComponentAssignedTypesFromUsage.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/getComponentAssignedTypesFromUsage.ts
index 6ccb282a0..3698ade60 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/getComponentAssignedTypesFromUsage.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/getComponentAssignedTypesFromUsage.ts
@@ -1,76 +1,85 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { AssignedTypesByName } from "../../../../../mutations/assignments";
-import { getStaticNameOfProperty } from "../../../../../shared/names";
-import { getTypeAtLocationIfNotError } from "../../../../../shared/types";
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-import { ReactComponentNode } from "../reactFiltering/isReactComponentNode";
+import { AssignedTypesByName } from "../../../../../mutations/assignments.js";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
+import { getStaticNameOfProperty } from "../../../../../shared/names.js";
+import { getTypeAtLocationIfNotError } from "../../../../../shared/types.js";
+import { ReactComponentNode } from "../reactFiltering/isReactComponentNode.js";
/**
* Finds all assigned types for props in each JSX usage of a React component.
*/
export const getComponentAssignedTypesFromUsage = (
- request: FileMutationsRequest,
- node: ReactComponentNode,
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
): AssignedTypesByName[] | undefined => {
- const references = getComponentReferences(request, node);
- if (references === undefined) {
- return undefined;
- }
+ const references = getComponentReferences(request, node);
+ if (references === undefined) {
+ return undefined;
+ }
- const assignedTypes: AssignedTypesByName[] = [];
+ const assignedTypes: AssignedTypesByName[] = [];
- // For each referencing location, update types if the node is used as a component there
- for (const reference of references) {
- updateAssignedTypesForReference(reference, assignedTypes, request);
- }
+ // For each referencing location, update types if the node is used as a component there
+ for (const reference of references) {
+ updateAssignedTypesForReference(reference, assignedTypes, request);
+ }
- return assignedTypes;
+ return assignedTypes;
};
-const getComponentReferences = (request: FileMutationsRequest, node: ReactComponentNode) => {
- const referencesNode = ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node) ? node : node.parent;
+const getComponentReferences = (
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+) => {
+ const referencesNode =
+ ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node)
+ ? node
+ : node.parent;
- return request.fileInfoCache.getNodeReferencesAsNodes(referencesNode);
+ return request.fileInfoCache.getNodeReferencesAsNodes(referencesNode);
};
const updateAssignedTypesForReference = (
- identifier: ts.Node,
- componentAssignedTypes: AssignedTypesByName[],
- request: FileMutationsRequest,
+ identifier: ts.Node,
+ componentAssignedTypes: AssignedTypesByName[],
+ request: FileMutationsRequest,
): void => {
- // In order to assign props, the referencing node should be an identifier...
- if (!ts.isIdentifier(identifier)) {
- return;
- }
+ // In order to assign props, the referencing node should be an identifier...
+ if (!ts.isIdentifier(identifier)) {
+ return;
+ }
- // ...inside a starting JSX element
- const jsxElement = identifier.parent;
- if (!ts.isJsxSelfClosingElement(jsxElement) && !ts.isJsxOpeningElement(jsxElement)) {
- return;
- }
+ // ...inside a starting JSX element
+ const jsxElement = identifier.parent;
+ if (
+ !ts.isJsxSelfClosingElement(jsxElement) &&
+ !ts.isJsxOpeningElement(jsxElement)
+ ) {
+ return;
+ }
- // For each property passed in this element's attributes, grab its name and type into a map
- const assignedTypes: AssignedTypesByName = new Map();
+ // For each property passed in this element's attributes, grab its name and type into a map
+ const assignedTypes: AssignedTypesByName = new Map();
- for (const property of jsxElement.attributes.properties) {
- // Ignore properties that aren't directly JSX attributes
- if (!ts.isJsxAttribute(property)) {
- continue;
- }
+ for (const property of jsxElement.attributes.properties) {
+ // Ignore properties that aren't directly JSX attributes
+ if (!ts.isJsxAttribute(property)) {
+ continue;
+ }
- // For now, ignore any property with a name that's not immediately convertable to a string
- const name = getStaticNameOfProperty(property.name);
- if (name === undefined) {
- continue;
- }
+ // For now, ignore any property with a name that's not immediately convertible to a string
+ const name = getStaticNameOfProperty(property.name);
+ if (name === undefined) {
+ continue;
+ }
- // TypeScript stores the type of the property's value on the property itself
- const propertyType = getTypeAtLocationIfNotError(request, property);
- if (propertyType !== undefined) {
- assignedTypes.set(name, propertyType);
- }
- }
+ // TypeScript stores the type of the property's value on the property itself
+ const propertyType = getTypeAtLocationIfNotError(request, property);
+ if (propertyType !== undefined) {
+ assignedTypes.set(name, propertyType);
+ }
+ }
- componentAssignedTypes.push(assignedTypes);
+ componentAssignedTypes.push(assignedTypes);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/index.ts
index 9c7bc3bf6..93d6bd357 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromLaterAssignments/index.ts
@@ -1,30 +1,52 @@
-import { createTypeExpansionMutation } from "../../../../../mutations/expansions/expansionMutations";
-import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../../shared/fileMutator";
-import { isReactComponentNode, ReactComponentNode } from "../reactFiltering/isReactComponentNode";
-
-import { getComponentAssignedTypesFromUsage } from "./getComponentAssignedTypesFromUsage";
-import { getComponentPropsNode } from "../getComponentPropsNode";
+import { createTypeExpansionMutation } from "../../../../../mutations/expansions/expansionMutations.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes.js";
+import { getComponentPropsNode } from "../getComponentPropsNode.js";
+import {
+ ReactComponentNode,
+ isReactComponentNode,
+} from "../reactFiltering/isReactComponentNode.js";
+import { getComponentAssignedTypesFromUsage } from "./getComponentAssignedTypesFromUsage.js";
/**
* Expands the existing props type for a component from its external JSX-style declarations.
*/
export const fixReactPropsFromLaterAssignments: FileMutator = (request) => {
- return collectMutationsFromNodes(request, isReactComponentNode, visitReactComponentNode);
+ return collectMutationsFromNodes(
+ request,
+ isReactComponentNode,
+ visitReactComponentNode,
+ );
};
-const visitReactComponentNode = (node: ReactComponentNode, request: FileMutationsRequest) => {
- // Grab the node used to declare the node's props type, if it exists
- const propsNode = getComponentPropsNode(request, node);
- if (propsNode === undefined) {
- return undefined;
- }
+const visitReactComponentNode = (
+ node: ReactComponentNode,
+ request: FileMutationsRequest,
+) => {
+ // Grab the node used to declare the node's props type, if it exists
+ const propsNode = getComponentPropsNode(request, node);
+ if (propsNode === undefined) {
+ return undefined;
+ }
- // Find all types of props later passed to the node
- const componentAssignedTypes = getComponentAssignedTypesFromUsage(request, node);
- if (componentAssignedTypes === undefined || componentAssignedTypes.length === 0) {
- return undefined;
- }
+ // Find all types of props later passed to the node
+ const componentAssignedTypes = getComponentAssignedTypesFromUsage(
+ request,
+ node,
+ );
+ if (
+ componentAssignedTypes === undefined ||
+ componentAssignedTypes.length === 0
+ ) {
+ return undefined;
+ }
- return createTypeExpansionMutation(request, propsNode, componentAssignedTypes);
+ return createTypeExpansionMutation(
+ request,
+ propsNode,
+ componentAssignedTypes,
+ );
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/annotation/createInterfaceUsageMutation.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/annotation/createInterfaceUsageMutation.ts
index 28fd927f4..04119747b 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/annotation/createInterfaceUsageMutation.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/annotation/createInterfaceUsageMutation.ts
@@ -1,38 +1,51 @@
import { TextInsertMutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { getClassExtendsType } from "../../../../../../shared/nodes";
-import { ReactClassComponentNode, ReactComponentNode, ReactFunctionalComponentNode } from "../../reactFiltering/isReactComponentNode";
+import { getClassExtendsType } from "../../../../../../shared/nodes.js";
+import {
+ ReactClassComponentNode,
+ ReactComponentNode,
+ ReactFunctionalComponentNode,
+} from "../../reactFiltering/isReactComponentNode.js";
-export const createInterfaceUsageMutation = (node: ReactComponentNode, interfaceName: string): TextInsertMutation | undefined => {
- return ts.isClassLike(node)
- ? createClassInterfaceUsageMutation(node, interfaceName)
- : createFunctionLikeInterfaceUsageMutation(node, interfaceName);
+export const createInterfaceUsageMutation = (
+ node: ReactComponentNode,
+ interfaceName: string,
+): TextInsertMutation | undefined => {
+ return ts.isClassLike(node)
+ ? createClassInterfaceUsageMutation(node, interfaceName)
+ : createFunctionLikeInterfaceUsageMutation(node, interfaceName);
};
-const createClassInterfaceUsageMutation = (node: ReactClassComponentNode, interfaceName: string): TextInsertMutation | undefined => {
- const extension = getClassExtendsType(node);
- if (extension === undefined) {
- return undefined;
- }
+const createClassInterfaceUsageMutation = (
+ node: ReactClassComponentNode,
+ interfaceName: string,
+): TextInsertMutation | undefined => {
+ const extension = getClassExtendsType(node);
+ if (extension === undefined) {
+ return undefined;
+ }
- return {
- insertion: `<${interfaceName}>`,
- range: {
- begin: extension.end,
- },
- type: "text-insert",
- };
+ return {
+ insertion: `<${interfaceName}>`,
+ range: {
+ begin: extension.end,
+ },
+ type: "text-insert",
+ };
};
-const createFunctionLikeInterfaceUsageMutation = (node: ReactFunctionalComponentNode, interfaceName: string): TextInsertMutation => {
- const propsArgument = node.parameters[0];
+const createFunctionLikeInterfaceUsageMutation = (
+ node: ReactFunctionalComponentNode,
+ interfaceName: string,
+): TextInsertMutation => {
+ const propsArgument = node.parameters[0];
- return {
- insertion: `: ${interfaceName}`,
- range: {
- begin: propsArgument.end,
- },
- type: "text-insert",
- };
+ return {
+ insertion: `: ${interfaceName}`,
+ range: {
+ begin: propsArgument.end,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/index.ts
index 58bfb389e..a71d3d4d6 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/index.ts
@@ -1,73 +1,96 @@
-import { combineMutations, Mutation, TextInsertMutation } from "automutate";
-import * as ts from "typescript";
+import { Mutation, TextInsertMutation, combineMutations } from "automutate";
+import ts from "typescript";
-import { ReactPropTypesHint } from "../../../../../options/enums";
-import { getClassExtendsType } from "../../../../../shared/nodes";
-import { printNewLine } from "../../../../../shared/printing/newlines";
-import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../../shared/fileMutator";
-import { isReactComponentNode, ReactComponentNode } from "../reactFiltering/isReactComponentNode";
-
-import { createInterfaceUsageMutation } from "./annotation/createInterfaceUsageMutation";
-import { createInterfaceFromPropTypes } from "./propTypes/createInterfaceFromPropTypes";
-import { getPropTypesValue } from "./propTypes/getPropTypesValue";
+import { ReactPropTypesHint } from "../../../../../options/enums.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../../shared/fileMutator.js";
+import { getClassExtendsType } from "../../../../../shared/nodes.js";
+import { printNewLine } from "../../../../../shared/printing/newlines.js";
+import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes.js";
+import {
+ ReactComponentNode,
+ isReactComponentNode,
+} from "../reactFiltering/isReactComponentNode.js";
+import { createInterfaceUsageMutation } from "./annotation/createInterfaceUsageMutation.js";
+import { createInterfaceFromPropTypes } from "./propTypes/createInterfaceFromPropTypes.js";
+import { getPropTypesValue } from "./propTypes/getPropTypesValue.js";
/**
* Creates an initial props type for a component from its PropTypes declaration.
*/
-export const fixReactPropsFromPropTypes: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- if (request.options.hints.react.propTypes === ReactPropTypesHint.Ignore) {
- return [];
- }
+export const fixReactPropsFromPropTypes: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ if (request.options.hints.react.propTypes === ReactPropTypesHint.Ignore) {
+ return [];
+ }
- return collectMutationsFromNodes(request, isReactComponentNode, visitReactComponentNode);
+ return collectMutationsFromNodes(
+ request,
+ isReactComponentNode,
+ visitReactComponentNode,
+ );
};
-const visitReactComponentNode = (node: ReactComponentNode, request: FileMutationsRequest): Mutation | undefined => {
- // If the node is a class declaration, don't bother with prop types if it already declares a React.Component template
- if (ts.isClassDeclaration(node)) {
- const extendsType = getClassExtendsType(node);
+const visitReactComponentNode = (
+ node: ReactComponentNode,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // If the node is a class declaration, don't bother with prop types if it already declares a React.Component template
+ if (ts.isClassDeclaration(node)) {
+ const extendsType = getClassExtendsType(node);
- if (extendsType?.typeArguments !== undefined && extendsType.typeArguments.length > 0) {
- return undefined;
- }
- }
+ if (
+ extendsType?.typeArguments !== undefined &&
+ extendsType.typeArguments.length > 0
+ ) {
+ return undefined;
+ }
+ }
- // Try to find a static `propTypes` member to indicate the interface
- // If it doesn't exist, we can't infer anything about the component here, so we bail out
- const propTypes = getPropTypesValue(node);
- if (propTypes === undefined) {
- return undefined;
- }
+ // Try to find a static `propTypes` member to indicate the interface
+ // If it doesn't exist, we can't infer anything about the component here, so we bail out
+ const propTypes = getPropTypesValue(node);
+ if (propTypes === undefined) {
+ return undefined;
+ }
- // Since we did find the propTypes object, we can generate an interface from its members
- const { interfaceName, interfaceNode } = createInterfaceFromPropTypes(request, node, propTypes);
+ // Since we did find the propTypes object, we can generate an interface from its members
+ const { interfaceName, interfaceNode } = createInterfaceFromPropTypes(
+ request,
+ node,
+ propTypes,
+ );
- // That interface will be injected with blank lines around it just before the component
- const mutations: Mutation[] = [createInterfaceCreationMutation(request, node, interfaceNode)];
+ // That interface will be injected with blank lines around it just before the component
+ const mutations: Mutation[] = [
+ createInterfaceCreationMutation(request, node, interfaceNode),
+ ];
- // We'll also annotate the component with a type declaration to use the new prop type
- const usage = createInterfaceUsageMutation(node, interfaceName);
- if (usage !== undefined) {
- mutations.push(usage);
- }
+ // We'll also annotate the component with a type declaration to use the new prop type
+ const usage = createInterfaceUsageMutation(node, interfaceName);
+ if (usage !== undefined) {
+ mutations.push(usage);
+ }
- return combineMutations(...mutations);
+ return combineMutations(...mutations);
};
const createInterfaceCreationMutation = (
- request: FileMutationsRequest,
- node: ReactComponentNode,
- interfaceNode: ts.InterfaceDeclaration,
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+ interfaceNode: ts.InterfaceDeclaration,
): TextInsertMutation => {
- const endline = printNewLine(request.options.compilerOptions);
- const interfaceNodeText = request.services.printers.node(interfaceNode);
+ const endline = printNewLine(request.options.compilerOptions);
+ const interfaceNodeText = request.services.printers.node(interfaceNode);
- return {
- insertion: [endline, endline, interfaceNodeText, endline].join(""),
- range: {
- begin: node.pos,
- },
- type: "text-insert",
- };
+ return {
+ insertion: [endline, endline, interfaceNodeText, endline].join(""),
+ range: {
+ begin: node.pos,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/createInterfaceFromPropTypes.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/createInterfaceFromPropTypes.ts
index d9f8dbbef..561b1ed37 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/createInterfaceFromPropTypes.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/createInterfaceFromPropTypes.ts
@@ -1,34 +1,33 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutationsRequest } from "../../../../../../shared/fileMutator";
-import { getApparentNameOfComponent } from "../../getApparentNameOfComponent";
-import { ReactComponentNode } from "../../reactFiltering/isReactComponentNode";
-
-import { createPropTypesProperty } from "./propTypesProperties";
+import { FileMutationsRequest } from "../../../../../../shared/fileMutator.js";
+import { getApparentNameOfComponent } from "../../getApparentNameOfComponent.js";
+import { ReactComponentNode } from "../../reactFiltering/isReactComponentNode.js";
+import { createPropTypesProperty } from "./propTypesProperties.js";
export const createInterfaceFromPropTypes = (
- request: FileMutationsRequest,
- node: ReactComponentNode,
- propTypes: ts.ObjectLiteralExpression,
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+ propTypes: ts.ObjectLiteralExpression,
) => {
- const members: ts.TypeElement[] = [];
+ const members: ts.TypeElement[] = [];
- for (const rawProperty of propTypes.properties) {
- const member = createPropTypesProperty(request, rawProperty);
- if (member !== undefined) {
- members.push(member);
- }
- }
+ for (const rawProperty of propTypes.properties) {
+ const member = createPropTypesProperty(request, rawProperty);
+ if (member !== undefined) {
+ members.push(member);
+ }
+ }
- const interfaceName = `${getApparentNameOfComponent(request, node)}Props`;
+ const interfaceName = `${getApparentNameOfComponent(request, node)}Props`;
- const interfaceNode = ts.factory.createInterfaceDeclaration(
- undefined /* modifiers */,
- interfaceName,
- undefined /* typeParameters */,
- undefined /* heritageClauses */,
- members,
- );
+ const interfaceNode = ts.factory.createInterfaceDeclaration(
+ undefined /* modifiers */,
+ interfaceName,
+ undefined /* typeParameters */,
+ undefined /* heritageClauses */,
+ members,
+ );
- return { interfaceName, interfaceNode };
+ return { interfaceName, interfaceNode };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/getPropTypesValue.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/getPropTypesValue.ts
index 57239c43c..607dc934f 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/getPropTypesValue.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/getPropTypesValue.ts
@@ -1,91 +1,101 @@
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { ReactComponentNode } from "../../reactFiltering/isReactComponentNode";
+import { ReactComponentNode } from "../../reactFiltering/isReactComponentNode.js";
type PropTypesMember = ts.PropertyDeclaration & {
- initializer: ts.ObjectLiteralExpression;
- name: {
- kind: ts.SyntaxKind.Identifier;
- text: "propTypes";
- };
+ initializer: ts.ObjectLiteralExpression;
+ name: {
+ kind: ts.SyntaxKind.Identifier;
+ text: "propTypes";
+ };
};
/**
* @returns Whether a node is a `propTypes` class member with an object literal value.
*/
const getStaticPropTypes = (node: ts.ClassElement): node is PropTypesMember =>
- ts.isPropertyDeclaration(node) &&
- tsutils.includesModifier(node.modifiers as ts.NodeArray, ts.SyntaxKind.StaticKeyword) &&
- ts.isIdentifier(node.name) &&
- node.name.text === "propTypes" &&
- node.initializer !== undefined &&
- ts.isObjectLiteralExpression(node.initializer);
+ ts.isPropertyDeclaration(node) &&
+ tsutils.includesModifier(
+ node.modifiers as ts.NodeArray,
+ ts.SyntaxKind.StaticKeyword,
+ ) &&
+ ts.isIdentifier(node.name) &&
+ node.name.text === "propTypes" &&
+ node.initializer !== undefined &&
+ ts.isObjectLiteralExpression(node.initializer);
const getPropTypesChildFromParent = (parent: ts.Node, className: string) => {
- let result: ts.ObjectLiteralExpression | undefined;
+ let result: ts.ObjectLiteralExpression | undefined;
- parent.forEachChild((child: ts.Node) => {
- const propTypes = isPropTypesStatement(child, className);
- if (propTypes !== undefined) {
- result = propTypes;
- return true;
- }
+ parent.forEachChild((child: ts.Node) => {
+ const propTypes = isPropTypesStatement(child, className);
+ if (propTypes !== undefined) {
+ result = propTypes;
+ return true;
+ }
- return false;
- });
+ return false;
+ });
- return result;
+ return result;
};
/**
* @returns Object literal `propTypes` assigned to the class, if it exists in a sibling property setter.
*/
const isPropTypesStatement = (node: ts.Node, className: string) => {
- if (!ts.isExpressionStatement(node) || !ts.isBinaryExpression(node.expression)) {
- return undefined;
- }
+ if (
+ !ts.isExpressionStatement(node) ||
+ !ts.isBinaryExpression(node.expression)
+ ) {
+ return undefined;
+ }
- const { left, right } = node.expression;
- if (
- !ts.isPropertyAccessExpression(left) ||
- !ts.isIdentifier(left.expression) ||
- left.expression.text !== className ||
- !ts.isIdentifier(left.name) ||
- left.name.text !== "propTypes" ||
- !ts.isObjectLiteralExpression(right)
- ) {
- return undefined;
- }
+ const { left, right } = node.expression;
+ if (
+ !ts.isPropertyAccessExpression(left) ||
+ !ts.isIdentifier(left.expression) ||
+ left.expression.text !== className ||
+ !ts.isIdentifier(left.name) ||
+ left.name.text !== "propTypes" ||
+ !ts.isObjectLiteralExpression(right)
+ ) {
+ return undefined;
+ }
- return right;
+ return right;
};
/**
* Finds the equivalent `propTypes` object literal for a class, if it exists.
- *
* @todo
* This assumes an object literal (`{ ... }`) with all inline members.
* It doesn't yet handle shared variable references or `...` spread operations.
*/
-export const getPropTypesValue = (node: ReactComponentNode): ts.ObjectLiteralExpression | undefined => {
- // If the component's parent declares a prop types for it, use it
- if (node.name !== undefined) {
- const propTypesStatement = getPropTypesChildFromParent(node.parent, node.name.text);
- if (propTypesStatement !== undefined) {
- return propTypesStatement;
- }
- }
+export const getPropTypesValue = (
+ node: ReactComponentNode,
+): ts.ObjectLiteralExpression | undefined => {
+ // If the component's parent declares a prop types for it, use it
+ if (node.name !== undefined) {
+ const propTypesStatement = getPropTypesChildFromParent(
+ node.parent,
+ node.name.text,
+ );
+ if (propTypesStatement !== undefined) {
+ return propTypesStatement;
+ }
+ }
- // If the component is a class that declares its own static prop types, use it
- if (ts.isClassDeclaration(node)) {
- const staticPropTypes = node.members.find(getStaticPropTypes);
+ // If the component is a class that declares its own static prop types, use it
+ if (ts.isClassDeclaration(node)) {
+ const staticPropTypes = node.members.find(getStaticPropTypes);
- if (staticPropTypes !== undefined) {
- return staticPropTypes.initializer;
- }
- }
+ if (staticPropTypes !== undefined) {
+ return staticPropTypes.initializer;
+ }
+ }
- // Since none of the above worked out, assume no prop types are declared
- return undefined;
+ // Since none of the above worked out, assume no prop types are declared
+ return undefined;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesExtraction.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesExtraction.ts
index 154cacfca..a1dedf1a5 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesExtraction.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesExtraction.ts
@@ -1,42 +1,41 @@
-import * as ts from "typescript";
+import ts from "typescript";
/**
* Description of a single prop type via PropTypes.
*/
export interface PropTypesMembers {
- /**
- * Parent node of the name node.
- */
- accessNode: PropTypesAccessNode;
-
- /**
- * `.isRequired` ending node, if it exists.
- */
- isRequired?: ts.Identifier | ts.PrivateIdentifier;
-
- /**
- * Node representing the name of the type, such as `number` or `shape`.
- */
- nameNode: ts.Identifier | ts.PrivateIdentifier;
+ /**
+ * Parent node of the name node.
+ */
+ accessNode: PropTypesAccessNode;
+
+ /**
+ * `.isRequired` ending node, if it exists.
+ */
+ isRequired?: ts.Identifier | ts.PrivateIdentifier;
+
+ /**
+ * Node representing the name of the type, such as `number` or `shape`.
+ */
+ nameNode: ts.Identifier | ts.PrivateIdentifier;
}
/**
* Node type that can represent the value for a PropTypes description.
*/
export type PropTypesAccessNode =
- /**
- * Called descriptor, such as `PropTypes.shapeOf({ ... })`.
- */
- | ts.CallExpression
+ /**
+ * Called descriptor, such as `PropTypes.shapeOf({ ... })`.
+ */
+ | ts.CallExpression
- /**
- * Simple string descriptor, such as `PropTypes.number`.
- */
- | ts.PropertyAccessExpression;
+ /**
+ * Simple string descriptor, such as `PropTypes.number`.
+ */
+ | ts.PropertyAccessExpression;
/**
* Selects the relevant member nodes for a PropTypes member expression.
- *
* @param node
* PropTypes assignment in an object literal, as one of:
* `PropTypes.number`
@@ -44,82 +43,87 @@ export type PropTypesAccessNode =
* `PropTypes.shape({})`
* `PropTypes.shape({}).isRequired`
*/
-export const getPropTypesMember = (node: ts.Expression): PropTypesMembers | undefined => {
- if (ts.isCallExpression(node)) {
- return getPropTypesMemberFromCallExpression(node);
- }
+export const getPropTypesMember = (
+ node: ts.Expression,
+): PropTypesMembers | undefined => {
+ if (ts.isCallExpression(node)) {
+ return getPropTypesMemberFromCallExpression(node);
+ }
- if (ts.isPropertyAccessExpression(node)) {
- return getPropTypesMemberFromPropertyAccessExpression(node);
- }
+ if (ts.isPropertyAccessExpression(node)) {
+ return getPropTypesMemberFromPropertyAccessExpression(node);
+ }
- return undefined;
+ return undefined;
};
/**
- * @remarks
* Must be like `PropTypes.shape({})`, as `.isRequired` would make this a property access expression.
*/
-const getPropTypesMemberFromCallExpression = (node: ts.CallExpression): PropTypesMembers | undefined => {
- const accessNode = node.expression;
- if (!ts.isPropertyAccessExpression(accessNode)) {
- return undefined;
- }
+const getPropTypesMemberFromCallExpression = (
+ node: ts.CallExpression,
+): PropTypesMembers | undefined => {
+ const accessNode = node.expression;
+ if (!ts.isPropertyAccessExpression(accessNode)) {
+ return undefined;
+ }
- const nameNode = accessNode.name;
+ const nameNode = accessNode.name;
- return { accessNode, nameNode };
+ return { accessNode, nameNode };
};
/**
- * @remarks
* Must be like `PropTypes.number`, `PropTypes.number.isRequired`, or `PropTypes.shape({}).isRequired`.
*/
-const getPropTypesMemberFromPropertyAccessExpression = (node: ts.PropertyAccessExpression): PropTypesMembers | undefined => {
- const isRequired = node.name.text === "isRequired" ? node.name : undefined;
+const getPropTypesMemberFromPropertyAccessExpression = (
+ node: ts.PropertyAccessExpression,
+): PropTypesMembers | undefined => {
+ const isRequired = node.name.text === "isRequired" ? node.name : undefined;
- return isRequired === undefined
- ? getPropTypesMemberFromPropertyAccessExpressionOptional(node)
- : getPropTypesMemberFromPropertyAccessExpressionRequired(node, isRequired);
+ return isRequired === undefined
+ ? getPropTypesMemberFromPropertyAccessExpressionOptional(node)
+ : getPropTypesMemberFromPropertyAccessExpressionRequired(node, isRequired);
};
/**
- * @remarks
* Must be like `PropTypes.number`.
*/
-const getPropTypesMemberFromPropertyAccessExpressionOptional = (node: ts.PropertyAccessExpression): PropTypesMembers | undefined => {
- return { accessNode: node, nameNode: node.name };
+const getPropTypesMemberFromPropertyAccessExpressionOptional = (
+ node: ts.PropertyAccessExpression,
+): PropTypesMembers | undefined => {
+ return { accessNode: node, nameNode: node.name };
};
/**
- * @remarks
* Must be like `PropTypes.shape({}).isRequired` or `PropTypes.number.isRequired`.
*/
const getPropTypesMemberFromPropertyAccessExpressionRequired = (
- node: ts.PropertyAccessExpression,
- isRequired: ts.Identifier | ts.PrivateIdentifier,
+ node: ts.PropertyAccessExpression,
+ isRequired: ts.Identifier | ts.PrivateIdentifier,
): PropTypesMembers | undefined => {
- const { expression } = node;
-
- if (ts.isCallExpression(expression)) {
- const callExpressionTypesMember = getPropTypesMemberFromCallExpression(expression);
- if (callExpressionTypesMember === undefined) {
- return undefined;
- }
-
- return {
- ...callExpressionTypesMember,
- isRequired,
- };
- }
-
- if (!ts.isPropertyAccessExpression(expression)) {
- return undefined;
- }
-
- return {
- accessNode: expression,
- isRequired,
- nameNode: expression.name,
- };
+ const { expression } = node;
+
+ if (ts.isCallExpression(expression)) {
+ const callExpressionTypesMember =
+ getPropTypesMemberFromCallExpression(expression);
+ if (callExpressionTypesMember === undefined) {
+ return undefined;
+ }
+
+ return {
+ ...callExpressionTypesMember,
+ isRequired,
+ };
+ }
+
+ if (!ts.isPropertyAccessExpression(expression)) {
+ return undefined;
+ }
+
+ return {
+ accessNode: expression,
+ isRequired,
+ nameNode: expression.name,
+ };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesProperties.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesProperties.ts
index d65d2f4e3..bf416536f 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesProperties.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesProperties.ts
@@ -1,38 +1,51 @@
-import * as ts from "typescript";
-import { ReactPropTypesOptionality } from "../../../../../../options/enums";
-import { FileMutationsRequest } from "../../../../../../shared/fileMutator";
+import ts from "typescript";
-import { getPropTypesMember } from "./propTypesExtraction";
-import { createPropTypesTransform } from "./propTypesTransforms";
+import { ReactPropTypesOptionality } from "../../../../../../options/enums.js";
+import { FileMutationsRequest } from "../../../../../../shared/fileMutator.js";
+import { getPropTypesMember } from "./propTypesExtraction.js";
+import { createPropTypesTransform } from "./propTypesTransforms.js";
/**
* Creates a type signature node for a raw PropTypes object literal property.
*/
-export const createPropTypesProperty = (request: FileMutationsRequest, rawProperty: ts.ObjectLiteralElementLike) => {
- if (!ts.isPropertyAssignment(rawProperty) || !ts.isIdentifier(rawProperty.name)) {
- return undefined;
- }
+export const createPropTypesProperty = (
+ request: FileMutationsRequest,
+ rawProperty: ts.ObjectLiteralElementLike,
+) => {
+ if (
+ !ts.isPropertyAssignment(rawProperty) ||
+ !ts.isIdentifier(rawProperty.name)
+ ) {
+ return undefined;
+ }
- const propTypesMembers = getPropTypesMember(rawProperty.initializer);
- if (propTypesMembers === undefined) {
- return undefined;
- }
+ const propTypesMembers = getPropTypesMember(rawProperty.initializer);
+ if (propTypesMembers === undefined) {
+ return undefined;
+ }
- const memberTypeNode = createPropTypesTransform(request, propTypesMembers);
- if (memberTypeNode === undefined) {
- return undefined;
- }
+ const memberTypeNode = createPropTypesTransform(request, propTypesMembers);
+ if (memberTypeNode === undefined) {
+ return undefined;
+ }
- return ts.factory.createPropertySignature(
- undefined /* modifiers */,
- ts.factory.createIdentifier(rawProperty.name.text),
- getQuestionToken(!!propTypesMembers.isRequired, request.options.hints.react.propTypesOptionality),
- memberTypeNode,
- );
+ return ts.factory.createPropertySignature(
+ undefined /* modifiers */,
+ ts.factory.createIdentifier(rawProperty.name.text),
+ getQuestionToken(
+ !!propTypesMembers.isRequired,
+ request.options.hints.react.propTypesOptionality,
+ ),
+ memberTypeNode,
+ );
};
-const getQuestionToken = (isRequired: boolean, optionality: ReactPropTypesOptionality) => {
- return optionality === ReactPropTypesOptionality.AlwaysOptional || (!isRequired && optionality === ReactPropTypesOptionality.AsWritten)
- ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
- : undefined;
+const getQuestionToken = (
+ isRequired: boolean,
+ optionality: ReactPropTypesOptionality,
+) => {
+ return optionality === ReactPropTypesOptionality.AlwaysOptional ||
+ (!isRequired && optionality === ReactPropTypesOptionality.AsWritten)
+ ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
+ : undefined;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesTransforms.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesTransforms.ts
index 7427048a3..2edc929b8 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesTransforms.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/propTypes/propTypesTransforms.ts
@@ -1,161 +1,210 @@
-import * as ts from "typescript";
-
-import { KnownTypeLiteralNode, transformLiteralToTypeLiteralNode } from "../../../../../../shared/transforms";
-import { FileMutationsRequest } from "../../../../../../shared/fileMutator";
-
-import { getPropTypesMember, PropTypesAccessNode, PropTypesMembers } from "./propTypesExtraction";
-import { createPropTypesProperty } from "./propTypesProperties";
+import ts from "typescript";
+
+import { FileMutationsRequest } from "../../../../../../shared/fileMutator.js";
+import {
+ KnownTypeLiteralNode,
+ transformLiteralToTypeLiteralNode,
+} from "../../../../../../shared/transforms.js";
+import {
+ PropTypesAccessNode,
+ PropTypesMembers,
+ getPropTypesMember,
+} from "./propTypesExtraction.js";
+import { createPropTypesProperty } from "./propTypesProperties.js";
export const createPropTypesTransform = (
- request: FileMutationsRequest,
- { accessNode, nameNode }: Exclude,
+ request: FileMutationsRequest,
+ { accessNode, nameNode }: Exclude,
): ts.TypeNode | undefined => {
- switch (nameNode.text) {
- case "array":
- return ts.factory.createArrayTypeNode(ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword));
+ switch (nameNode.text) {
+ case "array":
+ return ts.factory.createArrayTypeNode(
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
+ );
- case "arrayOf":
- return createArrayOfTransform(request, accessNode);
+ case "arrayOf":
+ return createArrayOfTransform(request, accessNode);
- case "bool":
- return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
+ case "bool":
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
- case "func":
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Function"), undefined);
+ case "func":
+ return ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier("Function"),
+ undefined,
+ );
- case "element":
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("React.ReactElement"), undefined);
+ case "element":
+ return ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier("React.ReactElement"),
+ undefined,
+ );
- case "instanceOf":
- return createInstanceOfTransform(accessNode);
+ case "instanceOf":
+ return createInstanceOfTransform(accessNode);
- case "number":
- return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
+ case "number":
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
- case "node":
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("React.ReactNode"), undefined);
+ case "node":
+ return ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier("React.ReactNode"),
+ undefined,
+ );
- case "object":
- return ts.factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword);
+ case "object":
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword);
- case "oneOf":
- return createOneOfTransform(accessNode);
+ case "oneOf":
+ return createOneOfTransform(accessNode);
- case "oneOfType":
- return createOneOfTypeTransform(request, accessNode);
+ case "oneOfType":
+ return createOneOfTypeTransform(request, accessNode);
- case "shape":
- return createShapeTransform(request, accessNode);
+ case "shape":
+ return createShapeTransform(request, accessNode);
- case "string":
- return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
+ case "string":
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
- case "symbol":
- return ts.factory.createKeywordTypeNode(ts.SyntaxKind.SymbolKeyword);
- }
+ case "symbol":
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.SymbolKeyword);
+ }
- return undefined;
+ return undefined;
};
-const createArrayOfTransform = (request: FileMutationsRequest, accessNode: PropTypesAccessNode) => {
- if (!ts.isCallExpression(accessNode.parent) || accessNode.parent.arguments.length !== 1) {
- return undefined;
- }
-
- const memberTypeNode = getPropTypesMember(accessNode.parent.arguments[0]);
- if (memberTypeNode === undefined) {
- return undefined;
- }
-
- const innerTransform = createPropTypesTransform(request, memberTypeNode);
- if (innerTransform === undefined) {
- return undefined;
- }
-
- return ts.factory.createArrayTypeNode(innerTransform);
+const createArrayOfTransform = (
+ request: FileMutationsRequest,
+ accessNode: PropTypesAccessNode,
+) => {
+ if (
+ !ts.isCallExpression(accessNode.parent) ||
+ accessNode.parent.arguments.length !== 1
+ ) {
+ return undefined;
+ }
+
+ const memberTypeNode = getPropTypesMember(accessNode.parent.arguments[0]);
+ if (memberTypeNode === undefined) {
+ return undefined;
+ }
+
+ const innerTransform = createPropTypesTransform(request, memberTypeNode);
+ if (innerTransform === undefined) {
+ return undefined;
+ }
+
+ return ts.factory.createArrayTypeNode(innerTransform);
};
const createInstanceOfTransform = (accessNode: PropTypesAccessNode) => {
- if (!ts.isCallExpression(accessNode.parent) || accessNode.parent.arguments.length !== 1) {
- return undefined;
- }
-
- const className = accessNode.parent.arguments[0];
- if (!ts.isIdentifier(className)) {
- return undefined;
- }
-
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(className.text), undefined);
+ if (
+ !ts.isCallExpression(accessNode.parent) ||
+ accessNode.parent.arguments.length !== 1
+ ) {
+ return undefined;
+ }
+
+ const className = accessNode.parent.arguments[0];
+ if (!ts.isIdentifier(className)) {
+ return undefined;
+ }
+
+ return ts.factory.createTypeReferenceNode(
+ ts.factory.createIdentifier(className.text),
+ undefined,
+ );
};
const createOneOfTransform = (accessNode: PropTypesAccessNode) => {
- if (!ts.isCallExpression(accessNode.parent) || accessNode.parent.arguments.length !== 1) {
- return undefined;
- }
-
- const allowedItems = accessNode.parent.arguments[0];
- if (!ts.isArrayLiteralExpression(allowedItems)) {
- return undefined;
- }
-
- const allowedTypes = allowedItems.elements
- .map(transformLiteralToTypeLiteralNode)
- .filter((typeNode): typeNode is KnownTypeLiteralNode => typeNode !== undefined);
- if (allowedTypes.length === 0) {
- return undefined;
- }
-
- return ts.factory.createUnionTypeNode(allowedTypes);
+ if (
+ !ts.isCallExpression(accessNode.parent) ||
+ accessNode.parent.arguments.length !== 1
+ ) {
+ return undefined;
+ }
+
+ const allowedItems = accessNode.parent.arguments[0];
+ if (!ts.isArrayLiteralExpression(allowedItems)) {
+ return undefined;
+ }
+
+ const allowedTypes = allowedItems.elements
+ .map(transformLiteralToTypeLiteralNode)
+ .filter(
+ (typeNode): typeNode is KnownTypeLiteralNode => typeNode !== undefined,
+ );
+ if (allowedTypes.length === 0) {
+ return undefined;
+ }
+
+ return ts.factory.createUnionTypeNode(allowedTypes);
};
-const createOneOfTypeTransform = (request: FileMutationsRequest, accessNode: PropTypesAccessNode) => {
- if (!ts.isCallExpression(accessNode.parent) || accessNode.parent.arguments.length !== 1) {
- return undefined;
- }
-
- const allowedItems = accessNode.parent.arguments[0];
- if (!ts.isArrayLiteralExpression(allowedItems)) {
- return undefined;
- }
-
- const allowedTypes = allowedItems.elements
- .map((element) => {
- if (!ts.isPropertyAccessExpression(element) || !ts.isIdentifier(element.name)) {
- return undefined;
- }
-
- return createPropTypesTransform(request, {
- accessNode: element,
- nameNode: element.name,
- });
- })
- .filter((typeName): typeName is ts.TypeNode => typeName !== undefined);
- if (allowedTypes.length === 0) {
- return undefined;
- }
-
- return ts.factory.createUnionTypeNode(allowedTypes);
+const createOneOfTypeTransform = (
+ request: FileMutationsRequest,
+ accessNode: PropTypesAccessNode,
+) => {
+ if (
+ !ts.isCallExpression(accessNode.parent) ||
+ accessNode.parent.arguments.length !== 1
+ ) {
+ return undefined;
+ }
+
+ const allowedItems = accessNode.parent.arguments[0];
+ if (!ts.isArrayLiteralExpression(allowedItems)) {
+ return undefined;
+ }
+
+ const allowedTypes = allowedItems.elements
+ .map((element) => {
+ if (
+ !ts.isPropertyAccessExpression(element) ||
+ !ts.isIdentifier(element.name)
+ ) {
+ return undefined;
+ }
+
+ return createPropTypesTransform(request, {
+ accessNode: element,
+ nameNode: element.name,
+ });
+ })
+ .filter((typeName): typeName is ts.TypeNode => typeName !== undefined);
+ if (allowedTypes.length === 0) {
+ return undefined;
+ }
+
+ return ts.factory.createUnionTypeNode(allowedTypes);
};
-const createShapeTransform = (request: FileMutationsRequest, accessNode: PropTypesAccessNode) => {
- if (!ts.isCallExpression(accessNode.parent) || accessNode.parent.arguments.length !== 1) {
- return undefined;
- }
-
- const shape = accessNode.parent.arguments[0];
- // Todo: handle shared variables and `...` object spreads
- if (!ts.isObjectLiteralExpression(shape)) {
- return undefined;
- }
-
- const members: ts.TypeElement[] = [];
-
- for (const rawProperty of shape.properties) {
- const member = createPropTypesProperty(request, rawProperty);
- if (member !== undefined) {
- members.push(member);
- }
- }
-
- return ts.factory.createTypeLiteralNode(members);
+const createShapeTransform = (
+ request: FileMutationsRequest,
+ accessNode: PropTypesAccessNode,
+) => {
+ if (
+ !ts.isCallExpression(accessNode.parent) ||
+ accessNode.parent.arguments.length !== 1
+ ) {
+ return undefined;
+ }
+
+ const shape = accessNode.parent.arguments[0];
+ // Todo: handle shared variables and `...` object spreads
+ if (!ts.isObjectLiteralExpression(shape)) {
+ return undefined;
+ }
+
+ const members: ts.TypeElement[] = [];
+
+ for (const rawProperty of shape.properties) {
+ const member = createPropTypesProperty(request, rawProperty);
+ if (member !== undefined) {
+ members.push(member);
+ }
+ }
+
+ return ts.factory.createTypeLiteralNode(members);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/getPropsUsageTypes.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/getPropsUsageTypes.ts
index 3df46decf..a53338ead 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/getPropsUsageTypes.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/getPropsUsageTypes.ts
@@ -1,121 +1,162 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { AssignedTypesByName } from "../../../../../mutations/assignments";
-import { getDeclaredTypesOfArgument } from "../../../../../shared/calls";
-import { isNodeWithinNode } from "../../../../../shared/nodes";
+import { AssignedTypesByName } from "../../../../../mutations/assignments.js";
+import { getDeclaredTypesOfArgument } from "../../../../../shared/calls.js";
+import { FileMutationsRequest } from "../../../../../shared/fileMutator.js";
import {
- isNodeWithIdentifierName,
- isPropertySignatureWithStaticName,
- PropertySignatureWithStaticName,
-} from "../../../../../shared/nodeTypes";
-import { getSymbolAtLocationIfNotError, getTypeAtLocationIfNotError } from "../../../../../shared/types";
-import { FileMutationsRequest } from "../../../../../shared/fileMutator";
-import { getComponentPropsNode, ReactComponentPropsNode } from "../getComponentPropsNode";
-import { getPropNodeFromReference } from "../getPropNodeFromReference";
-import { getReactComponentNode } from "../reactFiltering/getReactComponentNode";
-import { ReactComponentNode } from "../reactFiltering/isReactComponentNode";
+ PropertySignatureWithStaticName,
+ isNodeWithIdentifierName,
+ isPropertySignatureWithStaticName,
+} from "../../../../../shared/nodeTypes.js";
+import { isNodeWithinNode } from "../../../../../shared/nodes.js";
+import {
+ getSymbolAtLocationIfNotError,
+ getTypeAtLocationIfNotError,
+} from "../../../../../shared/types.js";
+import {
+ ReactComponentPropsNode,
+ getComponentPropsNode,
+} from "../getComponentPropsNode.js";
+import { getPropNodeFromReference } from "../getPropNodeFromReference.js";
+import { getReactComponentNode } from "../reactFiltering/getReactComponentNode.js";
+import { ReactComponentNode } from "../reactFiltering/isReactComponentNode.js";
export const getPropsUsageTypes = (
- request: FileMutationsRequest,
- componentNode: ReactComponentNode,
- propsNode: ReactComponentPropsNode,
+ request: FileMutationsRequest,
+ componentNode: ReactComponentNode,
+ propsNode: ReactComponentPropsNode,
) => {
- const allAssignedTypes: AssignedTypesByName[] = [];
-
- for (const member of propsNode.members) {
- if (isPropertySignatureWithStaticName(member)) {
- updateAssignedTypesForReferences(request, member, componentNode, member.name, new Set(), allAssignedTypes);
- }
- }
-
- return allAssignedTypes;
+ const allAssignedTypes: AssignedTypesByName[] = [];
+
+ for (const member of propsNode.members) {
+ if (isPropertySignatureWithStaticName(member)) {
+ updateAssignedTypesForReferences(
+ request,
+ member,
+ componentNode,
+ member.name,
+ new Set(),
+ allAssignedTypes,
+ );
+ }
+ }
+
+ return allAssignedTypes;
};
const updateAssignedTypesForReferences = (
- request: FileMutationsRequest,
- member: PropertySignatureWithStaticName,
- componentNode: ReactComponentNode,
- start: ts.Node,
- seenNodes: Set,
- allAssignedTypes: AssignedTypesByName[],
+ request: FileMutationsRequest,
+ member: PropertySignatureWithStaticName,
+ componentNode: ReactComponentNode,
+ start: ts.Node,
+ seenNodes: Set,
+ allAssignedTypes: AssignedTypesByName[],
) => {
- // Don't repeatedly bounce back and forth between references
- if (seenNodes.has(start)) {
- return;
- }
- seenNodes.add(start);
-
- // Find all references to the name of the type within the component
- const references = request.fileInfoCache
- .getNodeReferencesAsNodes(start)
- ?.filter((reference) => isNodeWithinNode(request.sourceFile, reference, componentNode));
- if (references === undefined || references.length === 0) {
- return;
- }
-
- // For each reference, try to infer the type from its usage...
- for (const reference of references) {
- // (except for the original member we're looking around)
- if (reference === member) {
- continue;
- }
-
- // If the reference is an indirect storage, such as a variable, recurse on *its* references
- if (!ts.isExpression(reference)) {
- updateAssignedTypesForReferences(request, member, componentNode, reference, seenNodes, allAssignedTypes);
- continue;
- }
-
- const propUsage = getPropNodeFromReference(reference);
-
- // Case: used as the value in a JSX attribute
- if (ts.isJsxExpression(propUsage.parent)) {
- // Use the type value for the declaration of that attribute (its own prop)
- const attributePropType = getAttributePropType(request, propUsage.parent.parent);
- if (attributePropType !== undefined) {
- allAssignedTypes.push(new Map([[member.name.text, attributePropType]]));
- }
-
- continue;
- }
-
- // Case: passed as an argument to a function
- if (ts.isCallExpression(propUsage.parent) || ts.isNewExpression(propUsage.parent)) {
- const declaredTypes = getDeclaredTypesOfArgument(request, propUsage.parent, propUsage);
-
- for (const declaredType of declaredTypes) {
- allAssignedTypes.push(new Map([[member.name.text, declaredType]]));
- }
- }
- }
+ // Don't repeatedly bounce back and forth between references
+ if (seenNodes.has(start)) {
+ return;
+ }
+
+ seenNodes.add(start);
+
+ // Find all references to the name of the type within the component
+ const references = request.fileInfoCache
+ .getNodeReferencesAsNodes(start)
+ ?.filter((reference) =>
+ isNodeWithinNode(request.sourceFile, reference, componentNode),
+ );
+ if (references === undefined || references.length === 0) {
+ return;
+ }
+
+ // For each reference, try to infer the type from its usage...
+ for (const reference of references) {
+ // (except for the original member we're looking around)
+ if (reference === member) {
+ continue;
+ }
+
+ // If the reference is an indirect storage, such as a variable, recurse on *its* references
+ if (!ts.isExpression(reference)) {
+ updateAssignedTypesForReferences(
+ request,
+ member,
+ componentNode,
+ reference,
+ seenNodes,
+ allAssignedTypes,
+ );
+ continue;
+ }
+
+ const propUsage = getPropNodeFromReference(reference);
+
+ // Case: used as the value in a JSX attribute
+ if (ts.isJsxExpression(propUsage.parent)) {
+ // Use the type value for the declaration of that attribute (its own prop)
+ const attributePropType = getAttributePropType(
+ request,
+ propUsage.parent.parent,
+ );
+ if (attributePropType !== undefined) {
+ allAssignedTypes.push(new Map([[member.name.text, attributePropType]]));
+ }
+
+ continue;
+ }
+
+ // Case: passed as an argument to a function
+ if (
+ ts.isCallExpression(propUsage.parent) ||
+ ts.isNewExpression(propUsage.parent)
+ ) {
+ const declaredTypes = getDeclaredTypesOfArgument(
+ request,
+ propUsage.parent,
+ propUsage,
+ );
+
+ for (const declaredType of declaredTypes) {
+ allAssignedTypes.push(new Map([[member.name.text, declaredType]]));
+ }
+ }
+ }
};
-const getAttributePropType = (request: FileMutationsRequest, attribute: ts.Node) => {
- if (!ts.isJsxAttribute(attribute) || !isNodeWithIdentifierName(attribute)) {
- return undefined;
- }
-
- // Find the corresponding declaration or (containing variable) for the node's backing React component
- // In theory we could try to get the symbol or type at the location,
- // but in practice it seems that always resolves to the (potentially incomplete) provided type
- const { tagName } = attribute.parent.parent;
- const tagDeclaration = getSymbolAtLocationIfNotError(request, tagName)?.valueDeclaration;
- if (tagDeclaration === undefined) {
- return undefined;
- }
-
- // Get the React component associated with the declaration
- const tagComponent = getReactComponentNode(tagDeclaration);
- if (tagComponent === undefined) {
- return undefined;
- }
-
- // Find the props node declaration for that component,
- // and within that, the specific prop declaration
- const tagProps = getComponentPropsNode(request, tagComponent);
- const propDeclaration = tagProps?.members.find(
- (member) => isNodeWithIdentifierName(member) && member.name.text === attribute.name.text,
- );
-
- return getTypeAtLocationIfNotError(request, propDeclaration);
+const getAttributePropType = (
+ request: FileMutationsRequest,
+ attribute: ts.Node,
+) => {
+ if (!ts.isJsxAttribute(attribute) || !isNodeWithIdentifierName(attribute)) {
+ return undefined;
+ }
+
+ // Find the corresponding declaration or (containing variable) for the node's backing React component
+ // In theory we could try to get the symbol or type at the location,
+ // but in practice it seems that always resolves to the (potentially incomplete) provided type
+ const { tagName } = attribute.parent.parent;
+ const tagDeclaration = getSymbolAtLocationIfNotError(
+ request,
+ tagName,
+ )?.valueDeclaration;
+ if (tagDeclaration === undefined) {
+ return undefined;
+ }
+
+ // Get the React component associated with the declaration
+ const tagComponent = getReactComponentNode(tagDeclaration);
+ if (tagComponent === undefined) {
+ return undefined;
+ }
+
+ // Find the props node declaration for that component,
+ // and within that, the specific prop declaration
+ const tagProps = getComponentPropsNode(request, tagComponent);
+ const propDeclaration = tagProps?.members.find(
+ (member) =>
+ isNodeWithIdentifierName(member) &&
+ member.name.text === attribute.name.text,
+ );
+
+ return getTypeAtLocationIfNotError(request, propDeclaration);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/index.ts
index e6843a1ee..65a078e3f 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromUses/index.ts
@@ -1,30 +1,46 @@
-import { createTypeExpansionMutation } from "../../../../../mutations/expansions/expansionMutations";
-import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../../shared/fileMutator";
-import { isReactComponentNode, ReactComponentNode } from "../reactFiltering/isReactComponentNode";
-
-import { getComponentPropsNode } from "../getComponentPropsNode";
-import { getPropsUsageTypes } from "./getPropsUsageTypes";
+import { createTypeExpansionMutation } from "../../../../../mutations/expansions/expansionMutations.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../../collectMutationsFromNodes.js";
+import { getComponentPropsNode } from "../getComponentPropsNode.js";
+import {
+ ReactComponentNode,
+ isReactComponentNode,
+} from "../reactFiltering/isReactComponentNode.js";
+import { getPropsUsageTypes } from "./getPropsUsageTypes.js";
/**
* Expands the existing props type for a component from its external JSX-style declarations.
*/
export const fixReactPropsFromUses: FileMutator = (request) => {
- return collectMutationsFromNodes(request, isReactComponentNode, visitReactComponentNode);
+ return collectMutationsFromNodes(
+ request,
+ isReactComponentNode,
+ visitReactComponentNode,
+ );
};
-const visitReactComponentNode = (node: ReactComponentNode, request: FileMutationsRequest) => {
- // Grab the node used to declare the node's props type, if it exists
- const propsNode = getComponentPropsNode(request, node);
- if (propsNode === undefined) {
- return undefined;
- }
+const visitReactComponentNode = (
+ node: ReactComponentNode,
+ request: FileMutationsRequest,
+) => {
+ // Grab the node used to declare the node's props type, if it exists
+ const propsNode = getComponentPropsNode(request, node);
+ if (propsNode === undefined) {
+ return undefined;
+ }
- // Find all types of props later passed to the node
- const componentAssignedTypes = getPropsUsageTypes(request, node, propsNode);
- if (componentAssignedTypes === undefined || componentAssignedTypes.length === 0) {
- return undefined;
- }
+ // Find all types of props later passed to the node
+ const componentAssignedTypes = getPropsUsageTypes(request, node, propsNode);
+ if (!componentAssignedTypes.length) {
+ return undefined;
+ }
- return createTypeExpansionMutation(request, propsNode, componentAssignedTypes);
+ return createTypeExpansionMutation(
+ request,
+ propsNode,
+ componentAssignedTypes,
+ );
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsMissing.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsMissing.ts
index c4ffc5ff6..656c40ec5 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsMissing.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsMissing.ts
@@ -1,189 +1,226 @@
import { combineMutations } from "automutate";
-import * as ts from "typescript";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
-import { isReactComponentNode, ReactComponentNode } from "./reactFiltering/isReactComponentNode";
-import { getComponentPropsNode } from "./getComponentPropsNode";
-import { getApparentNameOfComponent } from "./getApparentNameOfComponent";
-import { printNewLine } from "../../../../shared/printing/newlines";
+import ts from "typescript";
+
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { printNewLine } from "../../../../shared/printing/newlines.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+import { getApparentNameOfComponent } from "./getApparentNameOfComponent.js";
+import { getComponentPropsNode } from "./getComponentPropsNode.js";
+import {
+ ReactComponentNode,
+ isReactComponentNode,
+} from "./reactFiltering/isReactComponentNode.js";
/**
* Creates a new props type for a React component from scratch.
*/
export const fixReactPropsMissing: FileMutator = (request) => {
- return collectMutationsFromNodes(request, isReactComponentNode, visitReactComponentNode);
+ return collectMutationsFromNodes(
+ request,
+ isReactComponentNode,
+ visitReactComponentNode,
+ );
};
-const visitReactComponentNode = (node: ReactComponentNode, request: FileMutationsRequest) => {
- // Make sure a node doesn't yet exist to declare the node's props type
- const propsNode = getComponentPropsNode(request, node);
- if (propsNode !== undefined) {
- return undefined;
- }
-
- // Find all types of props later passed to the node
- const attributeTypesAndRequirements = collectComponentAttributeTypes(request, node);
- if (!attributeTypesAndRequirements?.attributeTypes.size) {
- return undefined;
- }
-
- // Generate a name for a new props interface to use on the node
- const interfaceName = `${getApparentNameOfComponent(request, node)}Props`;
-
- return combineMutations(
- // That interface will be injected with blank lines around it just before the component
- createPropsTypeCreationMutation(request, node, interfaceName, attributeTypesAndRequirements),
- // We'll also annotate the component with a type declaration to use the new prop type
- createPropsTypeUsageMutation(node, interfaceName),
- );
+const visitReactComponentNode = (
+ node: ReactComponentNode,
+ request: FileMutationsRequest,
+) => {
+ // Make sure a node doesn't yet exist to declare the node's props type
+ const propsNode = getComponentPropsNode(request, node);
+ if (propsNode !== undefined) {
+ return undefined;
+ }
+
+ // Find all types of props later passed to the node
+ const attributeTypesAndRequirements = collectComponentAttributeTypes(
+ request,
+ node,
+ );
+ if (!attributeTypesAndRequirements?.attributeTypes.size) {
+ return undefined;
+ }
+
+ // Generate a name for a new props interface to use on the node
+ const interfaceName = `${getApparentNameOfComponent(request, node)}Props`;
+
+ return combineMutations(
+ // That interface will be injected with blank lines around it just before the component
+ createPropsTypeCreationMutation(
+ request,
+ node,
+ interfaceName,
+ attributeTypesAndRequirements,
+ ),
+ // We'll also annotate the component with a type declaration to use the new prop type
+ createPropsTypeUsageMutation(node, interfaceName),
+ );
};
-const collectComponentAttributeTypes = (request: FileMutationsRequest, node: ReactComponentNode) => {
- // Find all references to the node, if there are more than just the node itself
- const references = request.fileInfoCache.getNodeReferencesAsNodes(
- node.parent.kind === ts.SyntaxKind.VariableDeclaration ? node.parent : node,
- );
- if (references === undefined || references.length === 0) {
- return undefined;
- }
-
- const allAttributeNames = new Set();
- const allAttributeNameUses: Set[] = [];
- const attributeTypes = new Map();
-
- // For each reference, try to collect attribute type from its usage...
- for (const reference of references) {
- // ...assuming the reference is a JSX element used with attributes
- const attributesElement = getAttributesElement(reference);
- if (attributesElement === undefined) {
- continue;
- }
-
- // Keep track of attribute names that are used, so later we can figure out which are optional
- const usedAttributeNames: string[] = [];
-
- for (const attribute of attributesElement.attributes.properties) {
- // Only look at JSX attributes, like prop={value} and prop
- if (!ts.isJsxAttribute(attribute)) {
- continue;
- }
-
- // Attempt to retrieve the type of the prop's value
- const typeChecker = request.services.program.getTypeChecker();
- const valueType = getAttributeValueType(typeChecker, attribute);
- if (valueType === undefined) {
- continue;
- }
-
- // Widen literals such as `false` to their primitives such as `boolean`
- const type = typeChecker.getBaseTypeOfLiteralType(valueType);
-
- // Add the type underneath the attribute name
- const name = ts.isJsxNamespacedName(attribute.name) ? attribute.name.getText(request.sourceFile) : attribute.name.text;
- const types = attributeTypes.get(name);
- if (types === undefined) {
- attributeTypes.set(name, [type]);
- } else {
- types.push(type);
- }
-
- // Remember the attribute name in all attributes, and in this usage (element)
- allAttributeNames.add(name);
- usedAttributeNames.push(name);
- }
-
- allAttributeNameUses.push(new Set(usedAttributeNames));
- }
-
- // Mark only the attributes that appear in every usage as required
- const requiredAttributeNames = new Set(
- Array.from(allAttributeNames).filter((attributeName) =>
- allAttributeNameUses.every((attributeNameUses) => attributeNameUses.has(attributeName)),
- ),
- );
-
- return { attributeTypes, requiredAttributeNames };
+const collectComponentAttributeTypes = (
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+) => {
+ // Find all references to the node, if there are more than just the node itself
+ const references = request.fileInfoCache.getNodeReferencesAsNodes(
+ node.parent.kind === ts.SyntaxKind.VariableDeclaration ? node.parent : node,
+ );
+ if (references === undefined || references.length === 0) {
+ return undefined;
+ }
+
+ const allAttributeNames = new Set();
+ const allAttributeNameUses: Set[] = [];
+ const attributeTypes = new Map();
+
+ // For each reference, try to collect attribute type from its usage...
+ for (const reference of references) {
+ // ...assuming the reference is a JSX element used with attributes
+ const attributesElement = getAttributesElement(reference);
+ if (attributesElement === undefined) {
+ continue;
+ }
+
+ // Keep track of attribute names that are used, so later we can figure out which are optional
+ const usedAttributeNames: string[] = [];
+
+ for (const attribute of attributesElement.attributes.properties) {
+ // Only look at JSX attributes, like prop={value} and prop
+ if (!ts.isJsxAttribute(attribute)) {
+ continue;
+ }
+
+ // Attempt to retrieve the type of the prop's value
+ const typeChecker = request.services.program.getTypeChecker();
+ const valueType = getAttributeValueType(typeChecker, attribute);
+ if (valueType === undefined) {
+ continue;
+ }
+
+ // Widen literals such as `false` to their primitives such as `boolean`
+ const type = typeChecker.getBaseTypeOfLiteralType(valueType);
+
+ // Add the type underneath the attribute name
+ const name = ts.isJsxNamespacedName(attribute.name)
+ ? attribute.name.getText(request.sourceFile)
+ : attribute.name.text;
+ const types = attributeTypes.get(name);
+ if (types === undefined) {
+ attributeTypes.set(name, [type]);
+ } else {
+ types.push(type);
+ }
+
+ // Remember the attribute name in all attributes, and in this usage (element)
+ allAttributeNames.add(name);
+ usedAttributeNames.push(name);
+ }
+
+ allAttributeNameUses.push(new Set(usedAttributeNames));
+ }
+
+ // Mark only the attributes that appear in every usage as required
+ const requiredAttributeNames = new Set(
+ Array.from(allAttributeNames).filter((attributeName) =>
+ allAttributeNameUses.every((attributeNameUses) =>
+ attributeNameUses.has(attributeName),
+ ),
+ ),
+ );
+
+ return { attributeTypes, requiredAttributeNames };
};
const getAttributesElement = (reference: ts.Node) => {
- if (!ts.isIdentifier(reference)) {
- return undefined;
- }
+ if (!ts.isIdentifier(reference)) {
+ return undefined;
+ }
- const { parent } = reference;
+ const { parent } = reference;
- if (ts.isJsxElement(parent)) {
- return parent.openingElement;
- }
+ if (ts.isJsxElement(parent)) {
+ return parent.openingElement;
+ }
- if (ts.isJsxSelfClosingElement(parent)) {
- return parent;
- }
+ if (ts.isJsxSelfClosingElement(parent)) {
+ return parent;
+ }
- return undefined;
+ return undefined;
};
-const getAttributeValueType = (typeChecker: ts.TypeChecker, attribute: ts.JsxAttribute) => {
- if (attribute.initializer) {
- if (ts.isStringLiteral(attribute.initializer)) {
- return typeChecker.getTypeAtLocation(attribute);
- }
-
- return ts.isJsxExpression(attribute.initializer) && attribute.initializer.expression
- ? typeChecker.getTypeAtLocation(attribute.initializer.expression)
- : undefined;
- }
-
- return typeChecker.getTypeAtLocation(attribute.name);
+const getAttributeValueType = (
+ typeChecker: ts.TypeChecker,
+ attribute: ts.JsxAttribute,
+) => {
+ if (attribute.initializer) {
+ if (ts.isStringLiteral(attribute.initializer)) {
+ return typeChecker.getTypeAtLocation(attribute);
+ }
+
+ return ts.isJsxExpression(attribute.initializer) &&
+ attribute.initializer.expression
+ ? typeChecker.getTypeAtLocation(attribute.initializer.expression)
+ : undefined;
+ }
+
+ return typeChecker.getTypeAtLocation(attribute.name);
};
interface AttributeTypesAndRequirements {
- attributeTypes: Map;
- requiredAttributeNames: Set;
+ attributeTypes: Map;
+ requiredAttributeNames: Set;
}
const createPropsTypeCreationMutation = (
- request: FileMutationsRequest,
- node: ReactComponentNode,
- interfaceName: string,
- { attributeTypes, requiredAttributeNames }: AttributeTypesAndRequirements,
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+ interfaceName: string,
+ { attributeTypes, requiredAttributeNames }: AttributeTypesAndRequirements,
) => {
- const endline = printNewLine(request.options.compilerOptions);
-
- return {
- insertion: [
- endline,
- `interface ${interfaceName} {`,
- ...Array.from(attributeTypes).map(
- ([name, type]) => `${name}${requiredAttributeNames.has(name) ? "" : "?"}: ${request.services.printers.type(type)};`,
- ),
- `}`,
- ].join(endline),
- range: {
- begin: ts.isClassDeclaration(node)
- ? node.pos
- : ts.isVariableDeclaration(node.parent)
- ? node.parent.parent.pos
- : node.parent.pos,
- },
- type: "text-insert",
- };
+ const endline = printNewLine(request.options.compilerOptions);
+
+ return {
+ insertion: [
+ endline,
+ `interface ${interfaceName} {`,
+ ...Array.from(attributeTypes).map(
+ ([name, type]) =>
+ `${name}${requiredAttributeNames.has(name) ? "" : "?"}: ${request.services.printers.type(type)};`,
+ ),
+ `}`,
+ ].join(endline),
+ range: {
+ begin: ts.isClassDeclaration(node)
+ ? node.pos
+ : ts.isVariableDeclaration(node.parent)
+ ? node.parent.parent.pos
+ : node.parent.pos,
+ },
+ type: "text-insert",
+ };
};
-const createPropsTypeUsageMutation = (node: ReactComponentNode, interfaceName: string) => {
- return ts.isFunctionLike(node)
- ? {
- insertion: `: ${interfaceName}`,
- range: {
- begin: node.parameters[0].end,
- },
- type: "text-insert",
- }
- : {
- insertion: `<${interfaceName}>`,
- range: {
- begin: node.heritageClauses[0].end,
- },
- type: "text-insert",
- };
+const createPropsTypeUsageMutation = (
+ node: ReactComponentNode,
+ interfaceName: string,
+) => {
+ return ts.isFunctionLike(node)
+ ? {
+ insertion: `: ${interfaceName}`,
+ range: {
+ begin: node.parameters[0].end,
+ },
+ type: "text-insert",
+ }
+ : {
+ insertion: `<${interfaceName}>`,
+ range: {
+ begin: node.heritageClauses[0].end,
+ },
+ type: "text-insert",
+ };
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getApparentNameOfComponent.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getApparentNameOfComponent.ts
index b81c80609..1b5b0be65 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getApparentNameOfComponent.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getApparentNameOfComponent.ts
@@ -1,28 +1,39 @@
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { getFriendlyFileName } from "../../../../shared/fileNames";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
-import { ReactComponentNode } from "./reactFiltering/isReactComponentNode";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { getFriendlyFileName } from "../../../../shared/fileNames.js";
+import { ReactComponentNode } from "./reactFiltering/isReactComponentNode.js";
/**
* @returns The name of a class or function component, if determinable.
*/
-export const getApparentNameOfComponent = (request: FileMutationsRequest, node: ReactComponentNode) => {
- // If the node itself has a name, great!
- if (node.name !== undefined) {
- return node.name.text;
- }
+export const getApparentNameOfComponent = (
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+) => {
+ // If the node itself has a name, great!
+ if (node.name !== undefined) {
+ return node.name.text;
+ }
- // If the node in a single named variable declaration, use that
- if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
- return node.parent.name.text;
- }
+ // If the node in a single named variable declaration, use that
+ if (
+ ts.isVariableDeclaration(node.parent) &&
+ ts.isIdentifier(node.parent.name)
+ ) {
+ return node.parent.name.text;
+ }
- // If the node is the default export of its file, use the file's name
- if (tsutils.includesModifier(node.modifiers as ts.NodeArray, ts.SyntaxKind.DefaultKeyword)) {
- return getFriendlyFileName(request.sourceFile.fileName);
- }
+ // If the node is the default export of its file, use the file's name
+ if (
+ tsutils.includesModifier(
+ node.modifiers as ts.NodeArray,
+ ts.SyntaxKind.DefaultKeyword,
+ )
+ ) {
+ return getFriendlyFileName(request.sourceFile.fileName);
+ }
- return "AnonymousComponent";
+ return "AnonymousComponent";
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getComponentPropsNode.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getComponentPropsNode.ts
index e4675bad7..a3e4df7a6 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getComponentPropsNode.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getComponentPropsNode.ts
@@ -1,71 +1,92 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { getClassExtendsType } from "../../../../shared/nodes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { getClassExtendsType } from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
import {
- ReactClassComponentNode,
- ReactComponentNode,
- ReactFunctionalComponentNode as ReactFunctionComponentNode,
-} from "./reactFiltering/isReactComponentNode";
+ ReactClassComponentNode,
+ ReactComponentNode,
+ ReactFunctionalComponentNode as ReactFunctionComponentNode,
+} from "./reactFiltering/isReactComponentNode.js";
-export type ReactComponentPropsNode = ts.InterfaceDeclaration | ts.TypeLiteralNode;
+export type ReactComponentPropsNode =
+ | ts.InterfaceDeclaration
+ | ts.TypeLiteralNode;
/**
* Finds the corresponding interface or type literal that declares a component's props type, if it exists.
*/
-export const getComponentPropsNode = (request: FileMutationsRequest, node: ReactComponentNode): ReactComponentPropsNode | undefined => {
- return ts.isClassDeclaration(node) || ts.isClassExpression(node)
- ? getClassComponentPropsNode(request, node)
- : getFunctionComponentPropsNode(request, node);
+export const getComponentPropsNode = (
+ request: FileMutationsRequest,
+ node: ReactComponentNode,
+): ReactComponentPropsNode | undefined => {
+ return ts.isClassDeclaration(node) || ts.isClassExpression(node)
+ ? getClassComponentPropsNode(request, node)
+ : getFunctionComponentPropsNode(request, node);
};
-const getClassComponentPropsNode = (request: FileMutationsRequest, node: ReactClassComponentNode): ReactComponentPropsNode | undefined => {
- const extendsType = getClassExtendsType(node);
- if (extendsType?.typeArguments === undefined || extendsType.typeArguments.length === 0) {
- return undefined;
- }
+const getClassComponentPropsNode = (
+ request: FileMutationsRequest,
+ node: ReactClassComponentNode,
+): ReactComponentPropsNode | undefined => {
+ const extendsType = getClassExtendsType(node);
+ if (
+ extendsType?.typeArguments === undefined ||
+ extendsType.typeArguments.length === 0
+ ) {
+ return undefined;
+ }
- const [rawPropsNode] = extendsType.typeArguments;
- const propsNodeType = getTypeAtLocationIfNotError(request, rawPropsNode);
- const propsNodeSymbol = propsNodeType?.getSymbol();
- if (propsNodeSymbol === undefined) {
- return undefined;
- }
+ const [rawPropsNode] = extendsType.typeArguments;
+ const propsNodeType = getTypeAtLocationIfNotError(request, rawPropsNode);
+ const propsNodeSymbol = propsNodeType?.getSymbol();
+ if (propsNodeSymbol === undefined) {
+ return undefined;
+ }
- const symbolDeclarations = propsNodeSymbol.getDeclarations();
- const declaration = symbolDeclarations === undefined || symbolDeclarations.length === 0 ? undefined : symbolDeclarations[0];
+ const symbolDeclarations = propsNodeSymbol.getDeclarations();
+ const declaration =
+ symbolDeclarations === undefined || symbolDeclarations.length === 0
+ ? undefined
+ : symbolDeclarations[0];
- return declaration !== undefined && isReactComponentPropsNode(declaration) ? declaration : undefined;
+ return declaration !== undefined && isReactComponentPropsNode(declaration)
+ ? declaration
+ : undefined;
};
const getFunctionComponentPropsNode = (
- request: FileMutationsRequest,
- node: ReactFunctionComponentNode,
+ request: FileMutationsRequest,
+ node: ReactFunctionComponentNode,
): ReactComponentPropsNode | undefined => {
- // If the node takes multiple parameters, we assume it's not an FC
- // TODO: this might not hold true for refs or other fancy things...
- const { parameters } = node;
- if (parameters.length !== 1) {
- return undefined;
- }
+ // If the node takes multiple parameters, we assume it's not an FC
+ // TODO: this might not hold true for refs or other fancy things...
+ const { parameters } = node;
+ if (parameters.length !== 1) {
+ return undefined;
+ }
- // Try to get the first backing type declaration for the single parameter
- const [parameter] = parameters;
- const symbol = getTypeAtLocationIfNotError(request, parameter)?.getSymbol();
- if (!symbol?.declarations?.length) {
- return undefined;
- }
+ // Try to get the first backing type declaration for the single parameter
+ const [parameter] = parameters;
+ const symbol = getTypeAtLocationIfNotError(request, parameter)?.getSymbol();
+ if (!symbol?.declarations?.length) {
+ return undefined;
+ }
- const [declaration] = symbol.declarations;
- // If the declaration is in another file... well, let's assume it's unrelated.
- // TODO: We'll eventually need to handle shared props types.
- if (isReactComponentPropsNode(declaration) && declaration.getSourceFile() === request.sourceFile) {
- return declaration;
- }
+ const [declaration] = symbol.declarations;
+ // If the declaration is in another file... well, let's assume it's unrelated.
+ // TODO: We'll eventually need to handle shared props types.
+ if (
+ isReactComponentPropsNode(declaration) &&
+ declaration.getSourceFile() === request.sourceFile
+ ) {
+ return declaration;
+ }
- return undefined;
+ return undefined;
};
-const isReactComponentPropsNode = (node: ts.Node): node is ReactComponentPropsNode =>
- ts.isInterfaceDeclaration(node) || ts.isTypeLiteralNode(node);
+const isReactComponentPropsNode = (
+ node: ts.Node,
+): node is ReactComponentPropsNode =>
+ ts.isInterfaceDeclaration(node) || ts.isTypeLiteralNode(node);
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getPropNodeFromReference.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getPropNodeFromReference.ts
index 7c62b562f..25ddfefa7 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getPropNodeFromReference.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/getPropNodeFromReference.ts
@@ -1,6 +1,10 @@
-import * as ts from "typescript";
+import ts from "typescript";
-export const getPropNodeFromReference = (reference: ts.Expression): ts.Expression => {
- // Case: class-style (e.g. 'this.props.key') or object style 'props.key'
- return ts.isPropertyAccessExpression(reference.parent) ? reference.parent : reference;
+export const getPropNodeFromReference = (
+ reference: ts.Expression,
+): ts.Expression => {
+ // Case: class-style (e.g. 'this.props.key') or object style 'props.key'
+ return ts.isPropertyAccessExpression(reference.parent)
+ ? reference.parent
+ : reference;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/index.ts
index 1f04ef8bf..8196468c3 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/index.ts
@@ -1,25 +1,24 @@
-import { findFirstMutations } from "../../../../shared/runtime";
-import { FileMutationsRequest } from "../../../../shared/fileMutator";
-
-import { fixReactPropsFromLaterAssignments } from "./fixReactPropsFromLaterAssignments";
-import { fixReactPropsFromUses } from "./fixReactPropsFromUses";
-import { fixReactPropsFromPropTypes } from "./fixReactPropsFromPropTypes";
-import { fixReactPropFunctionsFromCalls } from "./fixReactPropFunctionsFromCalls";
-import { fixReactPropsMissing } from "./fixReactPropsMissing";
+import { FileMutationsRequest } from "../../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../../shared/runtime.js";
+import { fixReactPropFunctionsFromCalls } from "./fixReactPropFunctionsFromCalls/index.js";
+import { fixReactPropsFromLaterAssignments } from "./fixReactPropsFromLaterAssignments/index.js";
+import { fixReactPropsFromPropTypes } from "./fixReactPropsFromPropTypes/index.js";
+import { fixReactPropsFromUses } from "./fixReactPropsFromUses/index.js";
+import { fixReactPropsMissing } from "./fixReactPropsMissing.js";
export const fixIncompleteReactTypes = (request: FileMutationsRequest) =>
- findFirstMutations(request, [
- // Intentionally look at internal uses before later assignments,
- // as they're less likely to contain misleading type information
- ["fixReactPropsFromUses", fixReactPropsFromUses],
- ["fixReactPropsFromLaterAssignments", fixReactPropsFromLaterAssignments],
+ findFirstMutations(request, [
+ // Intentionally look at internal uses before later assignments,
+ // as they're less likely to contain misleading type information
+ ["fixReactPropsFromUses", fixReactPropsFromUses],
+ ["fixReactPropsFromLaterAssignments", fixReactPropsFromLaterAssignments],
- ["fixReactPropFunctionsFromCalls", fixReactPropFunctionsFromCalls],
+ ["fixReactPropFunctionsFromCalls", fixReactPropFunctionsFromCalls],
- // Use propTypes with lower priority than uses, assignments, and calls
- // In practical code they are often wrong
- ["fixReactPropsFromPropTypes", fixReactPropsFromPropTypes],
+ // Use propTypes with lower priority than uses, assignments, and calls
+ // In practical code they are often wrong
+ ["fixReactPropsFromPropTypes", fixReactPropsFromPropTypes],
- // Lastly, if the component is missing a props type altogether, create one from scratch
- ["fixReactPropsMissing", fixReactPropsMissing],
- ]);
+ // Lastly, if the component is missing a props type altogether, create one from scratch
+ ["fixReactPropsMissing", fixReactPropsMissing],
+ ]);
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/getReactComponentNode.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/getReactComponentNode.ts
index dd9676f10..b6465147d 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/getReactComponentNode.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/getReactComponentNode.ts
@@ -1,15 +1,19 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { isReactComponentNode } from "./isReactComponentNode";
+import { isReactComponentNode } from "./isReactComponentNode.js";
export const getReactComponentNode = (node: ts.Node) => {
- if (isReactComponentNode(node)) {
- return node;
- }
+ if (isReactComponentNode(node)) {
+ return node;
+ }
- if (ts.isVariableDeclaration(node) && node.initializer !== undefined && isReactComponentNode(node.initializer)) {
- return node.initializer;
- }
+ if (
+ ts.isVariableDeclaration(node) &&
+ node.initializer !== undefined &&
+ isReactComponentNode(node.initializer)
+ ) {
+ return node.initializer;
+ }
- return undefined;
+ return undefined;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/isReactComponentNode.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/isReactComponentNode.ts
index 33628ca57..acfc25d35 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/isReactComponentNode.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/isReactComponentNode.ts
@@ -1,36 +1,55 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { getClassExtendsType } from "../../../../../shared/nodes";
+import { getClassExtendsType } from "../../../../../shared/nodes.js";
-export type ReactComponentNode = ReactClassComponentNode | ReactFunctionalComponentNode;
+export type ReactComponentNode =
+ | ReactClassComponentNode
+ | ReactFunctionalComponentNode;
-export type ReactClassComponentNode = (ts.ClassDeclaration | ts.ClassExpression) & {
- heritageClauses: ts.NodeArray;
+export type ReactClassComponentNode = (
+ | ts.ClassDeclaration
+ | ts.ClassExpression
+) & {
+ heritageClauses: ts.NodeArray;
};
-export type ReactFunctionalComponentNode = ts.ArrowFunction | ts.FunctionDeclaration | ts.FunctionExpression;
+export type ReactFunctionalComponentNode =
+ | ts.ArrowFunction
+ | ts.FunctionDeclaration
+ | ts.FunctionExpression;
/**
* @returns Whether the node is able to be a React component node.
*/
-export const isReactComponentNode = (node: ts.Node): node is ReactComponentNode => {
- // Functions can generally be React components if they have 0 or 1 parameters
- if (ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
- return node.parameters.length <= 1;
- }
-
- // Otherwise, we only look at class declarations and class expressions
- if (!ts.isClassLike(node)) {
- return false;
- }
-
- const extendsType = getClassExtendsType(node);
-
- return extendsType !== undefined && extensionExpressionIsReactComponent(extendsType);
+export const isReactComponentNode = (
+ node: ts.Node,
+): node is ReactComponentNode => {
+ // Functions can generally be React components if they have 0 or 1 parameters
+ if (
+ ts.isArrowFunction(node) ||
+ ts.isFunctionDeclaration(node) ||
+ ts.isFunctionExpression(node)
+ ) {
+ return node.parameters.length <= 1;
+ }
+
+ // Otherwise, we only look at class declarations and class expressions
+ if (!ts.isClassLike(node)) {
+ return false;
+ }
+
+ const extendsType = getClassExtendsType(node);
+
+ return (
+ extendsType !== undefined &&
+ extensionExpressionIsReactComponent(extendsType)
+ );
};
-const extensionExpressionIsReactComponent = (node: ts.ExpressionWithTypeArguments): boolean => {
- // Todo: actually check the type for this
- // See https://github.com/JoshuaKGoldberg/TypeStat/issues/135
- return node.getText().includes("Component");
+const extensionExpressionIsReactComponent = (
+ node: ts.ExpressionWithTypeArguments,
+): boolean => {
+ // Todo: actually check the type for this
+ // See https://github.com/JoshuaKGoldberg/TypeStat/issues/135
+ return node.getText().includes("Component");
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReturnTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReturnTypes/index.ts
index ecce49d95..ba468437b 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReturnTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReturnTypes/index.ts
@@ -1,35 +1,55 @@
import { Mutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { createTypeAdditionMutation } from "../../../../mutations/creators";
-import { isNotUndefined } from "../../../../shared/arrays";
-import { FunctionLikeDeclarationWithType, isNodeWithType } from "../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
-import { collectReturningNodeExpressions } from "../../fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/collectReturningNodeExpressions";
+import { createTypeAdditionMutation } from "../../../../mutations/creators.js";
+import { isNotUndefined } from "../../../../shared/arrays.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import {
+ FunctionLikeDeclarationWithType,
+ isNodeWithType,
+} from "../../../../shared/nodeTypes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+import { collectReturningNodeExpressions } from "../../fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/collectReturningNodeExpressions.js";
-export const fixIncompleteReturnTypes: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isNodeVisitableFunctionLikeDeclaration, visitFunctionWithBody);
+export const fixIncompleteReturnTypes: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isNodeVisitableFunctionLikeDeclaration,
+ visitFunctionWithBody,
+ );
-const isNodeVisitableFunctionLikeDeclaration = (node: ts.Node): node is FunctionLikeDeclarationWithType =>
- ts.isFunctionLike(node) &&
- // If the node has an implicit return type, we don't need to change anything
- isNodeWithType(node);
+const isNodeVisitableFunctionLikeDeclaration = (
+ node: ts.Node,
+): node is FunctionLikeDeclarationWithType =>
+ ts.isFunctionLike(node) &&
+ // If the node has an implicit return type, we don't need to change anything
+ isNodeWithType(node);
-const visitFunctionWithBody = (node: FunctionLikeDeclarationWithType, request: FileMutationsRequest) => {
- // Collect the type initially declared as returned
- const declaredType = getTypeAtLocationIfNotError(request, node.type);
- if (declaredType === undefined || tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)) {
- return undefined;
- }
+const visitFunctionWithBody = (
+ node: FunctionLikeDeclarationWithType,
+ request: FileMutationsRequest,
+) => {
+ // Collect the type initially declared as returned
+ const declaredType = getTypeAtLocationIfNotError(request, node.type);
+ if (
+ declaredType === undefined ||
+ tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)
+ ) {
+ return undefined;
+ }
- // Collect types of nodes returned by the function
- const returnedTypes = collectReturningNodeExpressions(node)
- .map((node) => getTypeAtLocationIfNotError(request, node))
- .filter(isNotUndefined);
+ // Collect types of nodes returned by the function
+ const returnedTypes = collectReturningNodeExpressions(node)
+ .map((node) => getTypeAtLocationIfNotError(request, node))
+ .filter(isNotUndefined);
- // Add later-returned types to the node's type declaration if necessary
- return createTypeAdditionMutation(request, node, declaredType, returnedTypes);
+ // Add later-returned types to the node's type declaration if necessary
+ return createTypeAdditionMutation(request, node, declaredType, returnedTypes);
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteVariableTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteVariableTypes/index.ts
index d881c3c3a..ed76f224b 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteVariableTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/fixIncompleteVariableTypes/index.ts
@@ -1,94 +1,132 @@
import { Mutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
-
-import { createTypeAdditionMutation, createTypeCreationMutation } from "../../../../mutations/creators";
-import { isNodeWithType, NodeWithType } from "../../../../shared/nodeTypes";
-import { isNodeFilteredOut } from "../../../../shared/references";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
-
-export const fixIncompleteVariableTypes: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isNodeVariableDeclarationWithType, visitVariableDeclaration);
-
-const isNodeVariableDeclarationWithType = (node: ts.Node): node is ts.VariableDeclaration & NodeWithType =>
- ts.isVariableDeclaration(node) && isNodeWithType(node);
-
-const visitVariableDeclaration = (node: ts.VariableDeclaration, request: FileMutationsRequest): Mutation | undefined => {
- // Collect types later assigned to the variable, and types initially declared by or inferred on the variable
- const assignedTypes = collectVariableAssignedTypes(node, request);
- if (assignedTypes.some((type) => tsutils.isTypeFlagSet(type, ts.TypeFlags.Any))) {
- return undefined;
- }
-
- const declaredType = getTypeAtLocationIfNotError(request, node);
- if (declaredType === undefined || tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)) {
- return undefined;
- }
-
- // If the variable already has a declared type, add assigned types to it if necessary
- if (isNodeWithType(node)) {
- return createTypeAdditionMutation(request, node, declaredType, assignedTypes);
- }
-
- // Since the node's missing type isn't inferrable, try our best to give it one
- return createTypeCreationMutation(request, node, declaredType, assignedTypes);
+import ts from "typescript";
+
+import {
+ createTypeAdditionMutation,
+ createTypeCreationMutation,
+} from "../../../../mutations/creators.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { NodeWithType, isNodeWithType } from "../../../../shared/nodeTypes.js";
+import { isNodeFilteredOut } from "../../../../shared/references.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+
+export const fixIncompleteVariableTypes: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isNodeVariableDeclarationWithType,
+ visitVariableDeclaration,
+ );
+
+const isNodeVariableDeclarationWithType = (
+ node: ts.Node,
+): node is ts.VariableDeclaration & NodeWithType =>
+ ts.isVariableDeclaration(node) && isNodeWithType(node);
+
+const visitVariableDeclaration = (
+ node: ts.VariableDeclaration,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Collect types later assigned to the variable, and types initially declared by or inferred on the variable
+ const assignedTypes = collectVariableAssignedTypes(node, request);
+ if (
+ assignedTypes.some((type) => tsutils.isTypeFlagSet(type, ts.TypeFlags.Any))
+ ) {
+ return undefined;
+ }
+
+ const declaredType = getTypeAtLocationIfNotError(request, node);
+ if (
+ declaredType === undefined ||
+ tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)
+ ) {
+ return undefined;
+ }
+
+ // If the variable already has a declared type, add assigned types to it if necessary
+ if (isNodeWithType(node)) {
+ return createTypeAdditionMutation(
+ request,
+ node,
+ declaredType,
+ assignedTypes,
+ );
+ }
+
+ // Since the node's missing type isn't inferrable, try our best to give it one
+ return createTypeCreationMutation(request, node, declaredType, assignedTypes);
};
/**
* Finds types later assigned to a variable declaration.
- *
* @param node Node to collect types from.
* @param request Metadata and settings to collect mutations in a file.
* @returns Types assigned to the node in the file.
*/
-const collectVariableAssignedTypes = (node: ts.VariableDeclaration, request: FileMutationsRequest): ReadonlyArray => {
- const assignedTypes: ts.Type[] = [];
-
- // If the variable has an initial value, consider that an assignment
- if (node.initializer !== undefined) {
- const initializerType = getTypeAtLocationIfNotError(request, node.initializer);
- if (initializerType !== undefined) {
- assignedTypes.push(initializerType);
- }
- }
-
- // If the variable is anonymous or marked as readonly, don't bother checking for more types
- if (!ts.isIdentifier(node.name) || tsutils.isModifierFlagSet(node, ts.ModifierFlags.Readonly)) {
- return assignedTypes;
- }
-
- // Collect all places in the file where the variable is later referenced
- const variableInfo = request.fileInfoCache.getVariableUsage().get(node.name);
- if (variableInfo === undefined) {
- return assignedTypes;
- }
-
- for (const use of variableInfo.uses) {
- const useIdentifier = use.location;
- const useExpression = useIdentifier.parent;
-
- // Ignore the node usage if it's inside an ignored node
- if (isNodeFilteredOut(request.filteredNodes, use.location)) {
- continue;
- }
-
- // We only care about binary expressions that assign a type to the variable
- if (
- !ts.isBinaryExpression(useExpression) ||
- useExpression.operatorToken.getText(request.sourceFile) !== "=" ||
- useExpression.left !== useIdentifier
- ) {
- continue;
- }
-
- // Grab the new type being assigned to the node
- const assignmentType = getTypeAtLocationIfNotError(request, useExpression.right);
- if (assignmentType !== undefined) {
- assignedTypes.push(assignmentType);
- }
- }
-
- return assignedTypes;
+const collectVariableAssignedTypes = (
+ node: ts.VariableDeclaration,
+ request: FileMutationsRequest,
+): readonly ts.Type[] => {
+ const assignedTypes: ts.Type[] = [];
+
+ // If the variable has an initial value, consider that an assignment
+ if (node.initializer !== undefined) {
+ const initializerType = getTypeAtLocationIfNotError(
+ request,
+ node.initializer,
+ );
+ if (initializerType !== undefined) {
+ assignedTypes.push(initializerType);
+ }
+ }
+
+ // If the variable is anonymous or marked as readonly, don't bother checking for more types
+ if (
+ !ts.isIdentifier(node.name) ||
+ tsutils.isModifierFlagSet(node, ts.ModifierFlags.Readonly)
+ ) {
+ return assignedTypes;
+ }
+
+ // Collect all places in the file where the variable is later referenced
+ const variableInfo = request.fileInfoCache.getVariableUsage().get(node.name);
+ if (variableInfo === undefined) {
+ return assignedTypes;
+ }
+
+ for (const use of variableInfo.uses) {
+ const useIdentifier = use.location;
+ const useExpression = useIdentifier.parent;
+
+ // Ignore the node usage if it's inside an ignored node
+ if (isNodeFilteredOut(request.filteredNodes, use.location)) {
+ continue;
+ }
+
+ // We only care about binary expressions that assign a type to the variable
+ if (
+ !ts.isBinaryExpression(useExpression) ||
+ useExpression.operatorToken.getText(request.sourceFile) !== "=" ||
+ useExpression.left !== useIdentifier
+ ) {
+ continue;
+ }
+
+ // Grab the new type being assigned to the node
+ const assignmentType = getTypeAtLocationIfNotError(
+ request,
+ useExpression.right,
+ );
+ if (assignmentType !== undefined) {
+ assignedTypes.push(assignmentType);
+ }
+ }
+
+ return assignedTypes;
};
diff --git a/src/mutators/builtIn/fixIncompleteTypes/index.ts b/src/mutators/builtIn/fixIncompleteTypes/index.ts
index ec25a2874..fc982e2a3 100644
--- a/src/mutators/builtIn/fixIncompleteTypes/index.ts
+++ b/src/mutators/builtIn/fixIncompleteTypes/index.ts
@@ -1,23 +1,28 @@
-import { findFirstMutations } from "../../../shared/runtime";
-import { FileMutationsRequest } from "../../../shared/fileMutator";
-
-import { fixIncompleteImplicitGenerics } from "./fixIncompleteImplicitGenerics";
-import { fixIncompleteInterfaceOrTypeLiteralGenerics } from "./fixIncompleteInterfaceOrTypeLiteralGenerics";
-import { fixIncompleteParameterTypes } from "./fixIncompleteParameterTypes";
-import { fixIncompletePropertyDeclarationTypes } from "./fixIncompletePropertyDeclarationTypes";
-import { fixIncompleteReactTypes } from "./fixIncompleteReactTypes";
-import { fixIncompleteReturnTypes } from "./fixIncompleteReturnTypes";
-import { fixIncompleteVariableTypes } from "./fixIncompleteVariableTypes";
+import { FileMutationsRequest } from "../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../shared/runtime.js";
+import { fixIncompleteImplicitGenerics } from "./fixIncompleteImplicitGenerics/index.js";
+import { fixIncompleteInterfaceOrTypeLiteralGenerics } from "./fixIncompleteInterfaceOrTypeLiteralGenerics/index.js";
+import { fixIncompleteParameterTypes } from "./fixIncompleteParameterTypes/index.js";
+import { fixIncompletePropertyDeclarationTypes } from "./fixIncompletePropertyDeclarationTypes/index.js";
+import { fixIncompleteReactTypes } from "./fixIncompleteReactTypes/index.js";
+import { fixIncompleteReturnTypes } from "./fixIncompleteReturnTypes/index.js";
+import { fixIncompleteVariableTypes } from "./fixIncompleteVariableTypes/index.js";
export const fixIncompleteTypes = (request: FileMutationsRequest) =>
- request.options.fixes.incompleteTypes
- ? findFirstMutations(request, [
- ["fixIncompleteImplicitGenerics", fixIncompleteImplicitGenerics],
- ["fixIncompleteInterfaceOrTypeLiteralGenerics", fixIncompleteInterfaceOrTypeLiteralGenerics],
- ["fixIncompleteParameterTypes", fixIncompleteParameterTypes],
- ["fixIncompletePropertyDeclarationTypes", fixIncompletePropertyDeclarationTypes],
- ["fixIncompleteReactTypes", fixIncompleteReactTypes],
- ["fixIncompleteReturnTypes", fixIncompleteReturnTypes],
- ["fixIncompleteVariableTypes", fixIncompleteVariableTypes],
- ])
- : undefined;
+ request.options.fixes.incompleteTypes
+ ? findFirstMutations(request, [
+ ["fixIncompleteImplicitGenerics", fixIncompleteImplicitGenerics],
+ [
+ "fixIncompleteInterfaceOrTypeLiteralGenerics",
+ fixIncompleteInterfaceOrTypeLiteralGenerics,
+ ],
+ ["fixIncompleteParameterTypes", fixIncompleteParameterTypes],
+ [
+ "fixIncompletePropertyDeclarationTypes",
+ fixIncompletePropertyDeclarationTypes,
+ ],
+ ["fixIncompleteReactTypes", fixIncompleteReactTypes],
+ ["fixIncompleteReturnTypes", fixIncompleteReturnTypes],
+ ["fixIncompleteVariableTypes", fixIncompleteVariableTypes],
+ ])
+ : undefined;
diff --git a/src/mutators/builtIn/fixMissingProperties/README.md b/src/mutators/builtIn/fixMissingProperties/README.md
index 982dca9c4..ca8b90471 100644
--- a/src/mutators/builtIn/fixMissingProperties/README.md
+++ b/src/mutators/builtIn/fixMissingProperties/README.md
@@ -6,15 +6,15 @@ This entirely relies on TypeScript's suggested fixes to infer types from usage.
## Use Cases
-* You're converting from JavaScript to TypeScript and have classes that contain properties
+- You're converting from JavaScript to TypeScript and have classes that contain properties
## Configuration
```json
{
- "fixes": {
- "missingProperties": true
- }
+ "fixes": {
+ "missingProperties": true
+ }
}
```
diff --git a/src/mutators/builtIn/fixMissingProperties/fixMissingPropertyAccesses/index.ts b/src/mutators/builtIn/fixMissingProperties/fixMissingPropertyAccesses/index.ts
index c784b8953..2ca9fcc76 100644
--- a/src/mutators/builtIn/fixMissingProperties/fixMissingPropertyAccesses/index.ts
+++ b/src/mutators/builtIn/fixMissingProperties/fixMissingPropertyAccesses/index.ts
@@ -1,40 +1,54 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { getMissingPropertyMutations } from "../../../../mutations/codeFixes/addMissingProperty";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { getMissingPropertyMutations } from "../../../../mutations/codeFixes/addMissingProperty.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixMissingPropertyAccesses: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- // If an undeclared property is referenced multiple times, TypeScript will suggest adding it in each time
- // We therefore only suggest each property name once per wave
- // In theory, we could also respect each node name per class, but that's hard, and it's rare to have many classes per file
- const suggestedMissingProperties = new Set();
+export const fixMissingPropertyAccesses: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ // If an undeclared property is referenced multiple times, TypeScript will suggest adding it in each time
+ // We therefore only suggest each property name once per wave
+ // In theory, we could also respect each node name per class, but that's hard, and it's rare to have many classes per file
+ const suggestedMissingProperties = new Set();
- const visitPropertyAccessExpression = (node: ts.PropertyAccessExpression): Mutation | undefined => {
- // If the access should create a missing property, go for that
- const missingPropertyFix = getMissingPropertyMutations(request, node);
- if (missingPropertyFix === undefined) {
- return undefined;
- }
+ const visitPropertyAccessExpression = (
+ node: ts.PropertyAccessExpression,
+ ): Mutation | undefined => {
+ // If the access should create a missing property, go for that
+ const missingPropertyFix = getMissingPropertyMutations(request, node);
+ if (missingPropertyFix === undefined) {
+ return undefined;
+ }
- // Don't suggest this missing property if a node of this name was already added
- if (suggestedMissingProperties.has(node.name.text)) {
- return undefined;
- }
+ // Don't suggest this missing property if a node of this name was already added
+ if (suggestedMissingProperties.has(node.name.text)) {
+ return undefined;
+ }
- // Additionally, for some reason, the language service seems suggest the same fixes repeatedly sometimes...
- // To get around this, we ignore any fixes for nodes that already exist on the parent class
- // https://github.com/JoshuaKGoldberg/TypeStat/issues/756
- const assigneeClassType = getTypeAtLocationIfNotError(request, node.expression);
- if (assigneeClassType?.getProperty(node.name.text) !== undefined) {
- return undefined;
- }
+ // Additionally, for some reason, the language service seems suggest the same fixes repeatedly sometimes...
+ // To get around this, we ignore any fixes for nodes that already exist on the parent class
+ // https://github.com/JoshuaKGoldberg/TypeStat/issues/756
+ const assigneeClassType = getTypeAtLocationIfNotError(
+ request,
+ node.expression,
+ );
+ if (assigneeClassType?.getProperty(node.name.text) !== undefined) {
+ return undefined;
+ }
- suggestedMissingProperties.add(node.name.text);
- return missingPropertyFix;
- };
+ suggestedMissingProperties.add(node.name.text);
+ return missingPropertyFix;
+ };
- return collectMutationsFromNodes(request, ts.isPropertyAccessExpression, visitPropertyAccessExpression);
+ return collectMutationsFromNodes(
+ request,
+ ts.isPropertyAccessExpression,
+ visitPropertyAccessExpression,
+ );
};
diff --git a/src/mutators/builtIn/fixMissingProperties/index.ts b/src/mutators/builtIn/fixMissingProperties/index.ts
index 4da680f1c..6a86303a9 100644
--- a/src/mutators/builtIn/fixMissingProperties/index.ts
+++ b/src/mutators/builtIn/fixMissingProperties/index.ts
@@ -1,9 +1,10 @@
-import { findFirstMutations } from "../../../shared/runtime";
-import { FileMutationsRequest } from "../../../shared/fileMutator";
-
-import { fixMissingPropertyAccesses } from "./fixMissingPropertyAccesses";
+import { FileMutationsRequest } from "../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../shared/runtime.js";
+import { fixMissingPropertyAccesses } from "./fixMissingPropertyAccesses/index.js";
export const fixMissingProperties = (request: FileMutationsRequest) =>
- request.options.fixes.missingProperties
- ? findFirstMutations(request, [["fixMissingPropertyAccesses", fixMissingPropertyAccesses]])
- : undefined;
+ request.options.fixes.missingProperties
+ ? findFirstMutations(request, [
+ ["fixMissingPropertyAccesses", fixMissingPropertyAccesses],
+ ])
+ : undefined;
diff --git a/src/mutators/builtIn/fixNoImplicitAny/README.md b/src/mutators/builtIn/fixNoImplicitAny/README.md
index 5137855e4..1847c3db2 100644
--- a/src/mutators/builtIn/fixNoImplicitAny/README.md
+++ b/src/mutators/builtIn/fixNoImplicitAny/README.md
@@ -6,8 +6,8 @@ This entirely relies on TypeScript's suggested fixes to infer types from usage.
## Use Cases
-* You're converting from JavaScript to TypeScript and want type coverage where possible
-* You'd like to enable [`--noImplicitAny`](https://basarat.gitbooks.io/typescript/docs/options/noImplicitAny.html) but have a lot of existing violations
+- You're converting from JavaScript to TypeScript and want type coverage where possible
+- You'd like to enable [`--noImplicitAny`](https://basarat.gitbooks.io/typescript/docs/options/noImplicitAny.html) but have a lot of existing violations
Places that don't need added types (i.e. would violate [`no-inferrable-types`](https://typescript-eslint.io/rules/no-inferrable-types))
won't have them added.
@@ -16,9 +16,9 @@ won't have them added.
```json
{
- "fixes": {
- "noImplicitAny": true
- }
+ "fixes": {
+ "noImplicitAny": true
+ }
}
```
@@ -47,7 +47,7 @@ If a class property is declared without a type, this will add one.
#### Examples: `noImplicitAny` Property Declarations
-When a class property is declared without a type but is later assigned `number`, TypeScript can infer the type from its usage:
+When a class property is declared without a type but is later assigned `number`, TypeScript can infer the type from its usage:
```diff
class Person {
diff --git a/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyParameters/index.ts b/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyParameters/index.ts
index 691b7a608..c4d125850 100644
--- a/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyParameters/index.ts
+++ b/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyParameters/index.ts
@@ -1,16 +1,27 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
import {
- canNodeBeFixedForNoImplicitAny,
- getNoImplicitAnyMutations,
- NoImplictAnyNodeToBeFixed,
-} from "../../../../mutations/codeFixes/noImplicitAny";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+ NoImplicitAnyNodeToBeFixed,
+ canNodeBeFixedForNoImplicitAny,
+ getNoImplicitAnyMutations,
+} from "../../../../mutations/codeFixes/noImplicitAny.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixNoImplicitAnyParameters: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isNodeNoImplicitAnyFixableParameter, getNoImplicitAnyMutations);
+export const fixNoImplicitAnyParameters: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isNodeNoImplicitAnyFixableParameter,
+ getNoImplicitAnyMutations,
+ );
-const isNodeNoImplicitAnyFixableParameter = (node: ts.Node): node is ts.ParameterDeclaration & NoImplictAnyNodeToBeFixed =>
- ts.isParameter(node) && canNodeBeFixedForNoImplicitAny(node);
+const isNodeNoImplicitAnyFixableParameter = (
+ node: ts.Node,
+): node is ts.ParameterDeclaration & NoImplicitAnyNodeToBeFixed =>
+ ts.isParameter(node) && canNodeBeFixedForNoImplicitAny(node);
diff --git a/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyPropertyDeclarations/index.ts b/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyPropertyDeclarations/index.ts
index 14969bd76..08db82963 100644
--- a/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyPropertyDeclarations/index.ts
+++ b/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyPropertyDeclarations/index.ts
@@ -1,16 +1,27 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
import {
- canNodeBeFixedForNoImplicitAny,
- getNoImplicitAnyMutations,
- NoImplictAnyNodeToBeFixed,
-} from "../../../../mutations/codeFixes/noImplicitAny";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+ NoImplicitAnyNodeToBeFixed,
+ canNodeBeFixedForNoImplicitAny,
+ getNoImplicitAnyMutations,
+} from "../../../../mutations/codeFixes/noImplicitAny.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixNoImplicitAnyPropertyDeclarations: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isNodeNoImplicitAnyFixablePropertyDeclaration, getNoImplicitAnyMutations);
+export const fixNoImplicitAnyPropertyDeclarations: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isNodeNoImplicitAnyFixablePropertyDeclaration,
+ getNoImplicitAnyMutations,
+ );
-const isNodeNoImplicitAnyFixablePropertyDeclaration = (node: ts.Node): node is ts.PropertyDeclaration & NoImplictAnyNodeToBeFixed =>
- ts.isPropertyDeclaration(node) && canNodeBeFixedForNoImplicitAny(node);
+const isNodeNoImplicitAnyFixablePropertyDeclaration = (
+ node: ts.Node,
+): node is ts.PropertyDeclaration & NoImplicitAnyNodeToBeFixed =>
+ ts.isPropertyDeclaration(node) && canNodeBeFixedForNoImplicitAny(node);
diff --git a/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyVariableDeclarations/index.ts b/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyVariableDeclarations/index.ts
index 700a08f43..e00f0a5a4 100644
--- a/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyVariableDeclarations/index.ts
+++ b/src/mutators/builtIn/fixNoImplicitAny/fixNoImplicitAnyVariableDeclarations/index.ts
@@ -1,33 +1,52 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { canNodeBeFixedForNoImplicitAny, getNoImplicitAnyMutations } from "../../../../mutations/codeFixes/noImplicitAny";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import {
+ canNodeBeFixedForNoImplicitAny,
+ getNoImplicitAnyMutations,
+} from "../../../../mutations/codeFixes/noImplicitAny.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixNoImplicitAnyVariableDeclarations: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- // This mutator fixes only for --noImplicitAny
- if (!request.options.fixes.noImplicitAny) {
- return [];
- }
+export const fixNoImplicitAnyVariableDeclarations: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ // This mutator fixes only for --noImplicitAny
+ if (!request.options.fixes.noImplicitAny) {
+ return [];
+ }
- return collectMutationsFromNodes(request, isNodeVisitableVariableDeclaration, visitVariableDeclaration);
+ return collectMutationsFromNodes(
+ request,
+ isNodeVisitableVariableDeclaration,
+ visitVariableDeclaration,
+ );
};
-const isNodeVisitableVariableDeclaration = (node: ts.Node): node is ts.VariableDeclaration =>
- ts.isVariableDeclaration(node) &&
- !node.type &&
- // Binding patterns are all implicitly typed, so ignore them
- !(ts.isArrayBindingPattern(node.name) || ts.isObjectBindingPattern(node.name)) &&
- // For-in and for-of loop varibles cannot have types, so don't bother trying to add them
- !ts.isForInStatement(node.parent.parent) &&
- !ts.isForOfStatement(node.parent.parent);
+const isNodeVisitableVariableDeclaration = (
+ node: ts.Node,
+): node is ts.VariableDeclaration =>
+ ts.isVariableDeclaration(node) &&
+ !node.type &&
+ // Binding patterns are all implicitly typed, so ignore them
+ !(
+ ts.isArrayBindingPattern(node.name) || ts.isObjectBindingPattern(node.name)
+ ) &&
+ // For-in and for-of loop variables cannot have types, so don't bother trying to add them
+ !ts.isForInStatement(node.parent.parent) &&
+ !ts.isForOfStatement(node.parent.parent);
-const visitVariableDeclaration = (node: ts.VariableDeclaration, request: FileMutationsRequest): Mutation | undefined => {
- // If the variable violates --noImplicitAny (has no type or initializer), this can only be a --noImplicitAny fix
- if (canNodeBeFixedForNoImplicitAny(node)) {
- return getNoImplicitAnyMutations(node, request);
- }
+const visitVariableDeclaration = (
+ node: ts.VariableDeclaration,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // If the variable violates --noImplicitAny (has no type or initializer), this can only be a --noImplicitAny fix
+ if (canNodeBeFixedForNoImplicitAny(node)) {
+ return getNoImplicitAnyMutations(node, request);
+ }
- return undefined;
+ return undefined;
};
diff --git a/src/mutators/builtIn/fixNoImplicitAny/index.ts b/src/mutators/builtIn/fixNoImplicitAny/index.ts
index 42a58b309..f8d633a85 100644
--- a/src/mutators/builtIn/fixNoImplicitAny/index.ts
+++ b/src/mutators/builtIn/fixNoImplicitAny/index.ts
@@ -1,15 +1,20 @@
-import { findFirstMutations } from "../../../shared/runtime";
-import { FileMutationsRequest } from "../../../shared/fileMutator";
-
-import { fixNoImplicitAnyParameters } from "./fixNoImplicitAnyParameters";
-import { fixNoImplicitAnyPropertyDeclarations } from "./fixNoImplicitAnyPropertyDeclarations";
-import { fixNoImplicitAnyVariableDeclarations } from "./fixNoImplicitAnyVariableDeclarations";
+import { FileMutationsRequest } from "../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../shared/runtime.js";
+import { fixNoImplicitAnyParameters } from "./fixNoImplicitAnyParameters/index.js";
+import { fixNoImplicitAnyPropertyDeclarations } from "./fixNoImplicitAnyPropertyDeclarations/index.js";
+import { fixNoImplicitAnyVariableDeclarations } from "./fixNoImplicitAnyVariableDeclarations/index.js";
export const fixNoImplicitAny = (request: FileMutationsRequest) =>
- request.options.fixes.noImplicitAny
- ? findFirstMutations(request, [
- ["fixNoImplicitAnyPropertyDeclarations", fixNoImplicitAnyPropertyDeclarations],
- ["fixNoImplicitAnyParameters", fixNoImplicitAnyParameters],
- ["fixNoImplicitAnyVariableDeclarations", fixNoImplicitAnyVariableDeclarations],
- ])
- : undefined;
+ request.options.fixes.noImplicitAny
+ ? findFirstMutations(request, [
+ [
+ "fixNoImplicitAnyPropertyDeclarations",
+ fixNoImplicitAnyPropertyDeclarations,
+ ],
+ ["fixNoImplicitAnyParameters", fixNoImplicitAnyParameters],
+ [
+ "fixNoImplicitAnyVariableDeclarations",
+ fixNoImplicitAnyVariableDeclarations,
+ ],
+ ])
+ : undefined;
diff --git a/src/mutators/builtIn/fixNoImplicitThis/README.md b/src/mutators/builtIn/fixNoImplicitThis/README.md
index 629fdc0b8..c3d91bacd 100644
--- a/src/mutators/builtIn/fixNoImplicitThis/README.md
+++ b/src/mutators/builtIn/fixNoImplicitThis/README.md
@@ -6,8 +6,8 @@ This entirely relies on TypeScript's suggested fixes to infer types from usage.
## Use Cases
-* You're converting from JavaScript to TypeScript and want type coverage where possible
-* You'd like to enable [`--noImplicitThis`](https://basarat.gitbooks.io/typescript/docs/options/noImplicitThis.html) but have a lot of existing violations
+- You're converting from JavaScript to TypeScript and want type coverage where possible
+- You'd like to enable [`--noImplicitThis`](https://basarat.gitbooks.io/typescript/docs/options/noImplicitThis.html) but have a lot of existing violations
Functions that already have a known scope or don't refer to `this` won't have them added.
@@ -15,9 +15,9 @@ Functions that already have a known scope or don't refer to `this` won't have th
```json
{
- "fixes": {
- "noImplicitThis": true
- }
+ "fixes": {
+ "noImplicitThis": true
+ }
}
```
diff --git a/src/mutators/builtIn/fixNoImplicitThis/index.ts b/src/mutators/builtIn/fixNoImplicitThis/index.ts
index 49de6066e..5ee4e25fc 100644
--- a/src/mutators/builtIn/fixNoImplicitThis/index.ts
+++ b/src/mutators/builtIn/fixNoImplicitThis/index.ts
@@ -1,10 +1,22 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { getNoImplicitThisMutations } from "../../../mutations/codeFixes/noImplicitThis";
-import { collectMutationsFromNodes } from "../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../shared/fileMutator";
+import { getNoImplicitThisMutations } from "../../../mutations/codeFixes/noImplicitThis.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../shared/fileMutator.js";
+import { collectMutationsFromNodes } from "../../collectMutationsFromNodes.js";
-export const fixNoImplicitThis: FileMutator = (request: FileMutationsRequest) =>
- request.options.fixes.noImplicitThis ? collectMutationsFromNodes(request, isThisExpression, getNoImplicitThisMutations) : undefined;
+export const fixNoImplicitThis: FileMutator = (
+ request: FileMutationsRequest,
+) =>
+ request.options.fixes.noImplicitThis
+ ? collectMutationsFromNodes(
+ request,
+ isThisExpression,
+ getNoImplicitThisMutations,
+ )
+ : undefined;
-const isThisExpression = (node: ts.Node): node is ts.ThisExpression => node.kind === ts.SyntaxKind.ThisKeyword;
+const isThisExpression = (node: ts.Node): node is ts.ThisExpression =>
+ node.kind === ts.SyntaxKind.ThisKeyword;
diff --git a/src/mutators/builtIn/fixNoInferableTypes/README.md b/src/mutators/builtIn/fixNoInferableTypes/README.md
index 53b109eeb..cc7035c1f 100644
--- a/src/mutators/builtIn/fixNoInferableTypes/README.md
+++ b/src/mutators/builtIn/fixNoInferableTypes/README.md
@@ -2,18 +2,18 @@
Whether to remove type annotations that don't change the meaning of code.
-# Use Cases
+## Use Cases
-* Your code was recently converted from JavaScript to TypeScript and previously useful type declarations are now visual clutter
-* You used to always add type declarations, but have since realized doing so unnecessary is a futile and wasteful act
+- Your code was recently converted from JavaScript to TypeScript and previously useful type declarations are now visual clutter
+- You used to always add type declarations, but have since realized doing so unnecessary is a futile and wasteful act
## Configuration
```json
{
- "fixes": {
- "noInferableTypes": true
- }
+ "fixes": {
+ "noInferableTypes": true
+ }
}
```
@@ -30,7 +30,7 @@ When a parameter is declared with a `: number` type declaration and a numeric in
```diff
- function receivesNumber(value: number = 0) {
+ function receivesNumber(value = 0) {
- return value * 2;
+ return value * 2;
}
```
diff --git a/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesParameters/index.ts b/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesParameters/index.ts
index 8f458a4dd..afac10215 100644
--- a/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesParameters/index.ts
+++ b/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesParameters/index.ts
@@ -1,44 +1,67 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { createTypeRemovalMutation } from "../../../../mutations/removals";
-import { declaredInitializedTypeNodeIsRedundant } from "../../../../shared/comparisons";
-import { ParameterDeclarationWithType, isNodeWithType } from "../../../../shared/nodeTypes";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { createTypeRemovalMutation } from "../../../../mutations/removals.js";
+import { declaredInitializedTypeNodeIsRedundant } from "../../../../shared/comparisons.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import {
+ ParameterDeclarationWithType,
+ isNodeWithType,
+} from "../../../../shared/nodeTypes.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixNoInferableTypesParameters: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isInferableTypeCapableParameter, getNoInferableTypeParameterMutation);
+export const fixNoInferableTypesParameters: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isInferableTypeCapableParameter,
+ getNoInferableTypeParameterMutation,
+ );
-const isInferableTypeCapableParameter = (node: ts.Node): node is ParameterDeclarationWithType =>
- ts.isParameter(node) && isNodeWithType(node) && node.modifiers === undefined;
+const isInferableTypeCapableParameter = (
+ node: ts.Node,
+): node is ParameterDeclarationWithType =>
+ ts.isParameter(node) && isNodeWithType(node) && node.modifiers === undefined;
-const getNoInferableTypeParameterMutation = (node: ParameterDeclarationWithType, request: FileMutationsRequest) => {
- if (!parameterTypeIsInferable(request, node)) {
- return undefined;
- }
+const getNoInferableTypeParameterMutation = (
+ node: ParameterDeclarationWithType,
+ request: FileMutationsRequest,
+) => {
+ if (!parameterTypeIsInferable(request, node)) {
+ return undefined;
+ }
- return createTypeRemovalMutation(request, node);
+ return createTypeRemovalMutation(request, node);
};
const parameterTypeIsInferable = (
- request: FileMutationsRequest,
- node: ParameterDeclarationWithType,
+ request: FileMutationsRequest,
+ node: ParameterDeclarationWithType,
): node is ParameterDeclarationWithType => {
- // If the parameter has an initializer (default value), that might invalidate its type
- if (node.initializer) {
- if (declaredInitializedTypeNodeIsRedundant(request, node.type, node.initializer)) {
- return true;
- }
- }
-
- // Eventually, it'd be nice to check for parameters whose values are inferable from
- // their parent function's declarations, e.g.
- // ```ts
- // type TakesString = (input: string) => void;
- // const takesString: TakesString = (input: string) => {};
- // ```
- // See https://github.com/microsoft/TypeScript/issues/35691
-
- return false;
+ // If the parameter has an initializer (default value), that might invalidate its type
+ if (node.initializer) {
+ if (
+ declaredInitializedTypeNodeIsRedundant(
+ request,
+ node.type,
+ node.initializer,
+ )
+ ) {
+ return true;
+ }
+ }
+
+ // Eventually, it'd be nice to check for parameters whose values are inferable from
+ // their parent function's declarations, e.g.
+ // ```ts
+ // type TakesString = (input: string) => void;
+ // const takesString: TakesString = (input: string) => {};
+ // ```
+ // See https://github.com/microsoft/TypeScript/issues/35691
+
+ return false;
};
diff --git a/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesPropertyDeclarations/index.ts b/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesPropertyDeclarations/index.ts
index bd7b6aa37..7daf53683 100644
--- a/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesPropertyDeclarations/index.ts
+++ b/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesPropertyDeclarations/index.ts
@@ -1,24 +1,48 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { createTypeRemovalMutation } from "../../../../mutations/removals";
-import { declaredInitializedTypeNodeIsRedundant } from "../../../../shared/comparisons";
-import { isNodeWithType, NodeWithType } from "../../../../shared/nodeTypes";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { createTypeRemovalMutation } from "../../../../mutations/removals.js";
+import { declaredInitializedTypeNodeIsRedundant } from "../../../../shared/comparisons.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { NodeWithType, isNodeWithType } from "../../../../shared/nodeTypes.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-type InferablePropertyDeclaration = ts.PropertyDeclaration & NodeWithType & Required>;
+type InferablePropertyDeclaration = ts.PropertyDeclaration &
+ NodeWithType &
+ Required>;
-export const fixNoInferableTypesPropertyDeclarations: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isInferableTypeCapablePropertyDeclaration, getNoInferableTypePropertyDeclarationMutation);
+export const fixNoInferableTypesPropertyDeclarations: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isInferableTypeCapablePropertyDeclaration,
+ getNoInferableTypePropertyDeclarationMutation,
+ );
-const isInferableTypeCapablePropertyDeclaration = (node: ts.Node): node is InferablePropertyDeclaration =>
- ts.isPropertyDeclaration(node) && isNodeWithType(node) && node.initializer !== undefined;
+const isInferableTypeCapablePropertyDeclaration = (
+ node: ts.Node,
+): node is InferablePropertyDeclaration =>
+ ts.isPropertyDeclaration(node) &&
+ isNodeWithType(node) &&
+ node.initializer !== undefined;
-const getNoInferableTypePropertyDeclarationMutation = (node: InferablePropertyDeclaration, request: FileMutationsRequest) => {
- if (!declaredInitializedTypeNodeIsRedundant(request, node.type, node.initializer)) {
- return undefined;
- }
+const getNoInferableTypePropertyDeclarationMutation = (
+ node: InferablePropertyDeclaration,
+ request: FileMutationsRequest,
+) => {
+ if (
+ !declaredInitializedTypeNodeIsRedundant(
+ request,
+ node.type,
+ node.initializer,
+ )
+ ) {
+ return undefined;
+ }
- return createTypeRemovalMutation(request, node);
+ return createTypeRemovalMutation(request, node);
};
diff --git a/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesVariableDeclarations/index.ts b/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesVariableDeclarations/index.ts
index 1ae0de38b..7f15fb288 100644
--- a/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesVariableDeclarations/index.ts
+++ b/src/mutators/builtIn/fixNoInferableTypes/fixNoInferableTypesVariableDeclarations/index.ts
@@ -1,34 +1,51 @@
import { Mutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { createTypeRemovalMutation } from "../../../../mutations/removals";
-import { declaredInitializedTypeNodeIsRedundant } from "../../../../shared/comparisons";
-import { isNodeWithType, NodeWithType } from "../../../../shared/nodeTypes";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { createTypeRemovalMutation } from "../../../../mutations/removals.js";
+import { declaredInitializedTypeNodeIsRedundant } from "../../../../shared/comparisons.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { NodeWithType, isNodeWithType } from "../../../../shared/nodeTypes.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
type InferableVariableDeclaration = ts.VariableDeclaration &
- NodeWithType &
- Required> & {
- parent: ts.VariableDeclarationList;
- };
+ NodeWithType &
+ Required> & {
+ parent: ts.VariableDeclarationList;
+ };
-export const fixNoInferableTypesVariableDeclarations: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isInferableTypeCapableVariableDeclaration, getNoInferableTypeVariableDeclarationMutation);
+export const fixNoInferableTypesVariableDeclarations: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isInferableTypeCapableVariableDeclaration,
+ getNoInferableTypeVariableDeclarationMutation,
+ );
-const isInferableTypeCapableVariableDeclaration = (node: ts.Node): node is InferableVariableDeclaration =>
- ts.isVariableDeclaration(node) && isNodeWithType(node) && node.initializer !== undefined && ts.isVariableDeclarationList(node.parent);
+const isInferableTypeCapableVariableDeclaration = (
+ node: ts.Node,
+): node is InferableVariableDeclaration =>
+ ts.isVariableDeclaration(node) &&
+ isNodeWithType(node) &&
+ node.initializer !== undefined &&
+ ts.isVariableDeclarationList(node.parent);
-const getNoInferableTypeVariableDeclarationMutation = (node: InferableVariableDeclaration, request: FileMutationsRequest) => {
- if (
- // `const` variables should always have their declarations removed
- tsutils.isNodeFlagSet(node.parent, ts.NodeFlags.Const) ||
- // `let` variables should have only uninformative declarations removed
- declaredInitializedTypeNodeIsRedundant(request, node.type, node.initializer)
- ) {
- return createTypeRemovalMutation(request, node);
- }
+const getNoInferableTypeVariableDeclarationMutation = (
+ node: InferableVariableDeclaration,
+ request: FileMutationsRequest,
+) => {
+ if (
+ // `const` variables should always have their declarations removed
+ tsutils.isNodeFlagSet(node.parent, ts.NodeFlags.Const) ||
+ // `let` variables should have only uninformative declarations removed
+ declaredInitializedTypeNodeIsRedundant(request, node.type, node.initializer)
+ ) {
+ return createTypeRemovalMutation(request, node);
+ }
- return undefined;
+ return undefined;
};
diff --git a/src/mutators/builtIn/fixNoInferableTypes/index.ts b/src/mutators/builtIn/fixNoInferableTypes/index.ts
index cb6e1b793..c6b9f7758 100644
--- a/src/mutators/builtIn/fixNoInferableTypes/index.ts
+++ b/src/mutators/builtIn/fixNoInferableTypes/index.ts
@@ -1,15 +1,20 @@
-import { findFirstMutations } from "../../../shared/runtime";
-import { FileMutationsRequest } from "../../../shared/fileMutator";
-
-import { fixNoInferableTypesParameters } from "./fixNoInferableTypesParameters";
-import { fixNoInferableTypesPropertyDeclarations } from "./fixNoInferableTypesPropertyDeclarations";
-import { fixNoInferableTypesVariableDeclarations } from "./fixNoInferableTypesVariableDeclarations";
+import { FileMutationsRequest } from "../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../shared/runtime.js";
+import { fixNoInferableTypesParameters } from "./fixNoInferableTypesParameters/index.js";
+import { fixNoInferableTypesPropertyDeclarations } from "./fixNoInferableTypesPropertyDeclarations/index.js";
+import { fixNoInferableTypesVariableDeclarations } from "./fixNoInferableTypesVariableDeclarations/index.js";
export const fixNoInferableTypes = (request: FileMutationsRequest) =>
- request.options.fixes.noInferableTypes
- ? findFirstMutations(request, [
- ["fixNoInferableTypesParameters", fixNoInferableTypesParameters],
- ["fixNoInferableTypesPropertyDeclarations", fixNoInferableTypesPropertyDeclarations],
- ["fixNoInferableTypesVariableDeclarations", fixNoInferableTypesVariableDeclarations],
- ])
- : undefined;
+ request.options.fixes.noInferableTypes
+ ? findFirstMutations(request, [
+ ["fixNoInferableTypesParameters", fixNoInferableTypesParameters],
+ [
+ "fixNoInferableTypesPropertyDeclarations",
+ fixNoInferableTypesPropertyDeclarations,
+ ],
+ [
+ "fixNoInferableTypesVariableDeclarations",
+ fixNoInferableTypesVariableDeclarations,
+ ],
+ ])
+ : undefined;
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/README.md b/src/mutators/builtIn/fixStrictNonNullAssertions/README.md
index ae51e3f34..60202cdc2 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/README.md
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/README.md
@@ -6,8 +6,8 @@ Whether to add missing non-null assertions.
You'd like to enable [`--strictNullChecks`](https://basarat.gitbooks.io/typescript/docs/options/strictNullChecks.html) but:
-* You'd like to enable the setting now and clean up existing violations later
-* Your tests pass nullable values in places that otherwise shouldn't accept them
+- You'd like to enable the setting now and clean up existing violations later
+- Your tests pass nullable values in places that otherwise shouldn't accept them
Note that `strictNullChecks` must be enabled in your `tsconfig.json` and/or TypeStat configuration file.
@@ -15,9 +15,9 @@ Note that `strictNullChecks` must be enabled in your `tsconfig.json` and/or Type
```json
{
- "fixes": {
- "strictNonNullAssertions": true
- }
+ "fixes": {
+ "strictNonNullAssertions": true
+ }
}
```
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionBinaryExpressions/index.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionBinaryExpressions/index.ts
index e758be5d1..07ee9206b 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionBinaryExpressions/index.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionBinaryExpressions/index.ts
@@ -1,37 +1,54 @@
import { Mutation } from "automutate";
import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import ts from "typescript";
-import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags";
-import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion";
-import { isNodeAssigningBinaryExpression } from "../../../../shared/nodes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags.js";
+import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { isNodeAssigningBinaryExpression } from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixStrictNonNullAssertionBinaryExpressions: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- return collectMutationsFromNodes(request, isNodeAssigningBinaryExpression, visitBinaryExpression);
+export const fixStrictNonNullAssertionBinaryExpressions: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ return collectMutationsFromNodes(
+ request,
+ isNodeAssigningBinaryExpression,
+ visitBinaryExpression,
+ );
};
-const visitBinaryExpression = (node: ts.BinaryExpression, request: FileMutationsRequest): Mutation | undefined => {
- // Grab the types of the declared and assigned nodes
- const assignedType = getTypeAtLocationIfNotError(request, node.right);
- if (assignedType === undefined) {
- return undefined;
- }
+const visitBinaryExpression = (
+ node: ts.BinaryExpression,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Grab the types of the declared and assigned nodes
+ const assignedType = getTypeAtLocationIfNotError(request, node.right);
+ if (assignedType === undefined) {
+ return undefined;
+ }
- const declaredType = getTypeAtLocationIfNotError(request, node.left);
- if (declaredType === undefined || tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)) {
- return undefined;
- }
+ const declaredType = getTypeAtLocationIfNotError(request, node.left);
+ if (
+ declaredType === undefined ||
+ tsutils.isTypeFlagSet(declaredType, ts.TypeFlags.Any)
+ ) {
+ return undefined;
+ }
- // We only care if the assigned type contains a strict flag the declared type doesn't
- if (
- (isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Null) || !isTypeFlagSetRecursively(assignedType, ts.TypeFlags.Null)) &&
- (isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Undefined) || !isTypeFlagSetRecursively(assignedType, ts.TypeFlags.Undefined))
- ) {
- return undefined;
- }
+ // We only care if the assigned type contains a strict flag the declared type doesn't
+ if (
+ (isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Null) ||
+ !isTypeFlagSetRecursively(assignedType, ts.TypeFlags.Null)) &&
+ (isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Undefined) ||
+ !isTypeFlagSetRecursively(assignedType, ts.TypeFlags.Undefined))
+ ) {
+ return undefined;
+ }
- return createNonNullAssertion(request, node.right);
+ return createNonNullAssertion(request, node.right);
};
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionCallExpressions/index.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionCallExpressions/index.ts
index 80cb09034..25278b652 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionCallExpressions/index.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionCallExpressions/index.ts
@@ -1,88 +1,135 @@
-import { combineMutations, MultipleMutations, Mutation } from "automutate";
-import * as ts from "typescript";
-import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags";
+import { MultipleMutations, Mutation, combineMutations } from "automutate";
+import ts from "typescript";
-import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion";
-import { getValueDeclarationOfFunction } from "../../../../shared/functionTypes";
-import { getParentOfKind, getVariableInitializerForExpression } from "../../../../shared/nodes";
-import { isNullOrUndefinedMissingBetween } from "../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags.js";
+import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { getValueDeclarationOfFunction } from "../../../../shared/functionTypes.js";
+import { isNullOrUndefinedMissingBetween } from "../../../../shared/nodeTypes.js";
+import {
+ getParentOfKind,
+ getVariableInitializerForExpression,
+} from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixStrictNonNullAssertionCallExpressions: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- return collectMutationsFromNodes(request, isVisitableCallExpression, visitCallExpression);
+export const fixStrictNonNullAssertionCallExpressions: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ return collectMutationsFromNodes(
+ request,
+ isVisitableCallExpression,
+ visitCallExpression,
+ );
};
const isVisitableCallExpression = (node: ts.Node): node is ts.CallExpression =>
- ts.isCallExpression(node) &&
- // We can quickly ignore any calls without arguments
- node.arguments.length !== 0;
+ ts.isCallExpression(node) &&
+ // We can quickly ignore any calls without arguments
+ node.arguments.length !== 0;
-const visitCallExpression = (node: ts.CallExpression, request: FileMutationsRequest): MultipleMutations | undefined => {
- // Collect the declared type of the function-like being called
- const functionLikeValueDeclaration = getValueDeclarationOfFunction(request, node.expression);
- if (functionLikeValueDeclaration === undefined) {
- return undefined;
- }
- // Collect mutations for each argument as needed
- const argumentMutations = collectArgumentMutations(request, node, functionLikeValueDeclaration);
- if (argumentMutations.length === 0) {
- return undefined;
- }
+const visitCallExpression = (
+ node: ts.CallExpression,
+ request: FileMutationsRequest,
+): MultipleMutations | undefined => {
+ // Collect the declared type of the function-like being called
+ const functionLikeValueDeclaration = getValueDeclarationOfFunction(
+ request,
+ node.expression,
+ );
+ if (functionLikeValueDeclaration === undefined) {
+ return undefined;
+ }
- return combineMutations(...argumentMutations);
+ // Collect mutations for each argument as needed
+ const argumentMutations = collectArgumentMutations(
+ request,
+ node,
+ functionLikeValueDeclaration,
+ );
+ if (argumentMutations.length === 0) {
+ return undefined;
+ }
+
+ return combineMutations(...argumentMutations);
};
const collectArgumentMutations = (
- request: FileMutationsRequest,
- callingNode: ts.CallExpression,
- functionLikeValueDeclaration: ts.SignatureDeclaration,
-): ReadonlyArray => {
- const mutations: Mutation[] = [];
- const visitableArguments = Math.min(callingNode.arguments.length, functionLikeValueDeclaration.parameters.length);
+ request: FileMutationsRequest,
+ callingNode: ts.CallExpression,
+ functionLikeValueDeclaration: ts.SignatureDeclaration,
+): readonly Mutation[] => {
+ const mutations: Mutation[] = [];
+ const visitableArguments = Math.min(
+ callingNode.arguments.length,
+ functionLikeValueDeclaration.parameters.length,
+ );
- // Check the types of each argument being passed in against the declared parameter type
- for (let i = 0; i < visitableArguments; i += 1) {
- // We can ignore parameters that are 'any'
- const typeOfParameter = getTypeAtLocationIfNotError(request, functionLikeValueDeclaration.parameters[i]);
- if (typeOfParameter === undefined || isTypeFlagSetRecursively(typeOfParameter, ts.TypeFlags.Any)) {
- continue;
- }
+ // Check the types of each argument being passed in against the declared parameter type
+ for (let i = 0; i < visitableArguments; i += 1) {
+ // We can ignore parameters that are 'any'
+ const typeOfParameter = getTypeAtLocationIfNotError(
+ request,
+ functionLikeValueDeclaration.parameters[i],
+ );
+ if (
+ typeOfParameter === undefined ||
+ isTypeFlagSetRecursively(typeOfParameter, ts.TypeFlags.Any)
+ ) {
+ continue;
+ }
- const typeOfArgument = getTypeAtLocationIfNotError(request, callingNode.arguments[i]);
+ const typeOfArgument = getTypeAtLocationIfNotError(
+ request,
+ callingNode.arguments[i],
+ );
- // If either null or undefined is missing in the argument, we'll need a ! mutation
- if (typeOfArgument !== undefined && isNullOrUndefinedMissingBetween(typeOfArgument, typeOfParameter)) {
- const argumentMutation = collectArgumentMutation(request, callingNode.arguments[i]);
- if (argumentMutation !== undefined) {
- mutations.push(argumentMutation);
- }
- }
- }
+ // If either null or undefined is missing in the argument, we'll need a ! mutation
+ if (
+ typeOfArgument !== undefined &&
+ isNullOrUndefinedMissingBetween(typeOfArgument, typeOfParameter)
+ ) {
+ const argumentMutation = collectArgumentMutation(
+ request,
+ callingNode.arguments[i],
+ );
+ if (argumentMutation !== undefined) {
+ mutations.push(argumentMutation);
+ }
+ }
+ }
- return mutations;
+ return mutations;
};
-const collectArgumentMutation = (request: FileMutationsRequest, callingArgument: ts.Expression) => {
- // If the argument is a variable declared in the parent function, add the ! to the variable...
- if (ts.isIdentifier(callingArgument)) {
- const declaringVariableInitializer = getVariableInitializerForExpression(
- request,
- callingArgument,
- getParentOfKind(callingArgument, isFunctionBodyOrBlock),
- );
- if (declaringVariableInitializer !== undefined) {
- // ...if the variable doesn't already have a ! after its initial value
- return declaringVariableInitializer.kind === ts.SyntaxKind.NonNullExpression
- ? undefined
- : createNonNullAssertion(request, declaringVariableInitializer);
- }
- }
+const collectArgumentMutation = (
+ request: FileMutationsRequest,
+ callingArgument: ts.Expression,
+) => {
+ // If the argument is a variable declared in the parent function, add the ! to the variable...
+ if (ts.isIdentifier(callingArgument)) {
+ const declaringVariableInitializer = getVariableInitializerForExpression(
+ request,
+ callingArgument,
+ getParentOfKind(callingArgument, isFunctionBodyOrBlock),
+ );
+ if (declaringVariableInitializer !== undefined) {
+ // ...if the variable doesn't already have a ! after its initial value
+ return declaringVariableInitializer.kind ===
+ ts.SyntaxKind.NonNullExpression
+ ? undefined
+ : createNonNullAssertion(request, declaringVariableInitializer);
+ }
+ }
- // Otherwise add the ! at the calling site's argument
- return createNonNullAssertion(request, callingArgument);
+ // Otherwise add the ! at the calling site's argument
+ return createNonNullAssertion(request, callingArgument);
};
-const isFunctionBodyOrBlock = (node: ts.Node): node is ts.Block | ts.FunctionLikeDeclaration | ts.SourceFile =>
- ts.isFunctionLike(node) || ts.isBlock(node) || ts.isSourceFile(node);
+const isFunctionBodyOrBlock = (
+ node: ts.Node,
+): node is ts.Block | ts.FunctionLikeDeclaration | ts.SourceFile =>
+ ts.isFunctionLike(node) || ts.isBlock(node) || ts.isSourceFile(node);
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionObjectLiterals/index.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionObjectLiterals/index.ts
index 50b10b883..8b63eb100 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionObjectLiterals/index.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionObjectLiterals/index.ts
@@ -1,56 +1,74 @@
import { Mutation, combineMutations } from "automutate";
-import * as ts from "typescript";
-
-import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
-import { getManuallyAssignedTypeOfNode } from "../../../../shared/assignments";
-import { getStaticNameOfProperty } from "../../../../shared/names";
-import { isNullOrUndefinedMissingBetween } from "../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-
-export const fixStrictNonNullAssertionObjectLiterals: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- const visitObjectLiteralExpression = (node: ts.ObjectLiteralExpression): Mutation | undefined => {
- return getStrictPropertyFix(request, node);
- };
-
- return collectMutationsFromNodes(request, ts.isObjectLiteralExpression, visitObjectLiteralExpression);
+import ts from "typescript";
+
+import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion.js";
+import { getManuallyAssignedTypeOfNode } from "../../../../shared/assignments.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { getStaticNameOfProperty } from "../../../../shared/names.js";
+import { isNullOrUndefinedMissingBetween } from "../../../../shared/nodeTypes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+
+export const fixStrictNonNullAssertionObjectLiterals: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ const visitObjectLiteralExpression = (
+ node: ts.ObjectLiteralExpression,
+ ): Mutation | undefined => {
+ return getStrictPropertyFix(request, node);
+ };
+
+ return collectMutationsFromNodes(
+ request,
+ ts.isObjectLiteralExpression,
+ visitObjectLiteralExpression,
+ );
};
-const getStrictPropertyFix = (request: FileMutationsRequest, node: ts.ObjectLiteralExpression): Mutation | undefined => {
- // Find the object type the node's properties are being assigned into
- const assignedType = getManuallyAssignedTypeOfNode(request, node);
- if (assignedType === undefined) {
- return undefined;
- }
-
- const propertyMutations = node.properties
- // Find all properties with a nullable value being passed into a non-nullable type
- .filter((property) => {
- // Ignore any property with a name that's not immediately convertable to a string
- const propertyName = getStaticNameOfProperty(property.name);
- if (propertyName === undefined) {
- return false;
- }
-
- // Also ignore any properties not declared in the assigned type
- const assignedProperty = assignedType.getProperty(propertyName);
- if (!assignedProperty) {
- return false;
- }
-
- // We'll mutate properties that are declared as non-nullable but assigned a nullable value
- const propertyType = getTypeAtLocationIfNotError(request, property);
- return (
- propertyType !== undefined &&
- isNullOrUndefinedMissingBetween(
- propertyType,
- request.services.program.getTypeChecker().getDeclaredTypeOfSymbol(assignedProperty),
- )
- );
- })
- // Convert each of those properties into an assertion mutation
- .map((property) => createNonNullAssertion(request, property));
-
- return propertyMutations.length === 0 ? undefined : combineMutations(...propertyMutations);
+const getStrictPropertyFix = (
+ request: FileMutationsRequest,
+ node: ts.ObjectLiteralExpression,
+): Mutation | undefined => {
+ // Find the object type the node's properties are being assigned into
+ const assignedType = getManuallyAssignedTypeOfNode(request, node);
+ if (assignedType === undefined) {
+ return undefined;
+ }
+
+ const propertyMutations = node.properties
+ // Find all properties with a nullable value being passed into a non-nullable type
+ .filter((property) => {
+ // Ignore any property with a name that's not immediately convertible to a string
+ const propertyName = getStaticNameOfProperty(property.name);
+ if (propertyName === undefined) {
+ return false;
+ }
+
+ // Also ignore any properties not declared in the assigned type
+ const assignedProperty = assignedType.getProperty(propertyName);
+ if (!assignedProperty) {
+ return false;
+ }
+
+ // We'll mutate properties that are declared as non-nullable but assigned a nullable value
+ const propertyType = getTypeAtLocationIfNotError(request, property);
+ return (
+ propertyType !== undefined &&
+ isNullOrUndefinedMissingBetween(
+ propertyType,
+ request.services.program
+ .getTypeChecker()
+ .getDeclaredTypeOfSymbol(assignedProperty),
+ )
+ );
+ })
+ // Convert each of those properties into an assertion mutation
+ .map((property) => createNonNullAssertion(request, property));
+
+ return propertyMutations.length === 0
+ ? undefined
+ : combineMutations(...propertyMutations);
};
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionPropertyAccesses/index.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionPropertyAccesses/index.ts
index 9f13779de..d574b6b94 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionPropertyAccesses/index.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionPropertyAccesses/index.ts
@@ -1,34 +1,58 @@
import { Mutation } from "automutate";
-import * as ts from "typescript";
+import ts from "typescript";
-import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags";
-import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags.js";
+import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
-export const fixStrictNonNullAssertionPropertyAccesses: FileMutator = (request: FileMutationsRequest): ReadonlyArray => {
- const visitPropertyAccessExpression = (node: ts.PropertyAccessExpression): Mutation | undefined => {
- return getStrictPropertyAccessFix(request, node);
- };
+export const fixStrictNonNullAssertionPropertyAccesses: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] => {
+ const visitPropertyAccessExpression = (
+ node: ts.PropertyAccessExpression,
+ ): Mutation | undefined => {
+ return getStrictPropertyAccessFix(request, node);
+ };
- return collectMutationsFromNodes(request, ts.isPropertyAccessExpression, visitPropertyAccessExpression);
+ return collectMutationsFromNodes(
+ request,
+ ts.isPropertyAccessExpression,
+ visitPropertyAccessExpression,
+ );
};
-const getStrictPropertyAccessFix = (request: FileMutationsRequest, node: ts.PropertyAccessExpression): Mutation | undefined => {
- // Early on skip checking for "!" needs if there already is one or it's a ?.
- if (ts.isAssertionExpression(node.parent) || ts.isNonNullExpression(node.parent) || node.questionDotToken) {
- return undefined;
- }
+const getStrictPropertyAccessFix = (
+ request: FileMutationsRequest,
+ node: ts.PropertyAccessExpression,
+): Mutation | undefined => {
+ // Early on skip checking for "!" needs if there already is one or it's a ?.
+ if (
+ ts.isAssertionExpression(node.parent) ||
+ ts.isNonNullExpression(node.parent) ||
+ node.questionDotToken
+ ) {
+ return undefined;
+ }
- // Grab the type of the property being accessed by name
- const expressionType = getTypeAtLocationIfNotError(request, node.expression);
+ // Grab the type of the property being accessed by name
+ const expressionType = getTypeAtLocationIfNotError(request, node.expression);
- // If the property's type cannot be null or undefined, rejoice! Nothing to do.
- if (expressionType === undefined || !isTypeFlagSetRecursively(expressionType, ts.TypeFlags.Null | ts.TypeFlags.Undefined)) {
- return undefined;
- }
+ // If the property's type cannot be null or undefined, rejoice! Nothing to do.
+ if (
+ expressionType === undefined ||
+ !isTypeFlagSetRecursively(
+ expressionType,
+ ts.TypeFlags.Null | ts.TypeFlags.Undefined,
+ )
+ ) {
+ return undefined;
+ }
- // Add a mutation to insert a "!" before the access
- return createNonNullAssertion(request, node.expression);
+ // Add a mutation to insert a "!" before the access
+ return createNonNullAssertion(request, node.expression);
};
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/collectReturningNodeExpressions.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/collectReturningNodeExpressions.ts
index 31d521268..39fb0c891 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/collectReturningNodeExpressions.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/collectReturningNodeExpressions.ts
@@ -1,30 +1,31 @@
-import * as ts from "typescript";
+import ts from "typescript";
/**
* Finds any nodes returned by a function-like.
- *
- * @param functionLikeDeclaration Returning function-like declaration.
+ * @param functionLikeDeclaration Returning function-like declaration to collect within.
* @returns Expression nodes returned from the function-like.
*/
-export const collectReturningNodeExpressions = (functionLikeDeclaration: ts.FunctionLikeDeclaration): ReadonlyArray => {
- const returnedTypes: ts.Expression[] = [];
+export const collectReturningNodeExpressions = (
+ functionLikeDeclaration: ts.FunctionLikeDeclaration,
+): readonly ts.Expression[] => {
+ const returnedTypes: ts.Expression[] = [];
- // Search through nodes within the function-like to find all its return statements
- const visitNode = (node: ts.Node): void => {
- // Don't look at returns within a nested function-like signature: they return for that function
- if (ts.isFunctionLike(node)) {
- return;
- }
+ // Search through nodes within the function-like to find all its return statements
+ const visitNode = (node: ts.Node): void => {
+ // Don't look at returns within a nested function-like signature: they return for that function
+ if (ts.isFunctionLike(node)) {
+ return;
+ }
- // Add new returning nodes as needed when we find any 'return' statement with a value (expression) returned
- if (ts.isReturnStatement(node) && node.expression !== undefined) {
- returnedTypes.push(node.expression);
- }
+ // Add new returning nodes as needed when we find any 'return' statement with a value (expression) returned
+ if (ts.isReturnStatement(node) && node.expression !== undefined) {
+ returnedTypes.push(node.expression);
+ }
- ts.forEachChild(node, visitNode);
- };
+ ts.forEachChild(node, visitNode);
+ };
- ts.forEachChild(functionLikeDeclaration, visitNode);
+ ts.forEachChild(functionLikeDeclaration, visitNode);
- return returnedTypes;
+ return returnedTypes;
};
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/index.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/index.ts
index f70ed54a8..b9e411b39 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/index.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/fixStrictNonNullAssertionReturnTypes/index.ts
@@ -1,78 +1,118 @@
-import { combineMutations, Mutation } from "automutate";
-import * as tsutils from "ts-api-utils";
-import * as ts from "typescript";
+import { Mutation, combineMutations } from "automutate";
+import ts from "typescript";
-import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags";
-import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion";
-import { getVariableInitializerForExpression } from "../../../../shared/nodes";
-import { FunctionLikeDeclarationWithType, isNodeWithType } from "../../../../shared/nodeTypes";
-import { getTypeAtLocationIfNotError } from "../../../../shared/types";
-import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes";
-import { FileMutationsRequest, FileMutator } from "../../../../shared/fileMutator";
+import { isTypeFlagSetRecursively } from "../../../../mutations/collecting/flags.js";
+import { createNonNullAssertion } from "../../../../mutations/typeMutating/createNonNullAssertion.js";
+import {
+ FileMutationsRequest,
+ FileMutator,
+} from "../../../../shared/fileMutator.js";
+import {
+ FunctionLikeDeclarationWithType,
+ isNodeWithType,
+} from "../../../../shared/nodeTypes.js";
+import { getVariableInitializerForExpression } from "../../../../shared/nodes.js";
+import { getTypeAtLocationIfNotError } from "../../../../shared/types.js";
+import { collectMutationsFromNodes } from "../../../collectMutationsFromNodes.js";
+import { collectReturningNodeExpressions } from "./collectReturningNodeExpressions.js";
-import { collectReturningNodeExpressions } from "./collectReturningNodeExpressions";
+export const fixStrictNonNullAssertionReturnTypes: FileMutator = (
+ request: FileMutationsRequest,
+): readonly Mutation[] =>
+ collectMutationsFromNodes(
+ request,
+ isNodeVisitableFunctionLikeDeclaration,
+ visitFunctionWithBody,
+ );
-export const fixStrictNonNullAssertionReturnTypes: FileMutator = (request: FileMutationsRequest): ReadonlyArray =>
- collectMutationsFromNodes(request, isNodeVisitableFunctionLikeDeclaration, visitFunctionWithBody);
+const isNodeVisitableFunctionLikeDeclaration = (
+ node: ts.Node,
+): node is FunctionLikeDeclarationWithType =>
+ ts.isFunctionLike(node) &&
+ // If the node has an implicit return type, we don't need to change anything
+ isNodeWithType(node);
-const isNodeVisitableFunctionLikeDeclaration = (node: ts.Node): node is FunctionLikeDeclarationWithType =>
- ts.isFunctionLike(node) &&
- // If the node has an implicit return type, we don't need to change anything
- isNodeWithType(node);
+const visitFunctionWithBody = (
+ node: FunctionLikeDeclarationWithType,
+ request: FileMutationsRequest,
+): Mutation | undefined => {
+ // Collect the type initially declared as returned and whether it contains null and/or undefined
+ const declaredType = getTypeAtLocationIfNotError(request, node.type);
-const visitFunctionWithBody = (node: FunctionLikeDeclarationWithType, request: FileMutationsRequest): Mutation | undefined => {
- // Collect the type initially declared as returned and whether it contains null and/or undefined
- const declaredType = getTypeAtLocationIfNotError(request, node.type);
+ // If the node's explicit return type contains 'any', we can't infer anything
+ if (
+ declaredType === undefined ||
+ isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Any)
+ ) {
+ return undefined;
+ }
- // If the node's explicit return type contains 'any', we can't infer anything
- if (declaredType === undefined || isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Any)) {
- return undefined;
- }
+ // If the type already has both null or undefined, all is well; rejoice!
+ const returningNull = isTypeFlagSetRecursively(
+ declaredType,
+ ts.TypeFlags.Null,
+ );
+ const returningUndefined = isTypeFlagSetRecursively(
+ declaredType,
+ ts.TypeFlags.Undefined,
+ );
+ if (returningNull && returningUndefined) {
+ return undefined;
+ }
- // If the type already has both null or undefined, all is well; rejoice!
- const returningNull = isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Null);
- const returningUndefined = isTypeFlagSetRecursively(declaredType, ts.TypeFlags.Undefined);
- if (returningNull && returningUndefined) {
- return undefined;
- }
+ // From now on, we only care about the two types of strict values that could be returned
+ const missingReturnTypes =
+ (returningNull ? 0 : ts.TypeFlags.Null) |
+ (returningUndefined ? 0 : ts.TypeFlags.Undefined);
- // From now on, we only care about the two types of strict values that could be returned
- const missingReturnTypes = (returningNull ? 0 : ts.TypeFlags.Null) | (returningUndefined ? 0 : ts.TypeFlags.Undefined);
+ // Collect ! additions for the return types of nodes in the function
+ const returningNodeExpressions = collectReturningNodeExpressions(node);
+ const mutations = collectNonNullMutations(
+ request,
+ node,
+ missingReturnTypes,
+ returningNodeExpressions,
+ );
- // Collect ! additions for the return types of nodes in the function
- const returningNodeExpressions = collectReturningNodeExpressions(node);
- const mutations = collectNonNullMutations(request, node, missingReturnTypes, returningNodeExpressions);
-
- return mutations.length === 0 ? undefined : combineMutations(...mutations);
+ return mutations.length === 0 ? undefined : combineMutations(...mutations);
};
const collectNonNullMutations = (
- request: FileMutationsRequest,
- functionLike: FunctionLikeDeclarationWithType,
- missingReturnTypes: ts.TypeFlags,
- expressions: ReadonlyArray,
-): ReadonlyArray => {
- const mutations: Mutation[] = [];
+ request: FileMutationsRequest,
+ functionLike: FunctionLikeDeclarationWithType,
+ missingReturnTypes: ts.TypeFlags,
+ expressions: readonly ts.Expression[],
+): readonly Mutation[] => {
+ const mutations: Mutation[] = [];
- for (const expression of expressions) {
- // If the expression doesn't return a type missing from the return, it's already safe
- const expressionType = getTypeAtLocationIfNotError(request, expression);
- if (expressionType === undefined || !isTypeFlagSetRecursively(expressionType, missingReturnTypes)) {
- continue;
- }
+ for (const expression of expressions) {
+ // If the expression doesn't return a type missing from the return, it's already safe
+ const expressionType = getTypeAtLocationIfNotError(request, expression);
+ if (
+ expressionType === undefined ||
+ !isTypeFlagSetRecursively(expressionType, missingReturnTypes)
+ ) {
+ continue;
+ }
- // If the expression is an variable declared in the parent function, add the ! to the variable
- if (ts.isIdentifier(expression)) {
- const declaringVariableInitializer = getVariableInitializerForExpression(request, expression, functionLike);
- if (declaringVariableInitializer !== undefined) {
- mutations.push(createNonNullAssertion(request, declaringVariableInitializer));
- continue;
- }
- }
+ // If the expression is an variable declared in the parent function, add the ! to the variable
+ if (ts.isIdentifier(expression)) {
+ const declaringVariableInitializer = getVariableInitializerForExpression(
+ request,
+ expression,
+ functionLike,
+ );
+ if (declaringVariableInitializer !== undefined) {
+ mutations.push(
+ createNonNullAssertion(request, declaringVariableInitializer),
+ );
+ continue;
+ }
+ }
- // Otherwise, add it at the end of the expression
- mutations.push(createNonNullAssertion(request, expression));
- }
+ // Otherwise, add it at the end of the expression
+ mutations.push(createNonNullAssertion(request, expression));
+ }
- return mutations;
+ return mutations;
};
diff --git a/src/mutators/builtIn/fixStrictNonNullAssertions/index.ts b/src/mutators/builtIn/fixStrictNonNullAssertions/index.ts
index fae3a142d..301474838 100644
--- a/src/mutators/builtIn/fixStrictNonNullAssertions/index.ts
+++ b/src/mutators/builtIn/fixStrictNonNullAssertions/index.ts
@@ -1,19 +1,33 @@
-import { findFirstMutations } from "../../../shared/runtime";
-import { FileMutationsRequest } from "../../../shared/fileMutator";
-
-import { fixStrictNonNullAssertionBinaryExpressions } from "./fixStrictNonNullAssertionBinaryExpressions";
-import { fixStrictNonNullAssertionCallExpressions } from "./fixStrictNonNullAssertionCallExpressions";
-import { fixStrictNonNullAssertionObjectLiterals } from "./fixStrictNonNullAssertionObjectLiterals";
-import { fixStrictNonNullAssertionPropertyAccesses } from "./fixStrictNonNullAssertionPropertyAccesses";
-import { fixStrictNonNullAssertionReturnTypes } from "./fixStrictNonNullAssertionReturnTypes";
+import { FileMutationsRequest } from "../../../shared/fileMutator.js";
+import { findFirstMutations } from "../../../shared/runtime.js";
+import { fixStrictNonNullAssertionBinaryExpressions } from "./fixStrictNonNullAssertionBinaryExpressions/index.js";
+import { fixStrictNonNullAssertionCallExpressions } from "./fixStrictNonNullAssertionCallExpressions/index.js";
+import { fixStrictNonNullAssertionObjectLiterals } from "./fixStrictNonNullAssertionObjectLiterals/index.js";
+import { fixStrictNonNullAssertionPropertyAccesses } from "./fixStrictNonNullAssertionPropertyAccesses/index.js";
+import { fixStrictNonNullAssertionReturnTypes } from "./fixStrictNonNullAssertionReturnTypes/index.js";
export const fixStrictNonNullAssertions = (request: FileMutationsRequest) =>
- request.options.fixes.strictNonNullAssertions
- ? findFirstMutations(request, [
- ["fixStrictNonNullAssertionBinaryExpressions", fixStrictNonNullAssertionBinaryExpressions],
- ["fixStrictNonNullAssertionCallExpressions", fixStrictNonNullAssertionCallExpressions],
- ["fixStrictNonNullAssertionObjectLiterals", fixStrictNonNullAssertionObjectLiterals],
- ["fixStrictNonNullAssertionPropertyAccesses", fixStrictNonNullAssertionPropertyAccesses],
- ["fixStrictNonNullAssertionReturnTypes", fixStrictNonNullAssertionReturnTypes],
- ])
- : undefined;
+ request.options.fixes.strictNonNullAssertions
+ ? findFirstMutations(request, [
+ [
+ "fixStrictNonNullAssertionBinaryExpressions",
+ fixStrictNonNullAssertionBinaryExpressions,
+ ],
+ [
+ "fixStrictNonNullAssertionCallExpressions",
+ fixStrictNonNullAssertionCallExpressions,
+ ],
+ [
+ "fixStrictNonNullAssertionObjectLiterals",
+ fixStrictNonNullAssertionObjectLiterals,
+ ],
+ [
+ "fixStrictNonNullAssertionPropertyAccesses",
+ fixStrictNonNullAssertionPropertyAccesses,
+ ],
+ [
+ "fixStrictNonNullAssertionReturnTypes",
+ fixStrictNonNullAssertionReturnTypes,
+ ],
+ ])
+ : undefined;
diff --git a/src/mutators/builtIn/index.ts b/src/mutators/builtIn/index.ts
index f1d2b8166..0f03b1806 100644
--- a/src/mutators/builtIn/index.ts
+++ b/src/mutators/builtIn/index.ts
@@ -1,19 +1,18 @@
-import { FileMutator } from "../../shared/fileMutator";
+import { FileMutator } from "../../shared/fileMutator.js";
+import { fixImportExtensions } from "./fixImportExtensions/index.js";
+import { fixIncompleteTypes } from "./fixIncompleteTypes/index.js";
+import { fixMissingProperties } from "./fixMissingProperties/index.js";
+import { fixNoImplicitAny } from "./fixNoImplicitAny/index.js";
+import { fixNoImplicitThis } from "./fixNoImplicitThis/index.js";
+import { fixNoInferableTypes } from "./fixNoInferableTypes/index.js";
+import { fixStrictNonNullAssertions } from "./fixStrictNonNullAssertions/index.js";
-import { fixImportExtensions } from "./fixImportExtensions";
-import { fixIncompleteTypes } from "./fixIncompleteTypes";
-import { fixMissingProperties } from "./fixMissingProperties";
-import { fixNoImplicitAny } from "./fixNoImplicitAny";
-import { fixNoImplicitThis } from "./fixNoImplicitThis";
-import { fixNoInferableTypes } from "./fixNoInferableTypes";
-import { fixStrictNonNullAssertions } from "./fixStrictNonNullAssertions";
-
-export const builtInFileMutators: ReadonlyArray<[string, FileMutator]> = [
- ["fixImportExtensions", fixImportExtensions],
- ["fixIncompleteTypes", fixIncompleteTypes],
- ["fixMissingProperties", fixMissingProperties],
- ["fixNoImplicitAny", fixNoImplicitAny],
- ["fixNoImplicitThis", fixNoImplicitThis],
- ["fixNoInferableTypes", fixNoInferableTypes],
- ["fixStrictNonNullAssertions", fixStrictNonNullAssertions],
+export const builtInFileMutators: readonly [string, FileMutator][] = [
+ ["fixImportExtensions", fixImportExtensions],
+ ["fixIncompleteTypes", fixIncompleteTypes],
+ ["fixMissingProperties", fixMissingProperties],
+ ["fixNoImplicitAny", fixNoImplicitAny],
+ ["fixNoImplicitThis", fixNoImplicitThis],
+ ["fixNoInferableTypes", fixNoInferableTypes],
+ ["fixStrictNonNullAssertions", fixStrictNonNullAssertions],
];
diff --git a/src/mutators/collectMutationsFromNodes.ts b/src/mutators/collectMutationsFromNodes.ts
index 883fc69ce..d6080620c 100644
--- a/src/mutators/collectMutationsFromNodes.ts
+++ b/src/mutators/collectMutationsFromNodes.ts
@@ -1,52 +1,58 @@
import { Mutation } from "automutate";
import { EOL } from "os";
-import * as ts from "typescript";
+import ts from "typescript";
-import { getQuickErrorSummary } from "../shared/errors";
-import { NodeSelector } from "../shared/nodeTypes";
+import { getQuickErrorSummary } from "../shared/errors.js";
+import { FileMutationsRequest } from "../shared/fileMutator.js";
+import { NodeSelector } from "../shared/nodeTypes.js";
-import { FileMutationsRequest } from "../shared/fileMutator";
-
-export type NodeVisitor = (node: TNode, request: FileMutationsRequest) => Readonly | undefined;
+export type NodeVisitor = (
+ node: TNode,
+ request: FileMutationsRequest,
+) => Readonly | undefined;
export const collectMutationsFromNodes = (
- request: FileMutationsRequest,
- selector: NodeSelector,
- visitor: NodeVisitor,
+ request: FileMutationsRequest,
+ selector: NodeSelector,
+ visitor: NodeVisitor,
) => {
- const mutations: Mutation[] = [];
+ const mutations: Mutation[] = [];
- const visitNode = (node: ts.Node) => {
- if (request.filteredNodes.has(node)) {
- return;
- }
+ const visitNode = (node: ts.Node) => {
+ if (request.filteredNodes.has(node)) {
+ return;
+ }
- if (selector(node)) {
- const mutation = tryGetMutation(request, node, visitor);
+ if (selector(node)) {
+ const mutation = tryGetMutation(request, node, visitor);
- if (mutation !== undefined) {
- mutations.push(mutation);
- }
- }
+ if (mutation !== undefined) {
+ mutations.push(mutation);
+ }
+ }
- ts.forEachChild(node, visitNode);
- };
+ ts.forEachChild(node, visitNode);
+ };
- ts.forEachChild(request.sourceFile, visitNode);
+ ts.forEachChild(request.sourceFile, visitNode);
- return mutations;
+ return mutations;
};
-const tryGetMutation = (request: FileMutationsRequest, node: TNode, visitor: NodeVisitor) => {
- try {
- return visitor(node, request);
- } catch (error) {
- request.options.output.stderr(
- `${EOL}Error in ${request.sourceFile.fileName} at node '${node.getText(request.sourceFile)}' (position ${node.pos}):`,
- );
- request.options.output.stderr(`\t${getQuickErrorSummary(error)}`);
- request.options.output.stderr(EOL);
- }
-
- return undefined;
+const tryGetMutation = (
+ request: FileMutationsRequest,
+ node: TNode,
+ visitor: NodeVisitor,
+) => {
+ try {
+ return visitor(node, request);
+ } catch (error) {
+ request.options.output.stderr(
+ `${EOL}Error in ${request.sourceFile.fileName} at node '${node.getText(request.sourceFile)}' (position ${node.pos}):`,
+ );
+ request.options.output.stderr(`\t${getQuickErrorSummary(error)}`);
+ request.options.output.stderr(EOL);
+ }
+
+ return undefined;
};
diff --git a/src/mutators/complaint.ts b/src/mutators/complaint.ts
index f8ace8314..5cc54e3d8 100644
--- a/src/mutators/complaint.ts
+++ b/src/mutators/complaint.ts
@@ -2,9 +2,18 @@
* Error and nested mutation path from a runtime failure.
*/
export class MutationsComplaint {
- public constructor(public readonly error: Error, public readonly mutatorPath: readonly string[]) {}
+ public constructor(
+ public readonly error: Error,
+ public readonly mutatorPath: readonly string[],
+ ) {}
- public static wrapping(mutatorName: string, subComplaint: MutationsComplaint) {
- return new MutationsComplaint(subComplaint.error, [mutatorName, ...subComplaint.mutatorPath]);
- }
+ public static wrapping(
+ mutatorName: string,
+ subComplaint: MutationsComplaint,
+ ) {
+ return new MutationsComplaint(subComplaint.error, [
+ mutatorName,
+ ...subComplaint.mutatorPath,
+ ]);
+ }
}
diff --git a/src/options/enums.ts b/src/options/enums.ts
index a9227f606..4040d2ba9 100644
--- a/src/options/enums.ts
+++ b/src/options/enums.ts
@@ -2,38 +2,38 @@
* Whether to use components' propTypes for inferences.
*/
export enum ReactPropTypesHint {
- /**
- * Always factor in all propTypes.
- */
- Always = "always",
+ /**
+ * Always factor in all propTypes.
+ */
+ Always = "always",
- /**
- * Don't factor in propTypes at all.
- */
- Ignore = "ignore",
+ /**
+ * Don't factor in propTypes at all.
+ */
+ Ignore = "ignore",
- /**
- * Only factor in nodes that are make as .required.
- */
- WhenRequired = "whenRequired",
+ /**
+ * Only factor in nodes that are make as .required.
+ */
+ WhenRequired = "whenRequired",
}
/**
* Whether to make propType inferences optional and/or required.
*/
export enum ReactPropTypesOptionality {
- /**
- * Always make the added props optional.
- */
- AlwaysOptional = "alwaysOptional",
+ /**
+ * Always make the added props optional.
+ */
+ AlwaysOptional = "alwaysOptional",
- /**
- * Always make the added props required.
- */
- AlwaysRequired = "alwaysRequired",
+ /**
+ * Always make the added props required.
+ */
+ AlwaysRequired = "alwaysRequired",
- /**
- * Respect whether the original code has .isRequired.
- */
- AsWritten = "asWritten",
+ /**
+ * Respect whether the original code has .isRequired.
+ */
+ AsWritten = "asWritten",
}
diff --git a/src/options/fillOutRawOptions.ts b/src/options/fillOutRawOptions.ts
index 2aca8ed39..6fc796100 100644
--- a/src/options/fillOutRawOptions.ts
+++ b/src/options/fillOutRawOptions.ts
@@ -1,87 +1,93 @@
-import { TypeStatArgv } from "../index";
-import { ProcessOutput } from "../output/types";
-import { collectOptionals } from "../shared/arrays";
-import { ReactPropTypesHint, ReactPropTypesOptionality } from "./enums";
-import { ParsedCompilerOptions } from "./parseRawCompilerOptions";
-
-import { collectAddedMutators } from "./parsing/collectAddedMutators";
-import { collectFileOptions } from "./parsing/collectFileOptions";
-import { collectNoImplicitAny } from "./parsing/collectNoImplicitAny";
-import { collectNoImplicitThis } from "./parsing/collectNoImplicitThis";
-import { collectPackageOptions } from "./parsing/collectPackageOptions";
-import { collectStrictNullChecks } from "./parsing/collectStrictNullChecks";
-import { PendingTypeStatOptions, RawTypeStatOptions } from "./types";
+import { TypeStatArgv } from "../index.js";
+import { ProcessOutput } from "../output/types.js";
+import { collectOptionals } from "../shared/arrays.js";
+import { ReactPropTypesHint, ReactPropTypesOptionality } from "./enums.js";
+import { ParsedCompilerOptions } from "./parseRawCompilerOptions.js";
+import { collectAddedMutators } from "./parsing/collectAddedMutators.js";
+import { collectFileOptions } from "./parsing/collectFileOptions.js";
+import { collectNoImplicitAny } from "./parsing/collectNoImplicitAny.js";
+import { collectNoImplicitThis } from "./parsing/collectNoImplicitThis.js";
+import { collectPackageOptions } from "./parsing/collectPackageOptions.js";
+import { collectStrictNullChecks } from "./parsing/collectStrictNullChecks.js";
+import { PendingTypeStatOptions, RawTypeStatOptions } from "./types.js";
export interface OptionsFromRawOptionsSettings {
- argv: TypeStatArgv;
- compilerOptions: Readonly;
- cwd: string;
- output: ProcessOutput;
- projectPath: string;
- rawOptions: RawTypeStatOptions;
+ argv: TypeStatArgv;
+ compilerOptions: Readonly;
+ cwd: string;
+ output: ProcessOutput;
+ projectPath: string;
+ rawOptions: RawTypeStatOptions;
}
/**
* Combines Node and CLi argument options with project and file metadata into pending TypeStat options.
- *
* @returns Parsed TypeStat options, or a string for an error complaint.
*/
export const fillOutRawOptions = ({
- compilerOptions,
- cwd,
- output,
- projectPath,
- rawOptions,
+ compilerOptions,
+ cwd,
+ output,
+ projectPath,
+ rawOptions,
}: OptionsFromRawOptionsSettings): PendingTypeStatOptions => {
- const rawOptionTypes = rawOptions.types ?? {};
- const noImplicitAny = collectNoImplicitAny(compilerOptions, rawOptions);
- const noImplicitThis = collectNoImplicitThis(compilerOptions, rawOptions);
- const { compilerStrictNullChecks, typeStrictNullChecks } = collectStrictNullChecks(compilerOptions, rawOptionTypes);
+ const rawOptionTypes = rawOptions.types ?? {};
+ const noImplicitAny = collectNoImplicitAny(compilerOptions, rawOptions);
+ const noImplicitThis = collectNoImplicitThis(compilerOptions, rawOptions);
+ const { compilerStrictNullChecks, typeStrictNullChecks } =
+ collectStrictNullChecks(compilerOptions, rawOptionTypes);
- const packageOptions = collectPackageOptions(cwd, rawOptions);
+ const packageOptions = collectPackageOptions(cwd, rawOptions);
- const shell: (readonly string[])[] = [];
- if (rawOptions.postProcess?.shell !== undefined) {
- shell.push(...rawOptions.postProcess.shell);
- }
+ const shell: (readonly string[])[] = [];
+ if (rawOptions.postProcess?.shell !== undefined) {
+ shell.push(...rawOptions.postProcess.shell);
+ }
- return {
- compilerOptions: {
- ...compilerOptions,
- noImplicitAny,
- noImplicitThis,
- strictNullChecks: compilerStrictNullChecks,
- },
- files: collectFileOptions(rawOptions),
- filters: collectOptionals(rawOptions.filters),
- fixes: {
- importExtensions: false,
- incompleteTypes: false,
- missingProperties: false,
- noImplicitAny: false,
- noImplicitThis: false,
- noInferableTypes: false,
- strictNonNullAssertions: false,
- ...rawOptions.fixes,
- },
- hints: {
- react: {
- propTypes: rawOptions.hints?.react?.propTypes ?? ReactPropTypesHint.WhenRequired,
- propTypesOptionality: rawOptions.hints?.react?.propTypesOptionality ?? ReactPropTypesOptionality.AsWritten,
- },
- },
- include: rawOptions.include ?? compilerOptions.include,
- mutators: collectAddedMutators(rawOptions, packageOptions.directory, output),
- output,
- package: packageOptions,
- postProcess: { shell },
- projectPath,
- cleanups: {
- suppressTypeErrors: false,
- ...rawOptions.cleanups,
- },
- types: {
- strictNullChecks: typeStrictNullChecks,
- },
- };
+ return {
+ cleanups: {
+ suppressTypeErrors: false,
+ ...rawOptions.cleanups,
+ },
+ compilerOptions: {
+ ...compilerOptions,
+ noImplicitAny,
+ noImplicitThis,
+ strictNullChecks: compilerStrictNullChecks,
+ },
+ files: collectFileOptions(rawOptions),
+ filters: collectOptionals(rawOptions.filters),
+ fixes: {
+ importExtensions: false,
+ incompleteTypes: false,
+ missingProperties: false,
+ noImplicitAny: false,
+ noImplicitThis: false,
+ noInferableTypes: false,
+ strictNonNullAssertions: false,
+ ...rawOptions.fixes,
+ },
+ hints: {
+ react: {
+ propTypes:
+ rawOptions.hints?.react?.propTypes ?? ReactPropTypesHint.WhenRequired,
+ propTypesOptionality:
+ rawOptions.hints?.react?.propTypesOptionality ??
+ ReactPropTypesOptionality.AsWritten,
+ },
+ },
+ include: rawOptions.include ?? compilerOptions.include,
+ mutators: collectAddedMutators(
+ rawOptions,
+ packageOptions.directory,
+ output,
+ ),
+ output,
+ package: packageOptions,
+ postProcess: { shell },
+ projectPath,
+ types: {
+ strictNullChecks: typeStrictNullChecks,
+ },
+ };
};
diff --git a/src/options/findRawOptions.ts b/src/options/findRawOptions.ts
index 41a7d5092..733d0e616 100644
--- a/src/options/findRawOptions.ts
+++ b/src/options/findRawOptions.ts
@@ -1,61 +1,71 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-import * as path from "path";
+import * as path from "node:path";
-import { RawTypeStatOptions } from "./types";
+import { RawTypeStatOptions } from "./types.js";
/**
* Results from searching for a raw TypeStat configuration file.
*/
export interface FoundRawOptions {
- /**
- * Raw configuration options to run in order.
- */
- allRawOptions: RawTypeStatOptions[];
-
- /**
- * Found file path result, if a file on disk was found.
- */
- filePath?: string;
+ /**
+ * Raw configuration options to run in order.
+ */
+ allRawOptions: RawTypeStatOptions[];
+
+ /**
+ * Found file path result, if a file on disk was found.
+ */
+ filePath?: string;
}
/**
* Parses raw options from a configuration file.
- *
* @param cwd Base directory to resolve paths from.
* @param configPath Suggested path to load from, instead of searching.
* @returns Parsed raw options from a configuration file, or an error string.
*/
-export const findRawOptions = (cwd: string, configPath: string): FoundRawOptions | string => {
- const resolutionPath = path.join(cwd, configPath);
+export const findRawOptions = (
+ cwd: string,
+ configPath: string,
+): FoundRawOptions | string => {
+ const resolutionPath = path.join(cwd, configPath);
- let filePath: string;
- try {
- filePath = require.resolve(resolutionPath);
- } catch {
- return configPath === resolutionPath
- ? `Could not find config file at '${configPath}'.`
- : `Could not find config file at '${configPath}' (resolved to '${resolutionPath}').`;
- }
+ let filePath: string;
+ try {
+ filePath = require.resolve(resolutionPath);
+ } catch {
+ return configPath === resolutionPath
+ ? `Could not find config file at '${configPath}'.`
+ : `Could not find config file at '${configPath}' (resolved to '${resolutionPath}').`;
+ }
- const allRawOptions = extractConfigAsRelative(filePath, require(filePath) as RawTypeStatOptions | RawTypeStatOptions[]);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-var-requires
+ const allRawOptions = extractConfigAsRelative(filePath, require(filePath));
- return { filePath, allRawOptions };
+ return { allRawOptions, filePath };
};
-const extractConfigAsRelative = (filePath: string, config: RawTypeStatOptions | RawTypeStatOptions[]): RawTypeStatOptions[] => {
- return config instanceof Array ? config.map((config) => relativizeConfig(filePath, config)) : [relativizeConfig(filePath, config)];
+const extractConfigAsRelative = (
+ filePath: string,
+ config: RawTypeStatOptions | RawTypeStatOptions[],
+): RawTypeStatOptions[] => {
+ return config instanceof Array
+ ? config.map((config) => relativizeConfig(filePath, config))
+ : [relativizeConfig(filePath, config)];
};
const relativizeConfig = (filePath: string, config: RawTypeStatOptions) => {
- if (config.package?.directory !== undefined && !path.isAbsolute(config.package.directory)) {
- config = {
- ...config,
- package: {
- ...config.package,
- directory: path.join(filePath, config.package.directory),
- },
- };
- }
-
- return config;
+ if (
+ config.package?.directory !== undefined &&
+ !path.isAbsolute(config.package.directory)
+ ) {
+ config = {
+ ...config,
+ package: {
+ ...config.package,
+ directory: path.join(filePath, config.package.directory),
+ },
+ };
+ }
+
+ return config;
};
diff --git a/src/options/loadPendingOptions.ts b/src/options/loadPendingOptions.ts
index e6c3ae402..aee74384e 100644
--- a/src/options/loadPendingOptions.ts
+++ b/src/options/loadPendingOptions.ts
@@ -1,61 +1,75 @@
-import * as path from "path";
+import * as path from "node:path";
-import { TypeStatArgv } from "../index";
-import { ProcessOutput } from "../output/types";
-import { normalizeAndSlashify } from "../shared/paths";
-
-import { fillOutRawOptions } from "./fillOutRawOptions";
-import { findRawOptions } from "./findRawOptions";
-import { findComplaintForOptions } from "./optionVerification";
-import { parseRawCompilerOptions } from "./parseRawCompilerOptions";
-import { PendingTypeStatOptions, RawTypeStatOptions } from "./types";
+import { TypeStatArgv } from "../index.js";
+import { ProcessOutput } from "../output/types.js";
+import { normalizeAndSlashify } from "../shared/paths.js";
+import { fillOutRawOptions } from "./fillOutRawOptions.js";
+import { findRawOptions } from "./findRawOptions.js";
+import { findComplaintForOptions } from "./optionVerification.js";
+import { parseRawCompilerOptions } from "./parseRawCompilerOptions.js";
+import { PendingTypeStatOptions, RawTypeStatOptions } from "./types.js";
/**
* Reads pre-file-rename TypeStat options using a config path.
- *
* @param argv Root arguments passed to TypeStat.
* @param output Wraps process and logfile output.
* @returns Promise for filled-out TypeStat options, or a string complaint from failing to make them.
*/
-export const loadPendingOptions = async (argv: TypeStatArgv, output: ProcessOutput): Promise => {
- if (argv.config === undefined) {
- return "-c/--config file must be provided.";
- }
-
- const cwd = process.cwd();
- const foundRawOptions = findRawOptions(cwd, argv.config);
- if (typeof foundRawOptions === "string") {
- return foundRawOptions;
- }
-
- const { allRawOptions, filePath } = foundRawOptions;
- const results: PendingTypeStatOptions[] = [];
-
- // Fill out each option in the config with its own separate settings
- // (or return the first failure string describing which one is incorrect)
- for (let i = 0; i < allRawOptions.length; i += 1) {
- const rawOptions = allRawOptions[i];
- const projectPath = getProjectPath(cwd, filePath, rawOptions);
- const compilerOptions = await parseRawCompilerOptions(cwd, projectPath);
-
- const filledOutOptions = fillOutRawOptions({ argv, compilerOptions, cwd, output, projectPath, rawOptions });
- const complaint = findComplaintForOptions(filledOutOptions);
- if (complaint) {
- return `Invalid options at index ${i}: ${complaint}`;
- }
-
- results.push(filledOutOptions);
- }
-
- return results;
+export const loadPendingOptions = async (
+ argv: TypeStatArgv,
+ output: ProcessOutput,
+): Promise => {
+ if (argv.config === undefined) {
+ return "-c/--config file must be provided.";
+ }
+
+ const cwd = process.cwd();
+ const foundRawOptions = findRawOptions(cwd, argv.config);
+ if (typeof foundRawOptions === "string") {
+ return foundRawOptions;
+ }
+
+ const { allRawOptions, filePath } = foundRawOptions;
+ const results: PendingTypeStatOptions[] = [];
+
+ // Fill out each option in the config with its own separate settings
+ // (or return the first failure string describing which one is incorrect)
+ for (let i = 0; i < allRawOptions.length; i += 1) {
+ const rawOptions = allRawOptions[i];
+ const projectPath = getProjectPath(cwd, filePath, rawOptions);
+ const compilerOptions = await parseRawCompilerOptions(cwd, projectPath);
+
+ const filledOutOptions = fillOutRawOptions({
+ argv,
+ compilerOptions,
+ cwd,
+ output,
+ projectPath,
+ rawOptions,
+ });
+ const complaint = findComplaintForOptions(filledOutOptions);
+ if (complaint) {
+ return `Invalid options at index ${i}: ${complaint}`;
+ }
+
+ results.push(filledOutOptions);
+ }
+
+ return results;
};
-const getProjectPath = (cwd: string, filePath: string | undefined, rawOptions: RawTypeStatOptions): string => {
- // If the TypeStat configuration file has a projectPath field, use that relative to the file
- if (filePath !== undefined && rawOptions.projectPath !== undefined) {
- return normalizeAndSlashify(path.join(path.dirname(filePath), rawOptions.projectPath));
- }
+const getProjectPath = (
+ cwd: string,
+ filePath: string | undefined,
+ rawOptions: RawTypeStatOptions,
+): string => {
+ // If the TypeStat configuration file has a projectPath field, use that relative to the file
+ if (filePath !== undefined && rawOptions.projectPath !== undefined) {
+ return normalizeAndSlashify(
+ path.join(path.dirname(filePath), rawOptions.projectPath),
+ );
+ }
- // Otherwise give up and try a ./tsconfig.json relative to the package directory
- return normalizeAndSlashify(path.join(cwd, "tsconfig.json"));
+ // Otherwise give up and try a ./tsconfig.json relative to the package directory
+ return normalizeAndSlashify(path.join(cwd, "tsconfig.json"));
};
diff --git a/src/options/optionVerification.ts b/src/options/optionVerification.ts
index 2e9cc10ff..79b73c30a 100644
--- a/src/options/optionVerification.ts
+++ b/src/options/optionVerification.ts
@@ -1,27 +1,31 @@
-import { PendingTypeStatOptions } from "./types";
+import { PendingTypeStatOptions } from "./types.js";
-export const findComplaintForOptions = (options: PendingTypeStatOptions | string): string | undefined => {
- if (typeof options === "string") {
- return options;
- }
+export const findComplaintForOptions = (
+ options: PendingTypeStatOptions | string,
+): string | undefined => {
+ if (typeof options === "string") {
+ return options;
+ }
- if (noFixesSpecified(options)) {
- return "No fixes or custom mutators specified. Consider enabling fixes.noImplicitAny (see http://github.com/joshuakgoldberg/typestat#cli).";
- }
+ if (noFixesSpecified(options)) {
+ return "No fixes or custom mutators specified. Consider enabling fixes.noImplicitAny (see http://github.com/joshuakgoldberg/typestat#cli).";
+ }
- if (strictNonNullAssertionsInNonStrictMode(options)) {
- return "fixes.strictNonNullAssertions specified but not strictNullChecks. Consider enabling types.strictNullChecks (see http://github.com/joshuakgoldberg/typestat/blob/main/docs/Fixes.md).";
- }
+ if (strictNonNullAssertionsInNonStrictMode(options)) {
+ return "fixes.strictNonNullAssertions specified but not strictNullChecks. Consider enabling types.strictNullChecks (see http://github.com/joshuakgoldberg/typestat/blob/main/docs/Fixes.md).";
+ }
- return undefined;
+ return undefined;
};
const noFixesSpecified = (options: PendingTypeStatOptions): boolean =>
- options.mutators.length === 0 &&
- !options.fixes.incompleteTypes &&
- !options.fixes.missingProperties &&
- !options.fixes.noImplicitAny &&
- !options.fixes.strictNonNullAssertions;
+ options.mutators.length === 0 &&
+ !options.fixes.incompleteTypes &&
+ !options.fixes.missingProperties &&
+ !options.fixes.noImplicitAny &&
+ !options.fixes.strictNonNullAssertions;
-const strictNonNullAssertionsInNonStrictMode = (options: PendingTypeStatOptions): boolean =>
- options.fixes.strictNonNullAssertions && !options.types.strictNullChecks;
+const strictNonNullAssertionsInNonStrictMode = (
+ options: PendingTypeStatOptions,
+): boolean =>
+ options.fixes.strictNonNullAssertions && !options.types.strictNullChecks;
diff --git a/src/options/parseRawCompilerOptions.ts b/src/options/parseRawCompilerOptions.ts
index 6507f9c28..dd2bc99da 100644
--- a/src/options/parseRawCompilerOptions.ts
+++ b/src/options/parseRawCompilerOptions.ts
@@ -1,44 +1,49 @@
-import minimatch from "minimatch";
import { glob } from "glob";
-import * as fs from "mz/fs";
-import * as path from "path";
-import * as ts from "typescript";
-import { stringifyDiagnosticMessageText } from "../shared/diagnostics";
+import { minimatch } from "minimatch";
+import * as fs from "node:fs";
+import * as fsp from "node:fs/promises";
+import * as path from "node:path";
+import ts from "typescript";
+
+import { stringifyDiagnosticMessageText } from "../shared/diagnostics.js";
export interface ParsedCompilerOptions extends ts.CompilerOptions {
- include?: string[];
+ include?: string[];
}
-export const parseRawCompilerOptions = async (cwd: string, projectPath: string): Promise => {
- const configRaw = (await fs.readFile(projectPath)).toString();
- const compilerOptions = ts.parseConfigFileTextToJson(projectPath, configRaw);
- if (compilerOptions.error !== undefined) {
- throw new Error(`Could not parse compiler options from '${projectPath}': ${stringifyDiagnosticMessageText(compilerOptions.error)}`);
- }
+export const parseRawCompilerOptions = async (
+ cwd: string,
+ projectPath: string,
+): Promise => {
+ const configRaw = (await fsp.readFile(projectPath)).toString();
+ const compilerOptions = ts.parseConfigFileTextToJson(projectPath, configRaw);
+ if (compilerOptions.error !== undefined) {
+ throw new Error(
+ `Could not parse compiler options from '${projectPath}': ${stringifyDiagnosticMessageText(compilerOptions.error)}`,
+ );
+ }
- const config = compilerOptions.config as ParsedCompilerOptions;
+ const config = compilerOptions.config as ParsedCompilerOptions;
- // TSConfig includes often come in a glob form like ["src"]
- if (config.include) {
- config.include = ts.parseJsonConfigFileContent(
- compilerOptions.config,
- {
- useCaseSensitiveFileNames: true,
- readDirectory: (rootDir, extensions, excludes, includes) =>
- includes
- .flatMap((include) => glob.sync(path.join(rootDir, include)))
- .filter(
- (filePath) =>
- !excludes?.some((exclude) => minimatch(filePath, exclude)) &&
- extensions.some((extension) => filePath.endsWith(extension)),
- )
- .map((filePath) => path.relative(rootDir, filePath)),
- fileExists: (filePath) => fs.statSync(filePath).isFile(),
- readFile: (filePath) => fs.readFileSync(filePath).toString(),
- },
- cwd,
- ).fileNames;
- }
+ // TSConfig includes often come in a glob form like ["src"]
+ config.include &&= ts.parseJsonConfigFileContent(
+ compilerOptions.config,
+ {
+ fileExists: (filePath) => fs.statSync(filePath).isFile(),
+ readDirectory: (rootDir, extensions, excludes, includes) =>
+ includes
+ .flatMap((include) => glob.sync(path.join(rootDir, include)))
+ .filter(
+ (filePath) =>
+ !excludes?.some((exclude) => minimatch(filePath, exclude)) &&
+ extensions.some((extension) => filePath.endsWith(extension)),
+ )
+ .map((filePath) => path.relative(rootDir, filePath)),
+ readFile: (filePath) => fs.readFileSync(filePath).toString(),
+ useCaseSensitiveFileNames: true,
+ },
+ cwd,
+ ).fileNames;
- return config;
+ return config;
};
diff --git a/src/options/parsing/collectAddedMutators.ts b/src/options/parsing/collectAddedMutators.ts
index 2e4a16244..9ad287db2 100644
--- a/src/options/parsing/collectAddedMutators.ts
+++ b/src/options/parsing/collectAddedMutators.ts
@@ -1,81 +1,104 @@
-import * as path from "path";
+import Module from "node:module";
+import * as path from "node:path";
-import { ProcessOutput } from "../../output/types";
-import { builtInFileMutators } from "../../mutators/builtIn";
-import { FileMutator } from "../../shared/fileMutator";
-import { collectOptionals } from "../../shared/arrays";
-import { getQuickErrorSummary } from "../../shared/errors";
-import { RawTypeStatOptions } from "../types";
+import { builtInFileMutators } from "../../mutators/builtIn/index.js";
+import { ProcessOutput } from "../../output/types.js";
+import { collectOptionals } from "../../shared/arrays.js";
+import { getQuickErrorSummary } from "../../shared/errors.js";
+import { FileMutator } from "../../shared/fileMutator.js";
+import { RawTypeStatOptions } from "../types.js";
+
+const require = Module.createRequire(import.meta.url);
interface ImportedFileMutator {
- fileMutator: FileMutator;
+ fileMutator: FileMutator;
}
/**
* Finds mutators to use in runtime, as either the built-in mutators or custom mutators specified by the user.
- *
* @param rawOptions Options listed as JSON in a typestat configuration file.
* @param packageDirectory Base directory to resolve paths from.
* @param output Wraps process.stderr and process.stdout.
* @returns Mutators to run with their friendly names.
*/
export const collectAddedMutators = (
- rawOptions: RawTypeStatOptions,
- packageDirectory: string,
- output: ProcessOutput,
-): ReadonlyArray<[string, FileMutator]> => {
- const addedMutators = collectOptionals(rawOptions.mutators);
- if (addedMutators.length === 0) {
- return builtInFileMutators;
- }
+ rawOptions: RawTypeStatOptions,
+ packageDirectory: string,
+ output: ProcessOutput,
+): readonly [string, FileMutator][] => {
+ const addedMutators = collectOptionals(rawOptions.mutators);
+ if (addedMutators.length === 0) {
+ return builtInFileMutators;
+ }
- const additions: [string, FileMutator][] = [];
- for (const rawAddedMutator of addedMutators) {
- try {
- const addedMutator = collectAddedMutator(packageDirectory, rawAddedMutator, output);
+ const additions: [string, FileMutator][] = [];
+ for (const rawAddedMutator of addedMutators) {
+ try {
+ const addedMutator = collectAddedMutator(
+ packageDirectory,
+ rawAddedMutator,
+ output,
+ );
- if (addedMutator !== undefined) {
- additions.push([rawAddedMutator, addedMutator]);
- }
- } catch (error) {
- output.stderr(`Could not require ${rawAddedMutator} from ${packageDirectory}.`);
- output.stderr(getQuickErrorSummary(error));
- }
- }
+ if (addedMutator !== undefined) {
+ additions.push([rawAddedMutator, addedMutator]);
+ }
+ } catch (error) {
+ output.stderr(
+ `Could not require ${rawAddedMutator} from ${packageDirectory}.`,
+ );
+ output.stderr(getQuickErrorSummary(error));
+ }
+ }
- return additions;
+ return additions;
};
-const collectAddedMutator = (packageDirectory: string, rawAddedMutator: string, output: ProcessOutput): FileMutator | undefined => {
- const requiringPath = path.join(packageDirectory, rawAddedMutator);
- const resolvedImport = tryRequireResolve(requiringPath);
- if (resolvedImport === undefined) {
- output.stderr(`Could not require ${rawAddedMutator} at ${requiringPath} from ${packageDirectory}.`);
- output.stderr("It doesn't seem to exist? :(");
- return undefined;
- }
+const collectAddedMutator = (
+ packageDirectory: string,
+ rawAddedMutator: string,
+ output: ProcessOutput,
+): FileMutator | undefined => {
+ const requiringPath = path.join(packageDirectory, rawAddedMutator);
+ const resolvedImport = tryRequireResolve(requiringPath);
+ if (resolvedImport === undefined) {
+ output.stderr(
+ `Could not require ${rawAddedMutator} at ${requiringPath} from ${packageDirectory}.`,
+ );
+ output.stderr("It doesn't seem to exist? :(");
+ return undefined;
+ }
- const result = require(requiringPath) as Partial;
+ const result = require(requiringPath) as
+ | ImportedFileMutator
+ | Record;
- if (typeof result.fileMutator !== "function") {
- output.stderr(`Could not require ${rawAddedMutator} from ${packageDirectory}.`);
+ if (typeof result.fileMutator !== "function") {
+ output.stderr(
+ `Could not require ${rawAddedMutator} from ${packageDirectory}.`,
+ );
- if (result.fileMutator === undefined) {
- output.stderr(`It doesn't have an exported .fileMutator, which must be a function.`);
- } else {
- output.stderr(`Its exported .fileMutator is ${typeof result.fileMutator} intead of function.`);
- }
+ if (result.fileMutator === undefined) {
+ output.stderr(
+ `It doesn't have an exported .fileMutator, which must be a function.`,
+ );
+ } else {
+ output.stderr(
+ `Its exported .fileMutator is ${typeof result.fileMutator} instead of function.`,
+ );
+ }
- return undefined;
- }
+ return undefined;
+ }
- return result.fileMutator;
+ return (result as ImportedFileMutator).fileMutator;
};
const tryRequireResolve = (requiringPath: string): string | undefined => {
- try {
- return require.resolve(requiringPath);
- } catch (error) {
- return undefined;
- }
+ try {
+ return require.resolve(requiringPath);
+ } catch (error) {
+ console.warn(error);
+ return undefined;
+ }
};
diff --git a/src/options/parsing/collectFileOptions.ts b/src/options/parsing/collectFileOptions.ts
index e2c18267b..4b3dae5ef 100644
--- a/src/options/parsing/collectFileOptions.ts
+++ b/src/options/parsing/collectFileOptions.ts
@@ -1,11 +1,12 @@
-import { Files, RawTypeStatOptions } from "../types";
+import { Files, RawTypeStatOptions } from "../types.js";
export const collectFileOptions = (rawOptions: RawTypeStatOptions): Files => {
- const files: Partial = rawOptions.files === undefined ? {} : { ...rawOptions.files };
+ const files: Partial =
+ rawOptions.files === undefined ? {} : { ...rawOptions.files };
- return {
- above: files.above === undefined ? "" : files.above,
- below: files.below === undefined ? "" : files.below,
- renameExtensions: files.renameExtensions === undefined ? false : files.renameExtensions,
- };
+ return {
+ above: files.above ?? "",
+ below: files.below ?? "",
+ renameExtensions: files.renameExtensions ?? false,
+ };
};
diff --git a/src/options/parsing/collectNoImplicitAny.ts b/src/options/parsing/collectNoImplicitAny.ts
index bd043ae07..2641555f7 100644
--- a/src/options/parsing/collectNoImplicitAny.ts
+++ b/src/options/parsing/collectNoImplicitAny.ts
@@ -1,15 +1,18 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { RawTypeStatOptions } from "../types";
+import { RawTypeStatOptions } from "../types.js";
-export const collectNoImplicitAny = (compilerOptions: Readonly, rawOptions: RawTypeStatOptions): boolean => {
- if (rawOptions.fixes !== undefined && rawOptions.fixes.noImplicitAny !== undefined) {
- return rawOptions.fixes.noImplicitAny;
- }
+export const collectNoImplicitAny = (
+ compilerOptions: Readonly,
+ rawOptions: RawTypeStatOptions,
+): boolean => {
+ if (rawOptions.fixes?.noImplicitAny !== undefined) {
+ return rawOptions.fixes.noImplicitAny;
+ }
- if (compilerOptions.noImplicitAny !== undefined) {
- return compilerOptions.noImplicitAny;
- }
+ if (compilerOptions.noImplicitAny !== undefined) {
+ return compilerOptions.noImplicitAny;
+ }
- return false;
+ return false;
};
diff --git a/src/options/parsing/collectNoImplicitThis.ts b/src/options/parsing/collectNoImplicitThis.ts
index b29e3047e..f4b8ae25c 100644
--- a/src/options/parsing/collectNoImplicitThis.ts
+++ b/src/options/parsing/collectNoImplicitThis.ts
@@ -1,15 +1,18 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { RawTypeStatOptions } from "../types";
+import { RawTypeStatOptions } from "../types.js";
-export const collectNoImplicitThis = (compilerOptions: Readonly, rawOptions: RawTypeStatOptions): boolean => {
- if (rawOptions.fixes !== undefined && rawOptions.fixes.noImplicitThis !== undefined) {
- return rawOptions.fixes.noImplicitThis;
- }
+export const collectNoImplicitThis = (
+ compilerOptions: Readonly,
+ rawOptions: RawTypeStatOptions,
+): boolean => {
+ if (rawOptions.fixes?.noImplicitThis !== undefined) {
+ return rawOptions.fixes.noImplicitThis;
+ }
- if (compilerOptions.noImplicitThis !== undefined) {
- return compilerOptions.noImplicitThis;
- }
+ if (compilerOptions.noImplicitThis !== undefined) {
+ return compilerOptions.noImplicitThis;
+ }
- return false;
+ return false;
};
diff --git a/src/options/parsing/collectPackageOptions.ts b/src/options/parsing/collectPackageOptions.ts
index 5e7063452..3f6e943d1 100644
--- a/src/options/parsing/collectPackageOptions.ts
+++ b/src/options/parsing/collectPackageOptions.ts
@@ -1,29 +1,35 @@
-import * as path from "path";
+import * as path from "node:path";
-import { normalizeAndSlashify } from "../../shared/paths";
-import { Package, RawTypeStatOptions } from "../types";
+import { normalizeAndSlashify } from "../../shared/paths.js";
+import { Package, RawTypeStatOptions } from "../types.js";
-export const collectPackageOptions = (cwd: string, rawOptions: RawTypeStatOptions): Package => {
- const rawPackageOptions = rawOptions.package === undefined ? {} : rawOptions.package;
- const rawPackageFile = rawPackageOptions.file;
+export const collectPackageOptions = (
+ cwd: string,
+ rawOptions: RawTypeStatOptions,
+): Package => {
+ const rawPackageOptions = rawOptions.package ?? {};
+ const rawPackageFile = rawPackageOptions.file;
- const file = collectRawPackageFile(cwd, rawPackageFile);
+ const file = collectRawPackageFile(cwd, rawPackageFile);
- return {
- directory: cwd,
- file,
- missingTypes: rawPackageOptions.missingTypes,
- };
+ return {
+ directory: cwd,
+ file,
+ missingTypes: rawPackageOptions.missingTypes,
+ };
};
-const collectRawPackageFile = (cwd: string, rawPackageFile: string | undefined) => {
- if (rawPackageFile === undefined) {
- return normalizeAndSlashify(path.join(cwd, "package.json"));
- }
+const collectRawPackageFile = (
+ cwd: string,
+ rawPackageFile: string | undefined,
+) => {
+ if (rawPackageFile === undefined) {
+ return normalizeAndSlashify(path.join(cwd, "package.json"));
+ }
- if (path.isAbsolute(rawPackageFile)) {
- return normalizeAndSlashify(rawPackageFile);
- }
+ if (path.isAbsolute(rawPackageFile)) {
+ return normalizeAndSlashify(rawPackageFile);
+ }
- return normalizeAndSlashify(path.join(cwd, rawPackageFile));
+ return normalizeAndSlashify(path.join(cwd, rawPackageFile));
};
diff --git a/src/options/parsing/collectStrictNullChecks.ts b/src/options/parsing/collectStrictNullChecks.ts
index 629fc356c..d7694e4b1 100644
--- a/src/options/parsing/collectStrictNullChecks.ts
+++ b/src/options/parsing/collectStrictNullChecks.ts
@@ -1,29 +1,35 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { RawTypeStatTypeOptions } from "../types";
+import { RawTypeStatTypeOptions } from "../types.js";
-export const collectStrictNullChecks = (compilerOptions: Readonly, rawOptionTypes: RawTypeStatTypeOptions) => {
- const typeStrictNullChecks = rawOptionTypes.strictNullChecks;
- const compilerStrictNullChecks = collectCompilerStrictNullChecks(compilerOptions, typeStrictNullChecks);
+export const collectStrictNullChecks = (
+ compilerOptions: Readonly,
+ rawOptionTypes: RawTypeStatTypeOptions,
+) => {
+ const typeStrictNullChecks = rawOptionTypes.strictNullChecks;
+ const compilerStrictNullChecks = collectCompilerStrictNullChecks(
+ compilerOptions,
+ typeStrictNullChecks,
+ );
- return { compilerStrictNullChecks, typeStrictNullChecks };
+ return { compilerStrictNullChecks, typeStrictNullChecks };
};
const collectCompilerStrictNullChecks = (
- compilerOptions: Readonly,
- typeStrictNullChecks: boolean | undefined,
+ compilerOptions: Readonly,
+ typeStrictNullChecks: boolean | undefined,
): boolean => {
- if (typeStrictNullChecks !== undefined) {
- return typeStrictNullChecks;
- }
+ if (typeStrictNullChecks !== undefined) {
+ return typeStrictNullChecks;
+ }
- if (compilerOptions.strictNullChecks !== undefined) {
- return compilerOptions.strictNullChecks;
- }
+ if (compilerOptions.strictNullChecks !== undefined) {
+ return compilerOptions.strictNullChecks;
+ }
- if (compilerOptions.strict !== undefined) {
- return compilerOptions.strict;
- }
+ if (compilerOptions.strict !== undefined) {
+ return compilerOptions.strict;
+ }
- return false;
+ return false;
};
diff --git a/src/options/types.ts b/src/options/types.ts
index 811a2871a..9fdf22926 100644
--- a/src/options/types.ts
+++ b/src/options/types.ts
@@ -1,313 +1,311 @@
-import * as ts from "typescript";
+import ts from "typescript";
-import { FileMutator } from "../shared/fileMutator";
-import { ProcessOutput } from "../output/types";
-import { ReactPropTypesHint, ReactPropTypesOptionality } from "./enums";
+import { ProcessOutput } from "../output/types.js";
+import { FileMutator } from "../shared/fileMutator.js";
+import { ReactPropTypesHint, ReactPropTypesOptionality } from "./enums.js";
/**
* Options listed as JSON in a typestat configuration file.
- *
- * @remarks These are read from disk and parsed into {@link PendingTypeStatOptions}.
+ * These are read from disk and parsed into {@link PendingTypeStatOptions}.
*/
export interface RawTypeStatOptions {
- /**
- * Directives for file-level changes.
- */
- readonly files?: Readonly>;
-
- /**
- * Any tsquery filters to exclude within files.
- */
- readonly filters?: readonly string[];
-
- /**
- * Which fixes (type mutations) are enabled.
- */
- readonly fixes?: Partial;
-
- /**
- * Behavior requests around how to infer types.
- */
- readonly hints?: Partial;
-
- /**
- * Globs of files to run on, if not everything in the TypeScript project.
- */
- readonly include?: readonly string[];
-
- /**
- * Any user-defined mutators to apply after the built-in mutators.
- */
- readonly mutators?: readonly string[];
-
- /**
- * Directives for project-level changes.
- */
- readonly package?: Readonly>;
-
- /**
- * Hooks to run after mutations are complete.
- */
- readonly postProcess?: Readonly>;
-
- /**
- * Path to a TypeScript configuration file, if not "tsconfig.json".
- */
- readonly projectPath?: string;
-
- /**
- * Which post-run cleanups are enabled.
- */
- readonly cleanups?: Partial;
-
- /**
- * Options for which types to add under what aliases.
- */
- readonly types?: RawTypeStatTypeOptions;
+ /**
+ * Which post-run cleanups are enabled.
+ */
+ readonly cleanups?: Partial;
+
+ /**
+ * Directives for file-level changes.
+ */
+ readonly files?: Readonly>;
+
+ /**
+ * Any tsquery filters to exclude within files.
+ */
+ readonly filters?: readonly string[];
+
+ /**
+ * Which fixes (type mutations) are enabled.
+ */
+ readonly fixes?: Partial;
+
+ /**
+ * Behavior requests around how to infer types.
+ */
+ readonly hints?: Partial;
+
+ /**
+ * Globs of files to run on, if not everything in the TypeScript project.
+ */
+ readonly include?: readonly string[];
+
+ /**
+ * Any user-defined mutators to apply after the built-in mutators.
+ */
+ readonly mutators?: readonly string[];
+
+ /**
+ * Directives for project-level changes.
+ */
+ readonly package?: Readonly>;
+
+ /**
+ * Hooks to run after mutations are complete.
+ */
+ readonly postProcess?: Readonly>;
+
+ /**
+ * Path to a TypeScript configuration file, if not "tsconfig.json".
+ */
+ readonly projectPath?: string;
+
+ /**
+ * Options for which types to add under what aliases.
+ */
+ readonly types?: RawTypeStatTypeOptions;
}
/**
* Options for which types to add under what aliases.
*/
export interface RawTypeStatTypeOptions {
- /**
- * Whether to add `null` and `undefined` as per TypeScript's --strictNullChecks.
- */
- strictNullChecks?: boolean;
+ /**
+ * Whether to add `null` and `undefined` as per TypeScript's --strictNullChecks.
+ */
+ strictNullChecks?: boolean;
}
/**
* Common parsed runtime options for TypeStat.
*/
export interface BaseTypeStatOptions {
- /**
- * Parsed TypeScript compiler options with relevant fields filled out.
- */
- readonly compilerOptions: Readonly;
-
- /**
- * Directives for file-level changes.
- */
- readonly files: Readonly;
-
- /**
- * Any tsquery filters to exclude within files.
- */
- readonly filters?: readonly string[];
-
- /**
- * Whether each fix (type mutation) is enabled.
- */
- readonly fixes: Readonly;
-
- /**
- * Behavior requests around how to infer types.
- */
- readonly hints: RuntimeHints;
-
- /**
- * Mutators to run, as either the built-in mutators or custom mutators specified by the user.
- */
- readonly mutators: readonly [string, FileMutator][];
-
- /**
- * Wraps process and logfile output.
- */
- readonly output: ProcessOutput;
-
- /**
- * Directives for project-level changes.
- */
- readonly package: Readonly;
-
- /**
- * Hooks to run after mutations are complete.
- */
- readonly postProcess: Readonly;
-
- /**
- * Path to a tsconfig.json file.
- */
- readonly projectPath: string;
-
- /**
- * Whether each post-run cleanup is enabled.
- */
- readonly cleanups: Readonly;
-
- /**
- * Options for which types to add under what aliases.
- */
- readonly types: TypeStatTypeOptions;
+ /**
+ * Whether each post-run cleanup is enabled.
+ */
+ readonly cleanups: Readonly;
+
+ /**
+ * Parsed TypeScript compiler options with relevant fields filled out.
+ */
+ readonly compilerOptions: Readonly;
+
+ /**
+ * Directives for file-level changes.
+ */
+ readonly files: Readonly;
+
+ /**
+ * Any tsquery filters to exclude within files.
+ */
+ readonly filters?: readonly string[];
+
+ /**
+ * Whether each fix (type mutation) is enabled.
+ */
+ readonly fixes: Readonly