@utoo/lint 0.2.7 → 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 +176 -159
- package/bin/migrate.js +84 -34
- package/configs/frontend.json +1 -1
- package/index.cjs +126 -7
- package/index.d.ts +9 -1
- package/index.js +126 -7
- package/package.json +11 -11
- package/schema.json +50 -37
package/README.md
CHANGED
|
@@ -2,234 +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
|
|
53
|
+
In an existing project, run `ut install` without a package name to install all
|
|
54
|
+
dependencies declared in `package.json`.
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
### Other package managers
|
|
52
57
|
|
|
53
58
|
```bash
|
|
54
|
-
pnpm
|
|
59
|
+
pnpm add -D @utoo/lint
|
|
60
|
+
npm install --save-dev @utoo/lint
|
|
55
61
|
```
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
The package selects the native binary for the current platform. No Zig
|
|
64
|
+
toolchain is required.
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
### Run with the default rules
|
|
58
69
|
|
|
59
70
|
```bash
|
|
60
|
-
|
|
71
|
+
utx @utoo/lint src
|
|
61
72
|
```
|
|
62
73
|
|
|
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.
|
|
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.
|
|
69
76
|
|
|
70
|
-
|
|
77
|
+
### Add a typed config
|
|
71
78
|
|
|
72
|
-
`
|
|
79
|
+
Create `utlint.config.ts`:
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
| `utlint.config.json` | You want a static, runtime-independent config. | Yes |
|
|
81
|
+
```ts
|
|
82
|
+
import { defineConfig, globalIgnores } from "@utoo/lint/config";
|
|
83
|
+
import frontend from "@utoo/lint/configs/frontend";
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
|
|
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
|
+
```
|
|
97
|
+
|
|
98
|
+
The CLI discovers the config and uses its `files` patterns:
|
|
81
99
|
|
|
82
100
|
```bash
|
|
83
|
-
|
|
84
|
-
pnpm exec utoo-lint --config=utlint.config.json src
|
|
101
|
+
utx @utoo/lint
|
|
85
102
|
```
|
|
86
103
|
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
89
109
|
|
|
90
110
|
```json
|
|
91
111
|
{
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"rules": {
|
|
96
|
-
"no-console": "off",
|
|
97
|
-
"no-debugger": "error"
|
|
112
|
+
"scripts": {
|
|
113
|
+
"lint": "utoo-lint src",
|
|
114
|
+
"lint:fix": "utoo-lint --fix src"
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
```
|
|
101
118
|
|
|
102
|
-
|
|
119
|
+
With utoo, run these scripts as `ut lint` and `ut lint:fix`.
|
|
103
120
|
|
|
104
|
-
|
|
105
|
-
import { defineConfig } from "@utoo/lint/config";
|
|
106
|
-
|
|
107
|
-
export default defineConfig({
|
|
108
|
-
files: ["src/**/*.{js,jsx,ts,tsx}"],
|
|
109
|
-
ignores: ["dist", "node_modules"],
|
|
110
|
-
rules: {
|
|
111
|
-
"no-console": "off",
|
|
112
|
-
"no-debugger": "error"
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
```
|
|
121
|
+
## Common commands
|
|
116
122
|
|
|
117
|
-
|
|
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` |
|
|
118
130
|
|
|
119
|
-
|
|
120
|
-
import { defineConfig } from "@utoo/lint/config";
|
|
121
|
-
import frontend from "@utoo/lint/configs/frontend";
|
|
131
|
+
Run `utx @utoo/lint --help` for all CLI options.
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
...frontend,
|
|
125
|
-
rules: {
|
|
126
|
-
...frontend.rules,
|
|
127
|
-
"no-console": "off",
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
```
|
|
133
|
+
## Configuration
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
`utoo-lint` supports two canonical config formats. They are alternative
|
|
136
|
+
representations of one active config and are not merged together.
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
|
|
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 |
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
|
147
158
|
```
|
|
148
159
|
|
|
149
|
-
|
|
150
|
-
generated `name`. Only such global entries prune directories during target
|
|
151
|
-
discovery. By contrast, `ignores` beside `files`, `rules`, or another config
|
|
152
|
-
key is entry-scoped: it prevents that entry from applying to matching files,
|
|
153
|
-
but does not exclude them from other entries. With no CLI targets, global
|
|
154
|
-
ignores filter the config's `files` patterns, or the current-directory scan
|
|
155
|
-
when no `files` are configured. Directory patterns such as `dist/` and
|
|
156
|
-
`.next/` are relative to the config; use `**/generated/` to match at any depth.
|
|
157
|
-
This intentionally follows [ESLint flat config ignore semantics](https://eslint.org/docs/latest/use/configure/ignore).
|
|
158
|
-
|
|
159
|
-
The two canonical names represent one active config and are not implicitly
|
|
160
|
-
merged. For the npm/Node entry point, discovery is nearest-directory-first.
|
|
161
|
-
Within the same directory, `utlint.config.ts` takes precedence over
|
|
162
|
-
`utlint.config.json`; deprecated `utoo.json` and `utoo-lint.json` files are
|
|
163
|
-
checked afterward for temporary backward compatibility. Rule-related CLI
|
|
164
|
-
options such as `--rules`, individual rule toggles, and fishlint's `--rule` are
|
|
165
|
-
applied after the selected config.
|
|
166
|
-
|
|
167
|
-
Project-config `files` and `ignores` patterns are relative to the selected
|
|
168
|
-
config file's directory. In a flat config array, they select the entries that
|
|
169
|
-
apply to each file; matching entries are combined in order and later rule
|
|
170
|
-
values override earlier values. The npm CLI, JavaScript API, and fishlint
|
|
171
|
-
compatibility command perform this rule resolution per file.
|
|
172
|
-
|
|
173
|
-
TypeScript config is trusted executable code. Its default export must be a
|
|
174
|
-
JSON-serializable object or flat config array. The npm wrapper executes it and
|
|
175
|
-
materializes the result as JSON before invoking the native binary. The raw
|
|
176
|
-
binary does not execute or discover TypeScript; it searches for
|
|
177
|
-
`utlint.config.json` and then the legacy JSON names. Direct native use therefore
|
|
178
|
-
requires a JSON config. The raw binary applies only its `rules`;
|
|
179
|
-
config-driven `files` and `ignores` filtering and default target selection are
|
|
180
|
-
npm/Node wrapper features. Pass lint targets explicitly when invoking the raw
|
|
181
|
-
binary. As in ESLint, selecting a config disables rules not present in its
|
|
182
|
-
resolved `rules` map. When no config is selected, utoo-lint uses its built-in
|
|
183
|
-
default rules.
|
|
184
|
-
|
|
185
|
-
Rule severities use ESLint's exit behavior: warnings are reported with exit
|
|
186
|
-
status 0, while errors return exit status 1. Use fishlint's `--max-warnings`
|
|
187
|
-
option when warnings should fail CI.
|
|
188
|
-
|
|
189
|
-
Start from the packaged frontend template:
|
|
160
|
+
Preview fixes without writing files:
|
|
190
161
|
|
|
191
162
|
```bash
|
|
192
|
-
|
|
163
|
+
utx @utoo/lint --fix-dry-run --format=json src
|
|
193
164
|
```
|
|
194
165
|
|
|
195
|
-
|
|
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.
|
|
196
169
|
|
|
197
|
-
|
|
170
|
+
## Suppression comments
|
|
198
171
|
|
|
199
|
-
|
|
200
|
-
|
|
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;
|
|
201
178
|
```
|
|
202
179
|
|
|
203
|
-
|
|
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:
|
|
204
198
|
|
|
205
199
|
```bash
|
|
206
|
-
|
|
207
|
-
|
|
200
|
+
utx @utoo/lint migrate eslint \
|
|
201
|
+
--from eslint.config.js \
|
|
202
|
+
--output utlint.config.json
|
|
208
203
|
```
|
|
209
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
|
+
|
|
210
210
|
## JavaScript API
|
|
211
211
|
|
|
212
|
+
The package provides ESM and CommonJS entry points:
|
|
213
|
+
|
|
212
214
|
```js
|
|
213
215
|
import { lintFiles } from "@utoo/lint";
|
|
214
216
|
|
|
215
217
|
const report = lintFiles(["src"], {
|
|
216
|
-
config: "utlint.config.
|
|
217
|
-
rules: ["no-debugger"]
|
|
218
|
+
config: "utlint.config.ts"
|
|
218
219
|
});
|
|
219
220
|
|
|
220
221
|
console.log(report.diagnostics);
|
|
221
222
|
```
|
|
222
223
|
|
|
223
|
-
|
|
224
|
-
as the CLI, so migration scripts usually do not need to expand config `files`
|
|
225
|
-
manually.
|
|
226
|
-
|
|
227
|
-
CommonJS is supported through `require("@utoo/lint")`.
|
|
228
|
-
|
|
229
|
-
Set `fix: true` to compute fixed output through the JavaScript API. Raw
|
|
230
|
-
`lintFiles()` and `lintText()` reports expose changed sources in `outputs`
|
|
231
|
-
without writing them. The ESLint-compatible API follows the usual two-step
|
|
232
|
-
flow:
|
|
224
|
+
An ESLint-style API is also available:
|
|
233
225
|
|
|
234
226
|
```js
|
|
235
227
|
import { ESLint } from "@utoo/lint";
|
|
@@ -239,8 +231,33 @@ const results = await eslint.lintFiles(["src"]);
|
|
|
239
231
|
await ESLint.outputFixes(results);
|
|
240
232
|
```
|
|
241
233
|
|
|
242
|
-
|
|
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
|
|
243
262
|
|
|
244
|
-
|
|
245
|
-
native `utoo-lint` binary. Set `UTOO_LINT_BIN=/path/to/utoo-lint` to force a
|
|
246
|
-
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 {
|
|
@@ -514,7 +532,7 @@ class UtooLint {
|
|
|
514
532
|
const results = reportToESLintResults(report, {
|
|
515
533
|
source: code,
|
|
516
534
|
filePath,
|
|
517
|
-
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
|
|
535
|
+
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
|
|
518
536
|
ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(nativeOptions, filePath)
|
|
519
537
|
});
|
|
520
538
|
if (report.files !== 0) {
|
|
@@ -641,7 +659,7 @@ class CLIEngine {
|
|
|
641
659
|
const results = maybeFilterQuietResults(reportToESLintResults(report, {
|
|
642
660
|
source: code,
|
|
643
661
|
filePath: normalizeESLintFilePath(filePath, mergedOptions.cwd),
|
|
644
|
-
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
|
|
662
|
+
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
|
|
645
663
|
ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(mergedOptions, filePath)
|
|
646
664
|
}), mergedOptions);
|
|
647
665
|
return resultsToCLIEngineReport(results);
|
|
@@ -842,6 +860,7 @@ function publicCliReport(report) {
|
|
|
842
860
|
files: report.files ?? 0,
|
|
843
861
|
filePaths: report.filePaths ?? [],
|
|
844
862
|
diagnostics: report.diagnostics ?? [],
|
|
863
|
+
suppressedDiagnostics: report.suppressedDiagnostics ?? [],
|
|
845
864
|
outputs: report.outputs ?? []
|
|
846
865
|
};
|
|
847
866
|
}
|
|
@@ -1140,7 +1159,7 @@ function lintFiles(paths, options = {}) {
|
|
|
1140
1159
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
1141
1160
|
const lintPaths = filteredLintPaths(targets, options);
|
|
1142
1161
|
if (lintPaths.length === 0) {
|
|
1143
|
-
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1162
|
+
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1144
1163
|
}
|
|
1145
1164
|
|
|
1146
1165
|
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
@@ -1205,8 +1224,10 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
|
1205
1224
|
if (!options.deferDiagnosticConfigFiltering) {
|
|
1206
1225
|
report.filePaths = normalizeReportFilePaths(report.filePaths, options);
|
|
1207
1226
|
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
|
|
1227
|
+
report.suppressedDiagnostics = normalizeDiagnosticFilePaths(report.suppressedDiagnostics, options);
|
|
1208
1228
|
report.outputs = normalizeReportOutputs(report.outputs, options);
|
|
1209
1229
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
1230
|
+
report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
|
|
1210
1231
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
1211
1232
|
}
|
|
1212
1233
|
return report;
|
|
@@ -1303,6 +1324,7 @@ function mergeNativeReports(reports) {
|
|
|
1303
1324
|
files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
|
|
1304
1325
|
filePaths: reports.flatMap((item) => item.filePaths ?? []),
|
|
1305
1326
|
diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
|
|
1327
|
+
suppressedDiagnostics: reports.flatMap((item) => item.suppressedDiagnostics ?? []),
|
|
1306
1328
|
outputs: reports.flatMap((item) => item.outputs ?? []),
|
|
1307
1329
|
exitCode: reports.some((item) => item.exitCode) ? 1 : 0
|
|
1308
1330
|
};
|
|
@@ -1335,6 +1357,7 @@ function lintText(code, options = {}) {
|
|
|
1335
1357
|
files: 0,
|
|
1336
1358
|
filePaths: [],
|
|
1337
1359
|
diagnostics,
|
|
1360
|
+
suppressedDiagnostics: [],
|
|
1338
1361
|
exitCode: exitCodeForDiagnostics(diagnostics)
|
|
1339
1362
|
};
|
|
1340
1363
|
}
|
|
@@ -1356,7 +1379,12 @@ function lintText(code, options = {}) {
|
|
|
1356
1379
|
...diagnostic,
|
|
1357
1380
|
filePath: requestedPath
|
|
1358
1381
|
}));
|
|
1382
|
+
report.suppressedDiagnostics = (report.suppressedDiagnostics ?? []).map((diagnostic) => ({
|
|
1383
|
+
...diagnostic,
|
|
1384
|
+
filePath: requestedPath
|
|
1385
|
+
}));
|
|
1359
1386
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
1387
|
+
report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
|
|
1360
1388
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
1361
1389
|
return report;
|
|
1362
1390
|
} finally {
|
|
@@ -1888,7 +1916,10 @@ class Linter {
|
|
|
1888
1916
|
config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
|
|
1889
1917
|
});
|
|
1890
1918
|
const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
|
|
1891
|
-
this.suppressedMessages =
|
|
1919
|
+
this.suppressedMessages = [
|
|
1920
|
+
...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
1921
|
+
...customRuleFilter.suppressedMessages
|
|
1922
|
+
];
|
|
1892
1923
|
this.times = { passes: [] };
|
|
1893
1924
|
this.fixPassCount = 0;
|
|
1894
1925
|
return [
|
|
@@ -2197,14 +2228,18 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
2197
2228
|
const directives = sourceCode.getDisableDirectives()
|
|
2198
2229
|
.filter((directive) => directive.node?.loc?.start?.line)
|
|
2199
2230
|
.sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
|
|
2200
|
-
|
|
2231
|
+
const utlintDirectives = sourceCode.getAllComments()
|
|
2232
|
+
.map((comment) => utlintDirectiveFromComment(comment, sourceCode))
|
|
2233
|
+
.filter(Boolean)
|
|
2234
|
+
.sort((left, right) => left.node.range[0] - right.node.range[0]);
|
|
2235
|
+
if (directives.length === 0 && utlintDirectives.length === 0) {
|
|
2201
2236
|
return { messages, suppressedMessages: [] };
|
|
2202
2237
|
}
|
|
2203
2238
|
|
|
2204
2239
|
const kept = [];
|
|
2205
2240
|
const suppressed = [];
|
|
2206
2241
|
for (const message of messages) {
|
|
2207
|
-
const directive = disableDirectiveForMessage(message, directives);
|
|
2242
|
+
const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
|
|
2208
2243
|
if (directive) {
|
|
2209
2244
|
suppressed.push({
|
|
2210
2245
|
...message,
|
|
@@ -2220,6 +2255,68 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
2220
2255
|
return { messages: kept, suppressedMessages: suppressed };
|
|
2221
2256
|
}
|
|
2222
2257
|
|
|
2258
|
+
function utlintDirectiveFromComment(comment, sourceCode) {
|
|
2259
|
+
const match = String(comment?.value ?? "").trim().match(/^(utlint-ignore(?:-all|-start|-end)?)\b\s*(.*)$/u);
|
|
2260
|
+
if (!match) {
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
const [, type, tail] = match;
|
|
2265
|
+
const colon = tail.indexOf(":");
|
|
2266
|
+
const rawRuleId = (colon === -1 ? tail : tail.slice(0, colon)).trim();
|
|
2267
|
+
const justification = colon === -1 ? "" : tail.slice(colon + 1).trim();
|
|
2268
|
+
const nextToken = sourceCode.getAllTokens().find((token) => token.range?.[0] >= comment.range?.[1]);
|
|
2269
|
+
return {
|
|
2270
|
+
type,
|
|
2271
|
+
node: comment,
|
|
2272
|
+
ruleId: rawRuleId || null,
|
|
2273
|
+
justification,
|
|
2274
|
+
nextCodeLine: nextToken?.loc?.start?.line ?? null,
|
|
2275
|
+
topLevel: sourceCode.getAllTokens().every((token) => token.range?.[0] >= comment.range?.[0])
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
function utlintDirectiveForMessage(message, directives) {
|
|
2280
|
+
let allRulesRangeDepth = 0;
|
|
2281
|
+
let namedRuleRangeDepth = 0;
|
|
2282
|
+
let allRulesRangeDirective = null;
|
|
2283
|
+
let namedRuleRangeDirective = null;
|
|
2284
|
+
|
|
2285
|
+
for (const directive of directives) {
|
|
2286
|
+
if (directive.node.loc.start.line > message.line) {
|
|
2287
|
+
break;
|
|
2288
|
+
}
|
|
2289
|
+
if (directive.type === "utlint-ignore-start") {
|
|
2290
|
+
if (directive.ruleId == null) {
|
|
2291
|
+
allRulesRangeDirective ??= directive;
|
|
2292
|
+
allRulesRangeDepth += 1;
|
|
2293
|
+
} else if (directive.ruleId === message.ruleId) {
|
|
2294
|
+
namedRuleRangeDirective ??= directive;
|
|
2295
|
+
namedRuleRangeDepth += 1;
|
|
2296
|
+
}
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
if (directive.type === "utlint-ignore-end") {
|
|
2300
|
+
if (directive.ruleId == null && allRulesRangeDepth > 0) {
|
|
2301
|
+
allRulesRangeDepth -= 1;
|
|
2302
|
+
if (allRulesRangeDepth === 0) allRulesRangeDirective = null;
|
|
2303
|
+
} else if (directive.ruleId === message.ruleId && namedRuleRangeDepth > 0) {
|
|
2304
|
+
namedRuleRangeDepth -= 1;
|
|
2305
|
+
if (namedRuleRangeDepth === 0) namedRuleRangeDirective = null;
|
|
2306
|
+
}
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
if (directive.type === "utlint-ignore-all" && directive.topLevel && disableDirectiveMatchesRule(directive, message.ruleId)) {
|
|
2310
|
+
return directive;
|
|
2311
|
+
}
|
|
2312
|
+
if (directive.type === "utlint-ignore" && directive.nextCodeLine === message.line && disableDirectiveMatchesRule(directive, message.ruleId)) {
|
|
2313
|
+
return directive;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
return namedRuleRangeDirective ?? allRulesRangeDirective;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2223
2320
|
function disableDirectiveForMessage(message, directives) {
|
|
2224
2321
|
const active = {
|
|
2225
2322
|
all: null,
|
|
@@ -3695,6 +3792,18 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3695
3792
|
byFile.get(filePath).messages.push(diagnosticToESLintMessage(diagnostic, ruleSeverities));
|
|
3696
3793
|
}
|
|
3697
3794
|
|
|
3795
|
+
for (const diagnostic of report.suppressedDiagnostics ?? []) {
|
|
3796
|
+
const filePath = textOptions.filePath ?? normalizeESLintFilePath(diagnostic.filePath, textOptions.cwd);
|
|
3797
|
+
if (!byFile.has(filePath)) {
|
|
3798
|
+
byFile.set(filePath, emptyESLintResult(filePath, textOptions.source));
|
|
3799
|
+
}
|
|
3800
|
+
const ruleSeverities = textOptions.ruleSeverityForFile?.(filePath) ?? textOptions.ruleSeverities;
|
|
3801
|
+
if (diagnostic.ruleId && ruleSeverities?.get(diagnostic.ruleId) === 0) {
|
|
3802
|
+
continue;
|
|
3803
|
+
}
|
|
3804
|
+
byFile.get(filePath).suppressedMessages.push(suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities));
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3698
3807
|
for (const fixed of report.outputs ?? []) {
|
|
3699
3808
|
const filePath = textOptions.filePath ?? normalizeESLintFilePath(fixed.filePath, textOptions.cwd);
|
|
3700
3809
|
if (!byFile.has(filePath)) {
|
|
@@ -4398,6 +4507,16 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4398
4507
|
return message;
|
|
4399
4508
|
}
|
|
4400
4509
|
|
|
4510
|
+
function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
4511
|
+
return {
|
|
4512
|
+
...diagnosticToESLintMessage(diagnostic, ruleSeverities),
|
|
4513
|
+
suppressions: [{
|
|
4514
|
+
kind: diagnostic.suppression?.kind ?? "directive",
|
|
4515
|
+
justification: diagnostic.suppression?.justification ?? ""
|
|
4516
|
+
}]
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
|
|
4401
4520
|
function finalizeESLintResult(result) {
|
|
4402
4521
|
result.errorCount = 0;
|
|
4403
4522
|
result.warningCount = 0;
|
package/index.d.ts
CHANGED
|
@@ -9,10 +9,17 @@ export interface LintMessage {
|
|
|
9
9
|
nodeType?: string | null;
|
|
10
10
|
fix?: LintFix | LintFix[];
|
|
11
11
|
suggestions?: LintSuggestion[];
|
|
12
|
+
suppressions?: LintSuppression[];
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export interface
|
|
15
|
+
export interface LintSuppression {
|
|
16
|
+
kind: "directive";
|
|
17
|
+
justification: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LintDiagnostic extends Omit<LintMessage, "severity" | "suppressions"> {
|
|
15
21
|
severity: "warning" | "error";
|
|
22
|
+
suppression?: LintSuppression;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export interface LintFix {
|
|
@@ -42,6 +49,7 @@ export interface LintReport {
|
|
|
42
49
|
files: number;
|
|
43
50
|
filePaths: string[];
|
|
44
51
|
diagnostics: LintDiagnostic[];
|
|
52
|
+
suppressedDiagnostics: LintDiagnostic[];
|
|
45
53
|
outputs?: Array<{ filePath: string; output: string }>;
|
|
46
54
|
exitCode: number;
|
|
47
55
|
stderr?: string;
|
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 {
|
|
@@ -517,7 +535,7 @@ export class UtooLint {
|
|
|
517
535
|
const results = reportToESLintResults(report, {
|
|
518
536
|
source: code,
|
|
519
537
|
filePath,
|
|
520
|
-
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
|
|
538
|
+
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
|
|
521
539
|
ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(nativeOptions, filePath)
|
|
522
540
|
});
|
|
523
541
|
if (report.files !== 0) {
|
|
@@ -635,7 +653,10 @@ export class Linter {
|
|
|
635
653
|
config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
|
|
636
654
|
});
|
|
637
655
|
const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
|
|
638
|
-
this.suppressedMessages =
|
|
656
|
+
this.suppressedMessages = [
|
|
657
|
+
...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
658
|
+
...customRuleFilter.suppressedMessages
|
|
659
|
+
];
|
|
639
660
|
this.times = { passes: [] };
|
|
640
661
|
this.fixPassCount = 0;
|
|
641
662
|
return [
|
|
@@ -944,14 +965,18 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
944
965
|
const directives = sourceCode.getDisableDirectives()
|
|
945
966
|
.filter((directive) => directive.node?.loc?.start?.line)
|
|
946
967
|
.sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
|
|
947
|
-
|
|
968
|
+
const utlintDirectives = sourceCode.getAllComments()
|
|
969
|
+
.map((comment) => utlintDirectiveFromComment(comment, sourceCode))
|
|
970
|
+
.filter(Boolean)
|
|
971
|
+
.sort((left, right) => left.node.range[0] - right.node.range[0]);
|
|
972
|
+
if (directives.length === 0 && utlintDirectives.length === 0) {
|
|
948
973
|
return { messages, suppressedMessages: [] };
|
|
949
974
|
}
|
|
950
975
|
|
|
951
976
|
const kept = [];
|
|
952
977
|
const suppressed = [];
|
|
953
978
|
for (const message of messages) {
|
|
954
|
-
const directive = disableDirectiveForMessage(message, directives);
|
|
979
|
+
const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
|
|
955
980
|
if (directive) {
|
|
956
981
|
suppressed.push({
|
|
957
982
|
...message,
|
|
@@ -967,6 +992,68 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
967
992
|
return { messages: kept, suppressedMessages: suppressed };
|
|
968
993
|
}
|
|
969
994
|
|
|
995
|
+
function utlintDirectiveFromComment(comment, sourceCode) {
|
|
996
|
+
const match = String(comment?.value ?? "").trim().match(/^(utlint-ignore(?:-all|-start|-end)?)\b\s*(.*)$/u);
|
|
997
|
+
if (!match) {
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const [, type, tail] = match;
|
|
1002
|
+
const colon = tail.indexOf(":");
|
|
1003
|
+
const rawRuleId = (colon === -1 ? tail : tail.slice(0, colon)).trim();
|
|
1004
|
+
const justification = colon === -1 ? "" : tail.slice(colon + 1).trim();
|
|
1005
|
+
const nextToken = sourceCode.getAllTokens().find((token) => token.range?.[0] >= comment.range?.[1]);
|
|
1006
|
+
return {
|
|
1007
|
+
type,
|
|
1008
|
+
node: comment,
|
|
1009
|
+
ruleId: rawRuleId || null,
|
|
1010
|
+
justification,
|
|
1011
|
+
nextCodeLine: nextToken?.loc?.start?.line ?? null,
|
|
1012
|
+
topLevel: sourceCode.getAllTokens().every((token) => token.range?.[0] >= comment.range?.[0])
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
function utlintDirectiveForMessage(message, directives) {
|
|
1017
|
+
let allRulesRangeDepth = 0;
|
|
1018
|
+
let namedRuleRangeDepth = 0;
|
|
1019
|
+
let allRulesRangeDirective = null;
|
|
1020
|
+
let namedRuleRangeDirective = null;
|
|
1021
|
+
|
|
1022
|
+
for (const directive of directives) {
|
|
1023
|
+
if (directive.node.loc.start.line > message.line) {
|
|
1024
|
+
break;
|
|
1025
|
+
}
|
|
1026
|
+
if (directive.type === "utlint-ignore-start") {
|
|
1027
|
+
if (directive.ruleId == null) {
|
|
1028
|
+
allRulesRangeDirective ??= directive;
|
|
1029
|
+
allRulesRangeDepth += 1;
|
|
1030
|
+
} else if (directive.ruleId === message.ruleId) {
|
|
1031
|
+
namedRuleRangeDirective ??= directive;
|
|
1032
|
+
namedRuleRangeDepth += 1;
|
|
1033
|
+
}
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
if (directive.type === "utlint-ignore-end") {
|
|
1037
|
+
if (directive.ruleId == null && allRulesRangeDepth > 0) {
|
|
1038
|
+
allRulesRangeDepth -= 1;
|
|
1039
|
+
if (allRulesRangeDepth === 0) allRulesRangeDirective = null;
|
|
1040
|
+
} else if (directive.ruleId === message.ruleId && namedRuleRangeDepth > 0) {
|
|
1041
|
+
namedRuleRangeDepth -= 1;
|
|
1042
|
+
if (namedRuleRangeDepth === 0) namedRuleRangeDirective = null;
|
|
1043
|
+
}
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
if (directive.type === "utlint-ignore-all" && directive.topLevel && disableDirectiveMatchesRule(directive, message.ruleId)) {
|
|
1047
|
+
return directive;
|
|
1048
|
+
}
|
|
1049
|
+
if (directive.type === "utlint-ignore" && directive.nextCodeLine === message.line && disableDirectiveMatchesRule(directive, message.ruleId)) {
|
|
1050
|
+
return directive;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
return namedRuleRangeDirective ?? allRulesRangeDirective;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
970
1057
|
function disableDirectiveForMessage(message, directives) {
|
|
971
1058
|
const active = {
|
|
972
1059
|
all: null,
|
|
@@ -2477,7 +2564,7 @@ export class CLIEngine {
|
|
|
2477
2564
|
const results = maybeFilterQuietResults(reportToESLintResults(report, {
|
|
2478
2565
|
source: code,
|
|
2479
2566
|
filePath: normalizeESLintFilePath(filePath, mergedOptions.cwd),
|
|
2480
|
-
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
|
|
2567
|
+
includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
|
|
2481
2568
|
ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(mergedOptions, filePath)
|
|
2482
2569
|
}), mergedOptions);
|
|
2483
2570
|
return resultsToCLIEngineReport(results);
|
|
@@ -2678,6 +2765,7 @@ function publicCliReport(report) {
|
|
|
2678
2765
|
files: report.files ?? 0,
|
|
2679
2766
|
filePaths: report.filePaths ?? [],
|
|
2680
2767
|
diagnostics: report.diagnostics ?? [],
|
|
2768
|
+
suppressedDiagnostics: report.suppressedDiagnostics ?? [],
|
|
2681
2769
|
outputs: report.outputs ?? []
|
|
2682
2770
|
};
|
|
2683
2771
|
}
|
|
@@ -2976,7 +3064,7 @@ export function lintFiles(paths, options = {}) {
|
|
|
2976
3064
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
2977
3065
|
const lintPaths = filteredLintPaths(targets, options);
|
|
2978
3066
|
if (lintPaths.length === 0) {
|
|
2979
|
-
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3067
|
+
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
2980
3068
|
}
|
|
2981
3069
|
|
|
2982
3070
|
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
@@ -3041,8 +3129,10 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
|
3041
3129
|
if (!options.deferDiagnosticConfigFiltering) {
|
|
3042
3130
|
report.filePaths = normalizeReportFilePaths(report.filePaths, options);
|
|
3043
3131
|
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
|
|
3132
|
+
report.suppressedDiagnostics = normalizeDiagnosticFilePaths(report.suppressedDiagnostics, options);
|
|
3044
3133
|
report.outputs = normalizeReportOutputs(report.outputs, options);
|
|
3045
3134
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
3135
|
+
report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
|
|
3046
3136
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
3047
3137
|
}
|
|
3048
3138
|
return report;
|
|
@@ -3139,6 +3229,7 @@ function mergeNativeReports(reports) {
|
|
|
3139
3229
|
files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
|
|
3140
3230
|
filePaths: reports.flatMap((item) => item.filePaths ?? []),
|
|
3141
3231
|
diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
|
|
3232
|
+
suppressedDiagnostics: reports.flatMap((item) => item.suppressedDiagnostics ?? []),
|
|
3142
3233
|
outputs: reports.flatMap((item) => item.outputs ?? []),
|
|
3143
3234
|
exitCode: reports.some((item) => item.exitCode) ? 1 : 0
|
|
3144
3235
|
};
|
|
@@ -3171,6 +3262,7 @@ export function lintText(code, options = {}) {
|
|
|
3171
3262
|
files: 0,
|
|
3172
3263
|
filePaths: [],
|
|
3173
3264
|
diagnostics,
|
|
3265
|
+
suppressedDiagnostics: [],
|
|
3174
3266
|
exitCode: exitCodeForDiagnostics(diagnostics)
|
|
3175
3267
|
};
|
|
3176
3268
|
}
|
|
@@ -3192,7 +3284,12 @@ export function lintText(code, options = {}) {
|
|
|
3192
3284
|
...diagnostic,
|
|
3193
3285
|
filePath: requestedPath
|
|
3194
3286
|
}));
|
|
3287
|
+
report.suppressedDiagnostics = (report.suppressedDiagnostics ?? []).map((diagnostic) => ({
|
|
3288
|
+
...diagnostic,
|
|
3289
|
+
filePath: requestedPath
|
|
3290
|
+
}));
|
|
3195
3291
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
3292
|
+
report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
|
|
3196
3293
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
3197
3294
|
return report;
|
|
3198
3295
|
} finally {
|
|
@@ -3698,6 +3795,18 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3698
3795
|
byFile.get(filePath).messages.push(diagnosticToESLintMessage(diagnostic, ruleSeverities));
|
|
3699
3796
|
}
|
|
3700
3797
|
|
|
3798
|
+
for (const diagnostic of report.suppressedDiagnostics ?? []) {
|
|
3799
|
+
const filePath = textOptions.filePath ?? normalizeESLintFilePath(diagnostic.filePath, textOptions.cwd);
|
|
3800
|
+
if (!byFile.has(filePath)) {
|
|
3801
|
+
byFile.set(filePath, emptyESLintResult(filePath, textOptions.source));
|
|
3802
|
+
}
|
|
3803
|
+
const ruleSeverities = textOptions.ruleSeverityForFile?.(filePath) ?? textOptions.ruleSeverities;
|
|
3804
|
+
if (diagnostic.ruleId && ruleSeverities?.get(diagnostic.ruleId) === 0) {
|
|
3805
|
+
continue;
|
|
3806
|
+
}
|
|
3807
|
+
byFile.get(filePath).suppressedMessages.push(suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities));
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3701
3810
|
for (const fixed of report.outputs ?? []) {
|
|
3702
3811
|
const filePath = textOptions.filePath ?? normalizeESLintFilePath(fixed.filePath, textOptions.cwd);
|
|
3703
3812
|
if (!byFile.has(filePath)) {
|
|
@@ -4401,6 +4510,16 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4401
4510
|
return message;
|
|
4402
4511
|
}
|
|
4403
4512
|
|
|
4513
|
+
function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
4514
|
+
return {
|
|
4515
|
+
...diagnosticToESLintMessage(diagnostic, ruleSeverities),
|
|
4516
|
+
suppressions: [{
|
|
4517
|
+
kind: diagnostic.suppression?.kind ?? "directive",
|
|
4518
|
+
justification: diagnostic.suppression?.justification ?? ""
|
|
4519
|
+
}]
|
|
4520
|
+
};
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4404
4523
|
function finalizeESLintResult(result) {
|
|
4405
4524
|
result.errorCount = 0;
|
|
4406
4525
|
result.warningCount = 0;
|
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
|
{
|