@utoo/lint 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -175
- package/bin/migrate.js +84 -34
- package/configs/frontend.json +1 -1
- package/index.cjs +19 -1
- package/index.js +19 -1
- package/package.json +11 -11
- package/schema.json +50 -37
package/README.md
CHANGED
|
@@ -2,252 +2,226 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@utoo/lint)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://github.com/utooland/utoo-lint/actions/workflows/ci.yml)
|
|
8
|
+
[](https://github.com/utooland/utoo-lint/blob/main/LICENSE)
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
A high-performance linter for JavaScript and TypeScript, written in Zig and
|
|
11
|
+
powered by [Yuku](https://github.com/yuku-toolchain/yuku).
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```
|
|
13
|
+
`@utoo/lint` combines a native lint engine with familiar configuration, CLI,
|
|
14
|
+
and JavaScript APIs.
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
[Installation](#installation) · [Quick start](#quick-start) ·
|
|
17
|
+
[Rules](https://github.com/utooland/utoo-lint/blob/main/docs/rule-status.md) ·
|
|
18
|
+
[Configuration](https://github.com/utooland/utoo-lint/blob/main/docs/configuration.md) ·
|
|
19
|
+
[GitHub](https://github.com/utooland/utoo-lint)
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
## Why utoo-lint?
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
- **Native performance** — Zig and Yuku power parsing, semantic analysis, and
|
|
24
|
+
parallel file linting.
|
|
25
|
+
- **Broad rule coverage** — More than 300 rules cover JavaScript, TypeScript,
|
|
26
|
+
React, JSX accessibility, and imports.
|
|
27
|
+
- **Familiar configuration** — Use typed `utlint.config.ts` or static
|
|
28
|
+
`utlint.config.json`, with ESLint-style rule names and severities.
|
|
29
|
+
- **Practical workflows** — Safe autofix, suppression comments, JSON output,
|
|
30
|
+
and ESM/CommonJS APIs are included.
|
|
31
|
+
- **Portable installation** — Prebuilt binaries are available for macOS,
|
|
32
|
+
Linux, and Windows on supported architectures.
|
|
20
33
|
|
|
21
|
-
|
|
22
|
-
`utlint.config.ts` or `utlint.config.json`. When no config file or `files` entry
|
|
23
|
-
exists, it scans the current directory. It skips `.git`, `.zig-cache`,
|
|
24
|
-
`node_modules`, `vendor`, and `zig-out`.
|
|
34
|
+
## Installation
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
`@utoo/lint` requires Node.js 20 or later.
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
pnpm exec utoo-lint --config=utlint.config.json src
|
|
30
|
-
```
|
|
38
|
+
### utoo
|
|
31
39
|
|
|
32
|
-
|
|
40
|
+
[utoo](https://utoo.land/en/docs/utoo) is a fast, npm-compatible package
|
|
41
|
+
manager written in Rust. Install it once if it is not already available:
|
|
33
42
|
|
|
34
43
|
```bash
|
|
35
|
-
|
|
44
|
+
npm install -g utoo
|
|
36
45
|
```
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
Add `@utoo/lint` as a development dependency:
|
|
39
48
|
|
|
40
49
|
```bash
|
|
41
|
-
|
|
50
|
+
ut install @utoo/lint -D
|
|
42
51
|
```
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
automatically; pass `--color` to force it or `--no-color` to disable it. JSON
|
|
47
|
-
output remains stable for editor and CI integrations.
|
|
48
|
-
|
|
49
|
-
## Autofix
|
|
50
|
-
|
|
51
|
-
Apply safe fixes from all enabled rules that support autofix:
|
|
53
|
+
In an existing project, run `ut install` without a package name to install all
|
|
54
|
+
dependencies declared in `package.json`.
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
pnpm exec utoo-lint --fix src
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Preview the result without changing files:
|
|
56
|
+
### Other package managers
|
|
58
57
|
|
|
59
58
|
```bash
|
|
60
|
-
pnpm
|
|
59
|
+
pnpm add -D @utoo/lint
|
|
60
|
+
npm install --save-dev @utoo/lint
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
until the source is stable, subject to a safety pass limit. Diagnostics remain
|
|
66
|
-
when a rule or a particular code shape cannot be fixed safely. The current
|
|
67
|
-
[rule status](https://github.com/fireairforce/utoo-lint/blob/main/docs/rule-status.md)
|
|
68
|
-
lists autofix coverage by rule.
|
|
63
|
+
The package selects the native binary for the current platform. No Zig
|
|
64
|
+
toolchain is required.
|
|
69
65
|
|
|
70
|
-
##
|
|
66
|
+
## Quick start
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
### Run with the default rules
|
|
73
69
|
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
debugger;
|
|
70
|
+
```bash
|
|
71
|
+
utx @utoo/lint src
|
|
77
72
|
```
|
|
78
73
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`utlint-ignore-start` and `utlint-ignore-end` comments for a range. Line and
|
|
82
|
-
block comments are supported. Parse errors remain visible, and fixes from
|
|
83
|
-
suppressed diagnostics are not applied.
|
|
74
|
+
Without a config file, `utoo-lint` uses its built-in default rules. It supports
|
|
75
|
+
`.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, and `.cts` files.
|
|
84
76
|
|
|
85
|
-
|
|
86
|
-
compatibility API exposes them in `suppressedMessages`.
|
|
77
|
+
### Add a typed config
|
|
87
78
|
|
|
88
|
-
|
|
79
|
+
Create `utlint.config.ts`:
|
|
89
80
|
|
|
90
|
-
|
|
81
|
+
```ts
|
|
82
|
+
import { defineConfig, globalIgnores } from "@utoo/lint/config";
|
|
83
|
+
import frontend from "@utoo/lint/configs/frontend";
|
|
91
84
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
export default defineConfig(
|
|
86
|
+
globalIgnores(["dist/", "coverage/"]),
|
|
87
|
+
{
|
|
88
|
+
...frontend,
|
|
89
|
+
files: ["src/**/*.{js,jsx,ts,tsx}"],
|
|
90
|
+
rules: {
|
|
91
|
+
...frontend.rules,
|
|
92
|
+
"no-console": "warn"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
```
|
|
96
97
|
|
|
97
|
-
The
|
|
98
|
-
explicitly:
|
|
98
|
+
The CLI discovers the config and uses its `files` patterns:
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
|
|
102
|
-
pnpm exec utoo-lint --config=utlint.config.json src
|
|
101
|
+
utx @utoo/lint
|
|
103
102
|
```
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
See the
|
|
105
|
+
[configuration guide](https://github.com/utooland/utoo-lint/blob/main/docs/configuration.md)
|
|
106
|
+
for flat config arrays, global ignores, rule options, and config precedence.
|
|
107
|
+
|
|
108
|
+
### Add package scripts
|
|
107
109
|
|
|
108
110
|
```json
|
|
109
111
|
{
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"rules": {
|
|
114
|
-
"no-console": "off",
|
|
115
|
-
"no-debugger": "error"
|
|
112
|
+
"scripts": {
|
|
113
|
+
"lint": "utoo-lint src",
|
|
114
|
+
"lint:fix": "utoo-lint --fix src"
|
|
116
115
|
}
|
|
117
116
|
}
|
|
118
117
|
```
|
|
119
118
|
|
|
120
|
-
|
|
119
|
+
With utoo, run these scripts as `ut lint` and `ut lint:fix`.
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
import { defineConfig } from "@utoo/lint/config";
|
|
124
|
-
|
|
125
|
-
export default defineConfig({
|
|
126
|
-
files: ["src/**/*.{js,jsx,ts,tsx}"],
|
|
127
|
-
ignores: ["dist", "node_modules"],
|
|
128
|
-
rules: {
|
|
129
|
-
"no-console": "off",
|
|
130
|
-
"no-debugger": "error"
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
```
|
|
121
|
+
## Common commands
|
|
134
122
|
|
|
135
|
-
|
|
123
|
+
| Task | Command |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| Lint files | `utx @utoo/lint src` |
|
|
126
|
+
| Apply safe fixes | `utx @utoo/lint --fix src` |
|
|
127
|
+
| Preview fixes as JSON | `utx @utoo/lint --fix-dry-run --format=json src` |
|
|
128
|
+
| Select rules for one run | `utx @utoo/lint --rules=no-debugger,no-unused-vars src` |
|
|
129
|
+
| Use an explicit config | `utx @utoo/lint --config=utlint.config.json src` |
|
|
136
130
|
|
|
137
|
-
|
|
138
|
-
import { defineConfig } from "@utoo/lint/config";
|
|
139
|
-
import frontend from "@utoo/lint/configs/frontend";
|
|
131
|
+
Run `utx @utoo/lint --help` for all CLI options.
|
|
140
132
|
|
|
141
|
-
|
|
142
|
-
...frontend,
|
|
143
|
-
rules: {
|
|
144
|
-
...frontend.rules,
|
|
145
|
-
"no-console": "off",
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
```
|
|
133
|
+
## Configuration
|
|
149
134
|
|
|
150
|
-
|
|
151
|
-
|
|
135
|
+
`utoo-lint` supports two canonical config formats. They are alternative
|
|
136
|
+
representations of one active config and are not merged together.
|
|
152
137
|
|
|
153
|
-
|
|
154
|
-
|
|
138
|
+
| Config | Best for | Raw native binary |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| `utlint.config.ts` | Typed authoring, imports, presets, and computed values | No |
|
|
141
|
+
| `utlint.config.json` | Static configuration and JSON Schema validation | Yes |
|
|
155
142
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
143
|
+
Rule severities follow ESLint conventions: `off`, `warn`, `error`, `0`, `1`,
|
|
144
|
+
and `2`. A selected config enables only the rules present in its resolved
|
|
145
|
+
`rules` map.
|
|
146
|
+
|
|
147
|
+
The npm CLI and JavaScript API load both formats. The raw native binary loads
|
|
148
|
+
JSON only. See the
|
|
149
|
+
[configuration guide](https://github.com/utooland/utoo-lint/blob/main/docs/configuration.md)
|
|
150
|
+
for the complete behavior.
|
|
151
|
+
|
|
152
|
+
## Autofix
|
|
153
|
+
|
|
154
|
+
Apply safe fixes in place:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
utx @utoo/lint --fix src
|
|
165
158
|
```
|
|
166
159
|
|
|
167
|
-
|
|
168
|
-
generated `name`. Only such global entries prune directories during target
|
|
169
|
-
discovery. By contrast, `ignores` beside `files`, `rules`, or another config
|
|
170
|
-
key is entry-scoped: it prevents that entry from applying to matching files,
|
|
171
|
-
but does not exclude them from other entries. With no CLI targets, global
|
|
172
|
-
ignores filter the config's `files` patterns, or the current-directory scan
|
|
173
|
-
when no `files` are configured. Directory patterns such as `dist/` and
|
|
174
|
-
`.next/` are relative to the config; use `**/generated/` to match at any depth.
|
|
175
|
-
This intentionally follows [ESLint flat config ignore semantics](https://eslint.org/docs/latest/use/configure/ignore).
|
|
176
|
-
|
|
177
|
-
The two canonical names represent one active config and are not implicitly
|
|
178
|
-
merged. For the npm/Node entry point, discovery is nearest-directory-first.
|
|
179
|
-
Within the same directory, `utlint.config.ts` takes precedence over
|
|
180
|
-
`utlint.config.json`; deprecated `utoo.json` and `utoo-lint.json` files are
|
|
181
|
-
checked afterward for temporary backward compatibility. Rule-related CLI
|
|
182
|
-
options such as `--rules`, individual rule toggles, and fishlint's `--rule` are
|
|
183
|
-
applied after the selected config.
|
|
184
|
-
|
|
185
|
-
Project-config `files` and `ignores` patterns are relative to the selected
|
|
186
|
-
config file's directory. In a flat config array, they select the entries that
|
|
187
|
-
apply to each file; matching entries are combined in order and later rule
|
|
188
|
-
values override earlier values. The npm CLI, JavaScript API, and fishlint
|
|
189
|
-
compatibility command perform this rule resolution per file.
|
|
190
|
-
|
|
191
|
-
TypeScript config is trusted executable code. Its default export must be a
|
|
192
|
-
JSON-serializable object or flat config array. The npm wrapper executes it and
|
|
193
|
-
materializes the result as JSON before invoking the native binary. The raw
|
|
194
|
-
binary does not execute or discover TypeScript; it searches for
|
|
195
|
-
`utlint.config.json` and then the legacy JSON names. Direct native use therefore
|
|
196
|
-
requires a JSON config. The raw binary applies only its `rules`;
|
|
197
|
-
config-driven `files` and `ignores` filtering and default target selection are
|
|
198
|
-
npm/Node wrapper features. Pass lint targets explicitly when invoking the raw
|
|
199
|
-
binary. As in ESLint, selecting a config disables rules not present in its
|
|
200
|
-
resolved `rules` map. When no config is selected, utoo-lint uses its built-in
|
|
201
|
-
default rules.
|
|
202
|
-
|
|
203
|
-
Rule severities use ESLint's exit behavior: warnings are reported with exit
|
|
204
|
-
status 0, while errors return exit status 1. Use fishlint's `--max-warnings`
|
|
205
|
-
option when warnings should fail CI.
|
|
206
|
-
|
|
207
|
-
Start from the packaged frontend template:
|
|
160
|
+
Preview fixes without writing files:
|
|
208
161
|
|
|
209
162
|
```bash
|
|
210
|
-
|
|
163
|
+
utx @utoo/lint --fix-dry-run --format=json src
|
|
211
164
|
```
|
|
212
165
|
|
|
213
|
-
|
|
166
|
+
Fixes run until the source is stable, subject to a safety pass limit. The
|
|
167
|
+
[rule status](https://github.com/utooland/utoo-lint/blob/main/docs/rule-status.md)
|
|
168
|
+
documents autofix support for each rule.
|
|
214
169
|
|
|
215
|
-
|
|
170
|
+
## Suppression comments
|
|
216
171
|
|
|
217
|
-
|
|
218
|
-
|
|
172
|
+
Use suppression comments for intentional exceptions without disabling a rule
|
|
173
|
+
in project configuration:
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
// utlint-ignore no-debugger: generated breakpoint
|
|
177
|
+
debugger;
|
|
219
178
|
```
|
|
220
179
|
|
|
221
|
-
|
|
180
|
+
| Directive | Scope |
|
|
181
|
+
| --- | --- |
|
|
182
|
+
| `utlint-ignore [rule]` | The next line of code |
|
|
183
|
+
| `utlint-ignore-all [rule]` | The entire file when placed before any code |
|
|
184
|
+
| `utlint-ignore-start [rule]` | The start of a suppressed range |
|
|
185
|
+
| `utlint-ignore-end [rule]` | The end of a suppressed range |
|
|
186
|
+
|
|
187
|
+
A directive may target one rule ID. Omitting it creates or closes an all-rules
|
|
188
|
+
suppression. Parse errors are never suppressed, and suppressed fixes are not
|
|
189
|
+
applied.
|
|
190
|
+
|
|
191
|
+
See the
|
|
192
|
+
[suppression comments guide](https://github.com/utooland/utoo-lint/blob/main/docs/suppressions.md)
|
|
193
|
+
for range examples and API behavior.
|
|
194
|
+
|
|
195
|
+
## Migrating from ESLint
|
|
196
|
+
|
|
197
|
+
Convert an existing ESLint config into a native utoo-lint config:
|
|
222
198
|
|
|
223
199
|
```bash
|
|
224
|
-
|
|
225
|
-
|
|
200
|
+
utx @utoo/lint migrate eslint \
|
|
201
|
+
--from eslint.config.js \
|
|
202
|
+
--output utlint.config.json
|
|
226
203
|
```
|
|
227
204
|
|
|
205
|
+
The package also exposes `eslint` and `fishlint` compatibility commands for
|
|
206
|
+
incremental replacement workflows. See the
|
|
207
|
+
[migration guide](https://github.com/utooland/utoo-lint/blob/main/docs/eslint-migration.md)
|
|
208
|
+
for supported mappings and known differences.
|
|
209
|
+
|
|
228
210
|
## JavaScript API
|
|
229
211
|
|
|
212
|
+
The package provides ESM and CommonJS entry points:
|
|
213
|
+
|
|
230
214
|
```js
|
|
231
215
|
import { lintFiles } from "@utoo/lint";
|
|
232
216
|
|
|
233
217
|
const report = lintFiles(["src"], {
|
|
234
|
-
config: "utlint.config.
|
|
235
|
-
rules: ["no-debugger"]
|
|
218
|
+
config: "utlint.config.ts"
|
|
236
219
|
});
|
|
237
220
|
|
|
238
221
|
console.log(report.diagnostics);
|
|
239
222
|
```
|
|
240
223
|
|
|
241
|
-
|
|
242
|
-
as the CLI, so migration scripts usually do not need to expand config `files`
|
|
243
|
-
manually.
|
|
244
|
-
|
|
245
|
-
CommonJS is supported through `require("@utoo/lint")`.
|
|
246
|
-
|
|
247
|
-
Set `fix: true` to compute fixed output through the JavaScript API. Raw
|
|
248
|
-
`lintFiles()` and `lintText()` reports expose changed sources in `outputs`
|
|
249
|
-
without writing them. The ESLint-compatible API follows the usual two-step
|
|
250
|
-
flow:
|
|
224
|
+
An ESLint-style API is also available:
|
|
251
225
|
|
|
252
226
|
```js
|
|
253
227
|
import { ESLint } from "@utoo/lint";
|
|
@@ -257,8 +231,33 @@ const results = await eslint.lintFiles(["src"]);
|
|
|
257
231
|
await ESLint.outputFixes(results);
|
|
258
232
|
```
|
|
259
233
|
|
|
260
|
-
|
|
234
|
+
Raw reports include active diagnostics, suppressed diagnostics, fixed outputs,
|
|
235
|
+
and an exit code. The compatibility layer also exports `Linter`, `CLIEngine`,
|
|
236
|
+
`RuleTester`, and `SourceCode` APIs.
|
|
237
|
+
|
|
238
|
+
## Supported platforms
|
|
239
|
+
|
|
240
|
+
The package installs a platform-specific optional dependency containing the
|
|
241
|
+
native binary.
|
|
242
|
+
|
|
243
|
+
| Operating system | Architectures |
|
|
244
|
+
| --- | --- |
|
|
245
|
+
| macOS | arm64, x64 |
|
|
246
|
+
| Linux | arm64, x64 |
|
|
247
|
+
| Windows | x64 |
|
|
248
|
+
|
|
249
|
+
Set `UTOO_LINT_BIN=/path/to/utoo-lint` to use a custom binary during local
|
|
250
|
+
development.
|
|
251
|
+
|
|
252
|
+
## Documentation
|
|
253
|
+
|
|
254
|
+
- [Rule status](https://github.com/utooland/utoo-lint/blob/main/docs/rule-status.md)
|
|
255
|
+
- [Configuration](https://github.com/utooland/utoo-lint/blob/main/docs/configuration.md)
|
|
256
|
+
- [Suppression comments](https://github.com/utooland/utoo-lint/blob/main/docs/suppressions.md)
|
|
257
|
+
- [Migrating from ESLint](https://github.com/utooland/utoo-lint/blob/main/docs/eslint-migration.md)
|
|
258
|
+
- [Benchmarks](https://github.com/utooland/utoo-lint/tree/main/benchmarks)
|
|
259
|
+
- [Security policy](https://github.com/utooland/utoo-lint/blob/main/SECURITY.md)
|
|
260
|
+
|
|
261
|
+
## License
|
|
261
262
|
|
|
262
|
-
|
|
263
|
-
native `utoo-lint` binary. Set `UTOO_LINT_BIN=/path/to/utoo-lint` to force a
|
|
264
|
-
specific binary during local development.
|
|
263
|
+
[MIT](https://github.com/utooland/utoo-lint/blob/main/LICENSE)
|
package/bin/migrate.js
CHANGED
|
@@ -16,7 +16,14 @@ const JAVASCRIPT_CONFIG_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
|
|
|
16
16
|
const IGNORED_RULES = new Map([
|
|
17
17
|
["prettier/prettier", "formatting is outside utoo-lint"]
|
|
18
18
|
]);
|
|
19
|
-
const
|
|
19
|
+
const RULE_ALIASES = new Map([
|
|
20
|
+
["@eslint-react/no-array-index-key", "react/no-array-index-key"],
|
|
21
|
+
["@eslint-react/dom-no-find-dom-node", "react/no-find-dom-node"],
|
|
22
|
+
["@eslint-react/dom-no-render-return-value", "react/no-render-return-value"],
|
|
23
|
+
["@eslint-react/dom-no-void-elements-with-children", "react/void-dom-elements-no-children"],
|
|
24
|
+
["@eslint-react/rules-of-hooks", "react-hooks/rules-of-hooks"]
|
|
25
|
+
]);
|
|
26
|
+
const SCHEMA_URL = "https://raw.githubusercontent.com/utooland/utoo-lint/main/npm/utoo-lint/schema.json";
|
|
20
27
|
const JAVASCRIPT_CONFIG_LOADER_SCRIPT = `
|
|
21
28
|
import { writeFileSync } from "node:fs";
|
|
22
29
|
import { pathToFileURL } from "node:url";
|
|
@@ -178,43 +185,41 @@ function migrateEslintConfig(options) {
|
|
|
178
185
|
const eslintConfig = loadEslintConfig(sourcePath, options.cwd);
|
|
179
186
|
const supportedRuleIds = new Set(new Linter().getRules().keys());
|
|
180
187
|
const entries = normalizeConfigEntries(eslintConfig);
|
|
181
|
-
const
|
|
182
|
-
const files = new Set();
|
|
183
|
-
const ignores = new Set();
|
|
188
|
+
const migratedEntries = [];
|
|
184
189
|
const supportedRules = [];
|
|
185
190
|
const unsupportedRules = [];
|
|
186
191
|
const ignoredRules = [];
|
|
192
|
+
const translatedRules = [];
|
|
187
193
|
|
|
188
194
|
for (const entry of entries) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
const rules = {};
|
|
196
|
+
if (entry.rules && typeof entry.rules === "object") {
|
|
197
|
+
for (const [ruleId, ruleConfig] of Object.entries(entry.rules)) {
|
|
198
|
+
const migratedRuleId = RULE_ALIASES.get(ruleId) ?? ruleId;
|
|
199
|
+
if (IGNORED_RULES.has(ruleId)) {
|
|
200
|
+
ignoredRules.push({ ruleId, reason: IGNORED_RULES.get(ruleId) });
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (!supportedRuleIds.has(migratedRuleId)) {
|
|
204
|
+
if (isRuleDisabled(ruleConfig)) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
unsupportedRules.push(ruleId);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
rules[migratedRuleId] = migratableRuleConfig(ruleConfig);
|
|
211
|
+
supportedRules.push(migratedRuleId);
|
|
212
|
+
if (migratedRuleId !== ruleId) {
|
|
213
|
+
translatedRules.push({ sourceRuleId: ruleId, targetRuleId: migratedRuleId });
|
|
214
|
+
}
|
|
198
215
|
}
|
|
199
|
-
if (!supportedRuleIds.has(ruleId)) {
|
|
200
|
-
unsupportedRules.push(ruleId);
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
rules[ruleId] = migratableRuleConfig(ruleConfig);
|
|
204
|
-
supportedRules.push(ruleId);
|
|
205
216
|
}
|
|
217
|
+
migratedEntries.push(migratableConfigEntry(entry, rules));
|
|
206
218
|
}
|
|
207
219
|
|
|
208
|
-
const config =
|
|
209
|
-
$schema: SCHEMA_URL
|
|
210
|
-
|
|
211
|
-
if (files.size > 0) {
|
|
212
|
-
config.files = [...files];
|
|
213
|
-
}
|
|
214
|
-
if (ignores.size > 0) {
|
|
215
|
-
config.ignores = [...ignores];
|
|
216
|
-
}
|
|
217
|
-
config.rules = sortObjectByKey(rules);
|
|
220
|
+
const config = Array.isArray(eslintConfig)
|
|
221
|
+
? [{ $schema: SCHEMA_URL }, ...migratedEntries]
|
|
222
|
+
: { $schema: SCHEMA_URL, ...(migratedEntries[0] ?? { rules: {} }) };
|
|
218
223
|
|
|
219
224
|
return {
|
|
220
225
|
config,
|
|
@@ -224,6 +229,7 @@ function migrateEslintConfig(options) {
|
|
|
224
229
|
supportedRules: uniqueSorted(supportedRules),
|
|
225
230
|
unsupportedRules: uniqueSorted(unsupportedRules),
|
|
226
231
|
ignoredRules: uniqueByRuleId(ignoredRules),
|
|
232
|
+
translatedRules: uniqueTranslatedRules(translatedRules),
|
|
227
233
|
optionDroppedRules: []
|
|
228
234
|
}
|
|
229
235
|
};
|
|
@@ -282,21 +288,54 @@ function normalizeConfigEntries(config) {
|
|
|
282
288
|
return [];
|
|
283
289
|
}
|
|
284
290
|
|
|
285
|
-
function
|
|
286
|
-
|
|
287
|
-
|
|
291
|
+
function migratableConfigEntry(entry, rules) {
|
|
292
|
+
const migrated = {};
|
|
293
|
+
if (typeof entry.name === "string") {
|
|
294
|
+
migrated.name = entry.name;
|
|
295
|
+
}
|
|
296
|
+
const files = migratablePatterns(entry.files);
|
|
297
|
+
if (files.length > 0) {
|
|
298
|
+
migrated.files = files;
|
|
299
|
+
}
|
|
300
|
+
const ignores = migratablePatterns(entry.ignores);
|
|
301
|
+
if (ignores.length > 0) {
|
|
302
|
+
migrated.ignores = ignores;
|
|
288
303
|
}
|
|
304
|
+
if (!isGlobalIgnoreEntry(entry)) {
|
|
305
|
+
migrated.rules = sortObjectByKey(rules);
|
|
306
|
+
}
|
|
307
|
+
return migrated;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function migratablePatterns(value) {
|
|
311
|
+
const patterns = [];
|
|
312
|
+
collectMigratablePatterns(value, patterns);
|
|
313
|
+
return [...new Set(patterns)];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function collectMigratablePatterns(value, patterns) {
|
|
289
317
|
for (const pattern of Array.isArray(value) ? value : [value]) {
|
|
290
|
-
if (
|
|
291
|
-
|
|
318
|
+
if (Array.isArray(pattern)) {
|
|
319
|
+
collectMigratablePatterns(pattern, patterns);
|
|
320
|
+
} else if (typeof pattern === "string") {
|
|
321
|
+
patterns.push(pattern);
|
|
292
322
|
}
|
|
293
323
|
}
|
|
294
324
|
}
|
|
295
325
|
|
|
326
|
+
function isGlobalIgnoreEntry(entry) {
|
|
327
|
+
return Boolean(entry.ignores) && Object.keys(entry).every((key) => key === "name" || key === "ignores");
|
|
328
|
+
}
|
|
329
|
+
|
|
296
330
|
function migratableRuleConfig(ruleConfig) {
|
|
297
331
|
return Array.isArray(ruleConfig) ? [...ruleConfig] : ruleConfig;
|
|
298
332
|
}
|
|
299
333
|
|
|
334
|
+
function isRuleDisabled(ruleConfig) {
|
|
335
|
+
const severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
336
|
+
return severity === "off" || severity === 0 || severity === false;
|
|
337
|
+
}
|
|
338
|
+
|
|
300
339
|
function sortObjectByKey(object) {
|
|
301
340
|
return Object.fromEntries(Object.entries(object).sort(([left], [right]) => left.localeCompare(right)));
|
|
302
341
|
}
|
|
@@ -313,6 +352,14 @@ function uniqueByRuleId(values) {
|
|
|
313
352
|
return [...result.values()].sort((left, right) => left.ruleId.localeCompare(right.ruleId));
|
|
314
353
|
}
|
|
315
354
|
|
|
355
|
+
function uniqueTranslatedRules(values) {
|
|
356
|
+
const result = new Map();
|
|
357
|
+
for (const value of values) {
|
|
358
|
+
result.set(value.sourceRuleId, value);
|
|
359
|
+
}
|
|
360
|
+
return [...result.values()].sort((left, right) => left.sourceRuleId.localeCompare(right.sourceRuleId));
|
|
361
|
+
}
|
|
362
|
+
|
|
316
363
|
function writeReport(report, options, stream) {
|
|
317
364
|
if (options.report === "json") {
|
|
318
365
|
stream.write(JSON.stringify(report, null, 2) + "\n");
|
|
@@ -324,6 +371,9 @@ function writeReport(report, options, stream) {
|
|
|
324
371
|
stream.write(`utoo-lint migrate eslint: wrote ${report.output}\n`);
|
|
325
372
|
}
|
|
326
373
|
stream.write(`utoo-lint migrate eslint: migrated ${report.supportedRules.length} supported rule(s)\n`);
|
|
374
|
+
if (report.translatedRules.length > 0) {
|
|
375
|
+
stream.write(`utoo-lint migrate eslint: translated ${report.translatedRules.length} rule alias(es): ${report.translatedRules.map((rule) => `${rule.sourceRuleId} -> ${rule.targetRuleId}`).join(", ")}\n`);
|
|
376
|
+
}
|
|
327
377
|
if (report.ignoredRules.length > 0) {
|
|
328
378
|
stream.write(`utoo-lint migrate eslint: ignored ${report.ignoredRules.length} rule(s): ${report.ignoredRules.map((rule) => rule.ruleId).join(", ")}\n`);
|
|
329
379
|
}
|
package/configs/frontend.json
CHANGED
package/index.cjs
CHANGED
|
@@ -305,6 +305,11 @@ const BUILTIN_RULE_IDS = [
|
|
|
305
305
|
"import/no-named-as-default-member",
|
|
306
306
|
"import/no-unresolved",
|
|
307
307
|
"import/no-self-import",
|
|
308
|
+
"promise/no-promise-in-callback",
|
|
309
|
+
"promise/no-return-in-finally",
|
|
310
|
+
"promise/no-return-wrap",
|
|
311
|
+
"promise/param-names",
|
|
312
|
+
"promise/valid-params",
|
|
308
313
|
"jsx-a11y/alt-text",
|
|
309
314
|
"jsx-a11y/anchor-has-content",
|
|
310
315
|
"jsx-a11y/aria-props",
|
|
@@ -318,6 +323,11 @@ const BUILTIN_RULE_IDS = [
|
|
|
318
323
|
"jsx-a11y/role-has-required-aria-props",
|
|
319
324
|
"jsx-a11y/role-supports-aria-props",
|
|
320
325
|
"jsx-a11y/scope",
|
|
326
|
+
"promise/always-return",
|
|
327
|
+
"promise/catch-or-return",
|
|
328
|
+
"promise/no-callback-in-promise",
|
|
329
|
+
"promise/no-nesting",
|
|
330
|
+
"promise/no-new-statics",
|
|
321
331
|
"react/button-has-type",
|
|
322
332
|
"react/default-props-match-prop-types",
|
|
323
333
|
"react/display-name",
|
|
@@ -358,7 +368,9 @@ const BUILTIN_RULE_IDS = [
|
|
|
358
368
|
"react/self-closing-comp",
|
|
359
369
|
"react/style-prop-object",
|
|
360
370
|
"react/void-dom-elements-no-children",
|
|
371
|
+
"react-hooks/exhaustive-deps",
|
|
361
372
|
"react-hooks/rules-of-hooks",
|
|
373
|
+
"unused-imports/no-unused-imports",
|
|
362
374
|
"@typescript-eslint/adjacent-overload-signatures",
|
|
363
375
|
"@typescript-eslint/array-type",
|
|
364
376
|
"@typescript-eslint/ban-ts-comment",
|
|
@@ -376,6 +388,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
376
388
|
"@typescript-eslint/no-dupe-class-members",
|
|
377
389
|
"@typescript-eslint/no-empty-function",
|
|
378
390
|
"@typescript-eslint/no-empty-interface",
|
|
391
|
+
"@typescript-eslint/no-empty-object-type",
|
|
379
392
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
380
393
|
"@typescript-eslint/no-extra-semi",
|
|
381
394
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
@@ -391,6 +404,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
391
404
|
"@typescript-eslint/no-shadow",
|
|
392
405
|
"@typescript-eslint/no-this-alias",
|
|
393
406
|
"@typescript-eslint/no-unsafe-declaration-merging",
|
|
407
|
+
"@typescript-eslint/no-unsafe-function-type",
|
|
394
408
|
"@typescript-eslint/triple-slash-reference",
|
|
395
409
|
"@typescript-eslint/typedef",
|
|
396
410
|
"@typescript-eslint/unified-signatures",
|
|
@@ -434,7 +448,11 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
434
448
|
"semantic-errors"
|
|
435
449
|
];
|
|
436
450
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
437
|
-
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
451
|
+
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
452
|
+
"no-extra-semi",
|
|
453
|
+
"@typescript-eslint/no-extra-semi",
|
|
454
|
+
"unused-imports/no-unused-imports"
|
|
455
|
+
]);
|
|
438
456
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
439
457
|
|
|
440
458
|
class UtooLint {
|
package/index.js
CHANGED
|
@@ -308,6 +308,11 @@ const BUILTIN_RULE_IDS = [
|
|
|
308
308
|
"import/no-named-as-default-member",
|
|
309
309
|
"import/no-unresolved",
|
|
310
310
|
"import/no-self-import",
|
|
311
|
+
"promise/no-promise-in-callback",
|
|
312
|
+
"promise/no-return-in-finally",
|
|
313
|
+
"promise/no-return-wrap",
|
|
314
|
+
"promise/param-names",
|
|
315
|
+
"promise/valid-params",
|
|
311
316
|
"jsx-a11y/alt-text",
|
|
312
317
|
"jsx-a11y/anchor-has-content",
|
|
313
318
|
"jsx-a11y/aria-props",
|
|
@@ -321,6 +326,11 @@ const BUILTIN_RULE_IDS = [
|
|
|
321
326
|
"jsx-a11y/role-has-required-aria-props",
|
|
322
327
|
"jsx-a11y/role-supports-aria-props",
|
|
323
328
|
"jsx-a11y/scope",
|
|
329
|
+
"promise/always-return",
|
|
330
|
+
"promise/catch-or-return",
|
|
331
|
+
"promise/no-callback-in-promise",
|
|
332
|
+
"promise/no-nesting",
|
|
333
|
+
"promise/no-new-statics",
|
|
324
334
|
"react/button-has-type",
|
|
325
335
|
"react/default-props-match-prop-types",
|
|
326
336
|
"react/display-name",
|
|
@@ -361,7 +371,9 @@ const BUILTIN_RULE_IDS = [
|
|
|
361
371
|
"react/self-closing-comp",
|
|
362
372
|
"react/style-prop-object",
|
|
363
373
|
"react/void-dom-elements-no-children",
|
|
374
|
+
"react-hooks/exhaustive-deps",
|
|
364
375
|
"react-hooks/rules-of-hooks",
|
|
376
|
+
"unused-imports/no-unused-imports",
|
|
365
377
|
"@typescript-eslint/adjacent-overload-signatures",
|
|
366
378
|
"@typescript-eslint/array-type",
|
|
367
379
|
"@typescript-eslint/ban-ts-comment",
|
|
@@ -379,6 +391,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
379
391
|
"@typescript-eslint/no-dupe-class-members",
|
|
380
392
|
"@typescript-eslint/no-empty-function",
|
|
381
393
|
"@typescript-eslint/no-empty-interface",
|
|
394
|
+
"@typescript-eslint/no-empty-object-type",
|
|
382
395
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
383
396
|
"@typescript-eslint/no-extra-semi",
|
|
384
397
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
@@ -394,6 +407,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
394
407
|
"@typescript-eslint/no-shadow",
|
|
395
408
|
"@typescript-eslint/no-this-alias",
|
|
396
409
|
"@typescript-eslint/no-unsafe-declaration-merging",
|
|
410
|
+
"@typescript-eslint/no-unsafe-function-type",
|
|
397
411
|
"@typescript-eslint/triple-slash-reference",
|
|
398
412
|
"@typescript-eslint/typedef",
|
|
399
413
|
"@typescript-eslint/unified-signatures",
|
|
@@ -437,7 +451,11 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
437
451
|
"semantic-errors"
|
|
438
452
|
];
|
|
439
453
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
440
|
-
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
454
|
+
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
455
|
+
"no-extra-semi",
|
|
456
|
+
"@typescript-eslint/no-extra-semi",
|
|
457
|
+
"unused-imports/no-unused-imports"
|
|
458
|
+
]);
|
|
441
459
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
442
460
|
|
|
443
461
|
export class UtooLint {
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utoo/lint",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.9",
|
|
4
|
+
"description": "High-performance JavaScript and TypeScript linter powered by Yuku",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/
|
|
8
|
+
"url": "git+https://github.com/utooland/utoo-lint.git"
|
|
9
9
|
},
|
|
10
10
|
"bugs": {
|
|
11
|
-
"url": "https://github.com/
|
|
11
|
+
"url": "https://github.com/utooland/utoo-lint/issues"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://github.com/
|
|
13
|
+
"homepage": "https://github.com/utooland/utoo-lint#readme",
|
|
14
14
|
"type": "module",
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=20.0.0"
|
|
17
17
|
},
|
|
18
18
|
"types": "./index.d.ts",
|
|
19
19
|
"exports": {
|
|
@@ -76,11 +76,11 @@
|
|
|
76
76
|
"use-at-your-own-risk.js"
|
|
77
77
|
],
|
|
78
78
|
"optionalDependencies": {
|
|
79
|
-
"@utoo/lint-darwin-arm64": "0.2.
|
|
80
|
-
"@utoo/lint-darwin-x64": "0.2.
|
|
81
|
-
"@utoo/lint-linux-arm64": "0.2.
|
|
82
|
-
"@utoo/lint-linux-x64": "0.2.
|
|
83
|
-
"@utoo/lint-win32-x64": "0.2.
|
|
79
|
+
"@utoo/lint-darwin-arm64": "0.2.9",
|
|
80
|
+
"@utoo/lint-darwin-x64": "0.2.9",
|
|
81
|
+
"@utoo/lint-linux-arm64": "0.2.9",
|
|
82
|
+
"@utoo/lint-linux-x64": "0.2.9",
|
|
83
|
+
"@utoo/lint-win32-x64": "0.2.9"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"jiti": "2.7.0"
|
package/schema.json
CHANGED
|
@@ -1,50 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft-07/schema",
|
|
3
|
-
"$id": "https://raw.githubusercontent.com/
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/utooland/utoo-lint/main/npm/utoo-lint/schema.json",
|
|
4
4
|
"title": "utoo-lint configuration",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"$schema": {
|
|
9
|
-
"type": "string"
|
|
5
|
+
"oneOf": [
|
|
6
|
+
{
|
|
7
|
+
"$ref": "#/definitions/configObject"
|
|
10
8
|
},
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"$ref": "#/definitions/ruleSeverity"
|
|
9
|
+
{
|
|
10
|
+
"type": "array",
|
|
11
|
+
"items": {
|
|
12
|
+
"$ref": "#/definitions/configObject"
|
|
16
13
|
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"definitions": {
|
|
17
|
+
"configObject": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": true,
|
|
20
|
+
"properties": {
|
|
21
|
+
"$schema": {
|
|
22
22
|
"type": "string"
|
|
23
23
|
},
|
|
24
|
-
{
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
24
|
+
"rules": {
|
|
25
|
+
"description": "ESLint-compatible rule severity map. Unknown rule names are rejected by utoo-lint.",
|
|
26
|
+
"type": "object",
|
|
27
|
+
"additionalProperties": {
|
|
28
|
+
"$ref": "#/definitions/ruleSeverity"
|
|
28
29
|
}
|
|
29
|
-
}
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
"ignores": {
|
|
33
|
-
"description": "File globs ignored by this config entry.",
|
|
34
|
-
"oneOf": [
|
|
35
|
-
{
|
|
36
|
-
"type": "string"
|
|
37
30
|
},
|
|
38
|
-
{
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
"files": {
|
|
32
|
+
"description": "File globs this config entry applies to.",
|
|
33
|
+
"oneOf": [
|
|
34
|
+
{
|
|
35
|
+
"type": "string"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"ignores": {
|
|
46
|
+
"description": "File globs ignored by this config entry.",
|
|
47
|
+
"oneOf": [
|
|
48
|
+
{
|
|
49
|
+
"type": "string"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": {
|
|
54
|
+
"type": "string"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
43
58
|
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
"definitions": {
|
|
59
|
+
}
|
|
60
|
+
},
|
|
48
61
|
"ruleSeverity": {
|
|
49
62
|
"oneOf": [
|
|
50
63
|
{
|