@utoo/lint 0.2.8 → 0.3.4
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 +201 -172
- package/bin/fishlint.js +23 -3
- package/bin/migrate.js +555 -39
- package/bin/utoo-lint.js +15 -15
- package/configs/frontend.d.ts +54 -2
- package/configs/frontend.json +16 -1
- package/index.cjs +277 -60
- package/index.d.ts +14 -1
- package/index.js +277 -60
- package/package.json +13 -11
- package/schema.json +89 -36
package/index.js
CHANGED
|
@@ -80,6 +80,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
80
80
|
"block-scoped-var",
|
|
81
81
|
"camelcase",
|
|
82
82
|
"capitalized-comments",
|
|
83
|
+
"class-methods-use-this",
|
|
83
84
|
"complexity",
|
|
84
85
|
"consistent-return",
|
|
85
86
|
"consistent-this",
|
|
@@ -171,6 +172,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
171
172
|
"no-inline-comments",
|
|
172
173
|
"no-inner-declarations",
|
|
173
174
|
"no-invalid-regexp",
|
|
175
|
+
"no-invalid-this",
|
|
174
176
|
"no-irregular-whitespace",
|
|
175
177
|
"no-iterator",
|
|
176
178
|
"no-label-var",
|
|
@@ -179,6 +181,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
179
181
|
"no-lonely-if",
|
|
180
182
|
"no-loop-func",
|
|
181
183
|
"no-loss-of-precision",
|
|
184
|
+
"no-magic-numbers",
|
|
182
185
|
"no-mixed-spaces-and-tabs",
|
|
183
186
|
"no-misleading-character-class",
|
|
184
187
|
"no-multi-assign",
|
|
@@ -237,6 +240,8 @@ const BUILTIN_RULE_IDS = [
|
|
|
237
240
|
"no-underscore-dangle",
|
|
238
241
|
"no-undefined",
|
|
239
242
|
"no-unneeded-ternary",
|
|
243
|
+
"no-unexpected-multiline",
|
|
244
|
+
"no-unmodified-loop-condition",
|
|
240
245
|
"no-unreachable",
|
|
241
246
|
"no-unreachable-loop",
|
|
242
247
|
"no-unsafe-finally",
|
|
@@ -247,6 +252,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
247
252
|
"no-unused-private-class-members",
|
|
248
253
|
"no-unused-vars",
|
|
249
254
|
"no-use-before-define",
|
|
255
|
+
"no-useless-assignment",
|
|
250
256
|
"no-useless-backreference",
|
|
251
257
|
"no-useless-call",
|
|
252
258
|
"no-useless-catch",
|
|
@@ -308,6 +314,24 @@ const BUILTIN_RULE_IDS = [
|
|
|
308
314
|
"import/no-named-as-default-member",
|
|
309
315
|
"import/no-unresolved",
|
|
310
316
|
"import/no-self-import",
|
|
317
|
+
"jest/no-conditional-expect",
|
|
318
|
+
"jest/no-deprecated-functions",
|
|
319
|
+
"jest/no-export",
|
|
320
|
+
"jest/no-focused-tests",
|
|
321
|
+
"jest/no-identical-title",
|
|
322
|
+
"jest/no-interpolation-in-snapshots",
|
|
323
|
+
"jest/no-jasmine-globals",
|
|
324
|
+
"jest/no-mocks-import",
|
|
325
|
+
"jest/no-standalone-expect",
|
|
326
|
+
"jest/valid-describe-callback",
|
|
327
|
+
"jest/valid-expect-in-promise",
|
|
328
|
+
"jest/valid-expect",
|
|
329
|
+
"jest/valid-title",
|
|
330
|
+
"promise/no-promise-in-callback",
|
|
331
|
+
"promise/no-return-in-finally",
|
|
332
|
+
"promise/no-return-wrap",
|
|
333
|
+
"promise/param-names",
|
|
334
|
+
"promise/valid-params",
|
|
311
335
|
"jsx-a11y/alt-text",
|
|
312
336
|
"jsx-a11y/anchor-has-content",
|
|
313
337
|
"jsx-a11y/aria-props",
|
|
@@ -321,6 +345,11 @@ const BUILTIN_RULE_IDS = [
|
|
|
321
345
|
"jsx-a11y/role-has-required-aria-props",
|
|
322
346
|
"jsx-a11y/role-supports-aria-props",
|
|
323
347
|
"jsx-a11y/scope",
|
|
348
|
+
"promise/always-return",
|
|
349
|
+
"promise/catch-or-return",
|
|
350
|
+
"promise/no-callback-in-promise",
|
|
351
|
+
"promise/no-nesting",
|
|
352
|
+
"promise/no-new-statics",
|
|
324
353
|
"react/button-has-type",
|
|
325
354
|
"react/default-props-match-prop-types",
|
|
326
355
|
"react/display-name",
|
|
@@ -342,9 +371,12 @@ const BUILTIN_RULE_IDS = [
|
|
|
342
371
|
"react/no-danger",
|
|
343
372
|
"react/no-danger-with-children",
|
|
344
373
|
"react/no-deprecated",
|
|
374
|
+
"react/no-direct-mutation-state",
|
|
345
375
|
"react/no-find-dom-node",
|
|
376
|
+
"react/no-forward-ref",
|
|
346
377
|
"react/no-is-mounted",
|
|
347
378
|
"react/no-multi-comp",
|
|
379
|
+
"react/no-unstable-nested-components",
|
|
348
380
|
"react/no-redundant-should-component-update",
|
|
349
381
|
"react/no-render-return-value",
|
|
350
382
|
"react/no-string-refs",
|
|
@@ -361,7 +393,9 @@ const BUILTIN_RULE_IDS = [
|
|
|
361
393
|
"react/self-closing-comp",
|
|
362
394
|
"react/style-prop-object",
|
|
363
395
|
"react/void-dom-elements-no-children",
|
|
396
|
+
"react-hooks/exhaustive-deps",
|
|
364
397
|
"react-hooks/rules-of-hooks",
|
|
398
|
+
"unused-imports/no-unused-imports",
|
|
365
399
|
"@typescript-eslint/adjacent-overload-signatures",
|
|
366
400
|
"@typescript-eslint/array-type",
|
|
367
401
|
"@typescript-eslint/ban-ts-comment",
|
|
@@ -379,6 +413,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
379
413
|
"@typescript-eslint/no-dupe-class-members",
|
|
380
414
|
"@typescript-eslint/no-empty-function",
|
|
381
415
|
"@typescript-eslint/no-empty-interface",
|
|
416
|
+
"@typescript-eslint/no-empty-object-type",
|
|
382
417
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
383
418
|
"@typescript-eslint/no-extra-semi",
|
|
384
419
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
@@ -394,6 +429,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
394
429
|
"@typescript-eslint/no-shadow",
|
|
395
430
|
"@typescript-eslint/no-this-alias",
|
|
396
431
|
"@typescript-eslint/no-unsafe-declaration-merging",
|
|
432
|
+
"@typescript-eslint/no-unsafe-function-type",
|
|
397
433
|
"@typescript-eslint/triple-slash-reference",
|
|
398
434
|
"@typescript-eslint/typedef",
|
|
399
435
|
"@typescript-eslint/unified-signatures",
|
|
@@ -437,7 +473,16 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
437
473
|
"semantic-errors"
|
|
438
474
|
];
|
|
439
475
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
440
|
-
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
476
|
+
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
477
|
+
"jest/no-deprecated-functions",
|
|
478
|
+
"jest/no-jasmine-globals",
|
|
479
|
+
"no-extra-semi",
|
|
480
|
+
"@typescript-eslint/no-extra-semi",
|
|
481
|
+
"unused-imports/no-unused-imports"
|
|
482
|
+
]);
|
|
483
|
+
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
484
|
+
"jest/no-focused-tests"
|
|
485
|
+
]);
|
|
441
486
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
442
487
|
|
|
443
488
|
export class UtooLint {
|
|
@@ -747,7 +792,7 @@ function parserOptionsForConfig(config, filePath, cwd) {
|
|
|
747
792
|
|
|
748
793
|
function customRuleEntriesForConfig(config, rules, filePath, cwd) {
|
|
749
794
|
const entries = new Map();
|
|
750
|
-
for (const [ruleId, ruleConfig] of
|
|
795
|
+
for (const [ruleId, ruleConfig] of Object.entries(rulesFromConfig(config, filePath, cwd))) {
|
|
751
796
|
if (!rules.has(ruleId)) {
|
|
752
797
|
continue;
|
|
753
798
|
}
|
|
@@ -804,19 +849,6 @@ function matchingConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
|
804
849
|
return [config];
|
|
805
850
|
}
|
|
806
851
|
|
|
807
|
-
function ruleConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
808
|
-
if (Array.isArray(config)) {
|
|
809
|
-
return config.flatMap((item) => ruleConfigEntries(item, filePath, cwd));
|
|
810
|
-
}
|
|
811
|
-
if (!config || typeof config !== "object" || !config.rules || typeof config.rules !== "object") {
|
|
812
|
-
return [];
|
|
813
|
-
}
|
|
814
|
-
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
815
|
-
return [];
|
|
816
|
-
}
|
|
817
|
-
return Object.entries(config.rules);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
852
|
function configWithoutCustomRules(config, rules) {
|
|
821
853
|
if (Array.isArray(config)) {
|
|
822
854
|
return config.map((item) => configWithoutCustomRules(item, rules));
|
|
@@ -2117,10 +2149,7 @@ function mergeRuleTesterConfig(baseConfig, overrideConfig) {
|
|
|
2117
2149
|
return {
|
|
2118
2150
|
...baseConfig,
|
|
2119
2151
|
...overrideConfig,
|
|
2120
|
-
rules:
|
|
2121
|
-
...(baseConfig.rules ?? {}),
|
|
2122
|
-
...(overrideConfig.rules ?? {})
|
|
2123
|
-
}
|
|
2152
|
+
rules: mergeRuleConfigMaps(baseConfig.rules, overrideConfig.rules)
|
|
2124
2153
|
};
|
|
2125
2154
|
}
|
|
2126
2155
|
|
|
@@ -2579,6 +2608,20 @@ export class CLIEngine {
|
|
|
2579
2608
|
}
|
|
2580
2609
|
}
|
|
2581
2610
|
|
|
2611
|
+
const DEFAULT_NATIVE_MAX_BUFFER = 64 * 1024 * 1024;
|
|
2612
|
+
|
|
2613
|
+
function nativeMaxBuffer(options, env) {
|
|
2614
|
+
const configured = options.maxBuffer ?? env.UTOO_LINT_MAX_BUFFER;
|
|
2615
|
+
if (configured === undefined || configured === "") {
|
|
2616
|
+
return DEFAULT_NATIVE_MAX_BUFFER;
|
|
2617
|
+
}
|
|
2618
|
+
const value = typeof configured === "number" ? configured : Number(configured);
|
|
2619
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
2620
|
+
throw new TypeError("maxBuffer and UTOO_LINT_MAX_BUFFER must be a positive integer byte count");
|
|
2621
|
+
}
|
|
2622
|
+
return value;
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2582
2625
|
export function run(args = [], options = {}) {
|
|
2583
2626
|
const cliArgs = normalizeStringArray(args, "args");
|
|
2584
2627
|
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
@@ -2589,7 +2632,8 @@ export function run(args = [], options = {}) {
|
|
|
2589
2632
|
env,
|
|
2590
2633
|
encoding: options.encoding ?? "utf8",
|
|
2591
2634
|
input: options.input,
|
|
2592
|
-
stdio: options.stdio
|
|
2635
|
+
stdio: options.stdio,
|
|
2636
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
2593
2637
|
});
|
|
2594
2638
|
}
|
|
2595
2639
|
|
|
@@ -2731,8 +2775,9 @@ export function runCli(args = [], options = {}) {
|
|
|
2731
2775
|
extraArgs: parsed.passthroughArgs,
|
|
2732
2776
|
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
2733
2777
|
});
|
|
2734
|
-
const
|
|
2735
|
-
const
|
|
2778
|
+
const usesDefaultTargets = parsed.targets.length === 0;
|
|
2779
|
+
const targets = usesDefaultTargets ? defaultLintTargets(cliOptions) : parsed.targets;
|
|
2780
|
+
const report = lintFiles(targets, { ...cliOptions, useDefaultConfigTargets: usesDefaultTargets });
|
|
2736
2781
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
2737
2782
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
2738
2783
|
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
@@ -2840,7 +2885,8 @@ export function runFishlint(args = [], options = {}) {
|
|
|
2840
2885
|
env,
|
|
2841
2886
|
encoding: options.encoding ?? "utf8",
|
|
2842
2887
|
input: options.input,
|
|
2843
|
-
stdio: options.stdio
|
|
2888
|
+
stdio: options.stdio,
|
|
2889
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
2844
2890
|
});
|
|
2845
2891
|
}
|
|
2846
2892
|
|
|
@@ -3042,9 +3088,13 @@ function booleanFlagValue(arg) {
|
|
|
3042
3088
|
|
|
3043
3089
|
export function lintFiles(paths, options = {}) {
|
|
3044
3090
|
options = withConfigCache(options);
|
|
3091
|
+
const usesDefaultTargets = paths == null || options.useDefaultConfigTargets;
|
|
3045
3092
|
const targets = lintTargetsForInput(paths, options);
|
|
3046
3093
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
3047
|
-
|
|
3094
|
+
let lintPaths = filteredLintPaths(targets, options);
|
|
3095
|
+
if (usesDefaultTargets) {
|
|
3096
|
+
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
3097
|
+
}
|
|
3048
3098
|
if (lintPaths.length === 0) {
|
|
3049
3099
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3050
3100
|
}
|
|
@@ -3134,13 +3184,15 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3134
3184
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
3135
3185
|
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
3136
3186
|
hasConfigSource ||= configured;
|
|
3137
|
-
|
|
3187
|
+
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
3188
|
+
let rules = calculated.rules;
|
|
3189
|
+
const settings = calculated.settings;
|
|
3138
3190
|
if (configured && options.rules) {
|
|
3139
3191
|
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
3140
3192
|
}
|
|
3141
|
-
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
3193
|
+
const signature = configured ? stableConfigSignature({ rules, settings }) : "<native-defaults>";
|
|
3142
3194
|
if (!groups.has(signature)) {
|
|
3143
|
-
groups.set(signature, { paths: [], rules, configured });
|
|
3195
|
+
groups.set(signature, { paths: [], rules, settings, configured });
|
|
3144
3196
|
}
|
|
3145
3197
|
groups.get(signature).paths.push(filePath);
|
|
3146
3198
|
}
|
|
@@ -3170,7 +3222,10 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3170
3222
|
config: undefined,
|
|
3171
3223
|
noConfig: true,
|
|
3172
3224
|
baseConfig: undefined,
|
|
3173
|
-
overrideConfig: {
|
|
3225
|
+
overrideConfig: {
|
|
3226
|
+
rules: allDisabledNativeRules(group.rules),
|
|
3227
|
+
...(group.settings ? { settings: group.settings } : {})
|
|
3228
|
+
},
|
|
3174
3229
|
forceMaterializedConfig: true
|
|
3175
3230
|
}
|
|
3176
3231
|
};
|
|
@@ -3399,12 +3454,12 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
3399
3454
|
);
|
|
3400
3455
|
return {
|
|
3401
3456
|
...configData,
|
|
3402
|
-
rules:
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3457
|
+
rules: mergeRuleConfigMaps(
|
|
3458
|
+
rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
3459
|
+
rulesFromFileConfig(options, filePath),
|
|
3460
|
+
rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
3461
|
+
rulesFromNativeRuleList(options.rules)
|
|
3462
|
+
)
|
|
3408
3463
|
};
|
|
3409
3464
|
}
|
|
3410
3465
|
|
|
@@ -3499,10 +3554,10 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
3499
3554
|
return {};
|
|
3500
3555
|
}
|
|
3501
3556
|
if (Array.isArray(config)) {
|
|
3502
|
-
return config.reduce(
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3557
|
+
return config.reduce(
|
|
3558
|
+
(rules, entry) => mergeRuleConfigMaps(rules, rulesFromConfig(entry, filePath, cwd)),
|
|
3559
|
+
{}
|
|
3560
|
+
);
|
|
3506
3561
|
}
|
|
3507
3562
|
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
3508
3563
|
return {};
|
|
@@ -3555,12 +3610,64 @@ function defaultLintTargets(options = {}) {
|
|
|
3555
3610
|
return ["."];
|
|
3556
3611
|
}
|
|
3557
3612
|
|
|
3558
|
-
const
|
|
3613
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3614
|
+
if (configHasUnscopedRules(config)) {
|
|
3615
|
+
return ["."];
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
const targets = filePatternsFromConfig(config);
|
|
3559
3619
|
return targets.length > 0
|
|
3560
3620
|
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
3561
3621
|
: ["."];
|
|
3562
3622
|
}
|
|
3563
3623
|
|
|
3624
|
+
function filterDefaultConfigLintPaths(paths, options) {
|
|
3625
|
+
const configPath = configPathForOptions(options);
|
|
3626
|
+
if (!configPath) {
|
|
3627
|
+
return paths;
|
|
3628
|
+
}
|
|
3629
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3630
|
+
if (!configHasFileSelectors(config)) {
|
|
3631
|
+
return paths;
|
|
3632
|
+
}
|
|
3633
|
+
const cwd = dirname(configPath);
|
|
3634
|
+
return paths.filter((filePath) => configSelectsFile(config, filePath, cwd));
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3637
|
+
function configHasFileSelectors(config) {
|
|
3638
|
+
if (Array.isArray(config)) {
|
|
3639
|
+
return config.some(configHasFileSelectors);
|
|
3640
|
+
}
|
|
3641
|
+
return Boolean(config && typeof config === "object" && normalizeConfigFileSelectors(config.files).length > 0);
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
function configHasUnscopedRules(config) {
|
|
3645
|
+
if (Array.isArray(config)) {
|
|
3646
|
+
return config.some(configHasUnscopedRules);
|
|
3647
|
+
}
|
|
3648
|
+
return Boolean(
|
|
3649
|
+
config &&
|
|
3650
|
+
typeof config === "object" &&
|
|
3651
|
+
normalizeConfigFileSelectors(config.files).length === 0 &&
|
|
3652
|
+
config.rules &&
|
|
3653
|
+
typeof config.rules === "object" &&
|
|
3654
|
+
Object.keys(config.rules).length > 0
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3658
|
+
function configSelectsFile(config, filePath, cwd) {
|
|
3659
|
+
if (Array.isArray(config)) {
|
|
3660
|
+
return config.some((entry) => configSelectsFile(entry, filePath, cwd));
|
|
3661
|
+
}
|
|
3662
|
+
if (!config || typeof config !== "object") {
|
|
3663
|
+
return false;
|
|
3664
|
+
}
|
|
3665
|
+
const selectors = normalizeConfigFileSelectors(config.files);
|
|
3666
|
+
return selectors.length > 0
|
|
3667
|
+
? configAppliesToFile(config, filePath, cwd)
|
|
3668
|
+
: configHasUnscopedRules(config) && configAppliesToFile(config, filePath, cwd);
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3564
3671
|
function resolveConfigPattern(pattern, configDirectory) {
|
|
3565
3672
|
if (isAbsolute(pattern)) {
|
|
3566
3673
|
return pattern;
|
|
@@ -3584,8 +3691,10 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
3584
3691
|
}
|
|
3585
3692
|
|
|
3586
3693
|
const normalized = normalizeIgnoredPath(filePath, cwd ?? process.cwd());
|
|
3587
|
-
const files =
|
|
3588
|
-
if (files.length > 0 && !files.some((
|
|
3694
|
+
const files = normalizeConfigFileSelectors(config.files);
|
|
3695
|
+
if (files.length > 0 && !files.some((selector) => selector.every(
|
|
3696
|
+
(pattern) => matchesConfigFilePattern(normalized, normalizeIgnoredPattern(pattern))
|
|
3697
|
+
))) {
|
|
3589
3698
|
return false;
|
|
3590
3699
|
}
|
|
3591
3700
|
|
|
@@ -3593,6 +3702,23 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
3593
3702
|
return !pathIgnoredByPatterns(normalized, ignores);
|
|
3594
3703
|
}
|
|
3595
3704
|
|
|
3705
|
+
function normalizeConfigFileSelectors(patterns) {
|
|
3706
|
+
if (!patterns) {
|
|
3707
|
+
return [];
|
|
3708
|
+
}
|
|
3709
|
+
const values = Array.isArray(patterns) ? patterns : [patterns];
|
|
3710
|
+
return values.flatMap((value) => {
|
|
3711
|
+
if (typeof value === "string") {
|
|
3712
|
+
return [[value]];
|
|
3713
|
+
}
|
|
3714
|
+
if (Array.isArray(value)) {
|
|
3715
|
+
const selector = normalizeConfigPatterns(value);
|
|
3716
|
+
return selector.length > 0 ? [selector] : [];
|
|
3717
|
+
}
|
|
3718
|
+
return [];
|
|
3719
|
+
});
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3596
3722
|
function normalizeConfigPatterns(patterns) {
|
|
3597
3723
|
if (!patterns) {
|
|
3598
3724
|
return [];
|
|
@@ -3654,7 +3780,15 @@ function withTemporaryConfig(options, callback) {
|
|
|
3654
3780
|
const rules = shouldMaterializeFileConfig
|
|
3655
3781
|
? materializedRulesFromConfigs(...configs)
|
|
3656
3782
|
: runtimeRulesFromConfigs(...configs);
|
|
3657
|
-
|
|
3783
|
+
const settings = configs.reduce(
|
|
3784
|
+
(result, config) => ({
|
|
3785
|
+
...result,
|
|
3786
|
+
...(configDataFromConfig(config, options.filePath ?? options.filename, options.cwd).settings ?? {})
|
|
3787
|
+
}),
|
|
3788
|
+
{}
|
|
3789
|
+
);
|
|
3790
|
+
const hasSettings = Object.keys(settings).length > 0;
|
|
3791
|
+
if (Object.keys(rules).length === 0 && !hasSettings) {
|
|
3658
3792
|
if (shouldMaterializeFileConfig) {
|
|
3659
3793
|
return callback({
|
|
3660
3794
|
...options,
|
|
@@ -3666,7 +3800,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
3666
3800
|
}
|
|
3667
3801
|
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
3668
3802
|
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
3669
|
-
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3803
|
+
if (!shouldMaterializeFileConfig && !hasSettings && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3670
3804
|
return callback({
|
|
3671
3805
|
...options,
|
|
3672
3806
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -3678,7 +3812,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
3678
3812
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
3679
3813
|
const configPath = join(tmp, "utlint.config.json");
|
|
3680
3814
|
try {
|
|
3681
|
-
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
3815
|
+
writeFileSync(configPath, JSON.stringify({ rules, ...(hasSettings ? { settings } : {}) }));
|
|
3682
3816
|
return callback({
|
|
3683
3817
|
...options,
|
|
3684
3818
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
@@ -3697,11 +3831,7 @@ function enabledRuleNames(rules) {
|
|
|
3697
3831
|
}
|
|
3698
3832
|
|
|
3699
3833
|
function runtimeRulesFromConfigs(...configs) {
|
|
3700
|
-
|
|
3701
|
-
for (const config of configs) {
|
|
3702
|
-
Object.assign(rules, runtimeRulesFromConfig(config));
|
|
3703
|
-
}
|
|
3704
|
-
return rules;
|
|
3834
|
+
return mergeRuleConfigMaps(...configs.map(runtimeRulesFromConfig));
|
|
3705
3835
|
}
|
|
3706
3836
|
|
|
3707
3837
|
function materializedRulesFromConfigs(...configs) {
|
|
@@ -3713,10 +3843,10 @@ function runtimeRulesFromConfig(config) {
|
|
|
3713
3843
|
return {};
|
|
3714
3844
|
}
|
|
3715
3845
|
if (Array.isArray(config)) {
|
|
3716
|
-
return config.reduce(
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3846
|
+
return config.reduce(
|
|
3847
|
+
(rules, entry) => mergeRuleConfigMaps(rules, runtimeRulesFromConfig(entry)),
|
|
3848
|
+
{}
|
|
3849
|
+
);
|
|
3720
3850
|
}
|
|
3721
3851
|
|
|
3722
3852
|
const rules = {};
|
|
@@ -3726,6 +3856,26 @@ function runtimeRulesFromConfig(config) {
|
|
|
3726
3856
|
return rules;
|
|
3727
3857
|
}
|
|
3728
3858
|
|
|
3859
|
+
function mergeRuleConfigMaps(...ruleMaps) {
|
|
3860
|
+
const result = {};
|
|
3861
|
+
for (const rules of ruleMaps) {
|
|
3862
|
+
for (const [ruleId, ruleConfig] of Object.entries(rules ?? {})) {
|
|
3863
|
+
const previous = result[ruleId];
|
|
3864
|
+
if (previous !== undefined && isSeverityOnlyRuleConfig(ruleConfig) && Array.isArray(previous) && previous.length > 1) {
|
|
3865
|
+
const severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
3866
|
+
result[ruleId] = [severity, ...previous.slice(1)];
|
|
3867
|
+
} else {
|
|
3868
|
+
result[ruleId] = ruleConfig;
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
return result;
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
function isSeverityOnlyRuleConfig(ruleConfig) {
|
|
3876
|
+
return !Array.isArray(ruleConfig) || ruleConfig.length === 1;
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3729
3879
|
function enabledRuleNamesFromConfigs(...configs) {
|
|
3730
3880
|
const rules = new Set();
|
|
3731
3881
|
for (const config of configs) {
|
|
@@ -4040,7 +4190,7 @@ function collectGlobFiles(target, cwd, patterns, expression, files) {
|
|
|
4040
4190
|
|
|
4041
4191
|
const child = join(target, entry.name);
|
|
4042
4192
|
if (entry.isDirectory()) {
|
|
4043
|
-
if (
|
|
4193
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4044
4194
|
collectGlobFiles(child, cwd, patterns, expression, files);
|
|
4045
4195
|
}
|
|
4046
4196
|
continue;
|
|
@@ -4110,7 +4260,7 @@ function expandLintTarget(target, cwd, patterns) {
|
|
|
4110
4260
|
if (stat.isFile()) {
|
|
4111
4261
|
return isLintableFilePath(target) && !pathIgnoredByPatterns(normalizeIgnoredPath(target, cwd), patterns) ? [target] : [];
|
|
4112
4262
|
}
|
|
4113
|
-
if (!stat.isDirectory() ||
|
|
4263
|
+
if (!stat.isDirectory() || !shouldTraverseDirectory(normalizeIgnoredPath(target, cwd), patterns)) {
|
|
4114
4264
|
return [];
|
|
4115
4265
|
}
|
|
4116
4266
|
|
|
@@ -4128,7 +4278,7 @@ function collectLintableFiles(target, cwd, patterns, files) {
|
|
|
4128
4278
|
|
|
4129
4279
|
const child = join(target, entry.name);
|
|
4130
4280
|
if (entry.isDirectory()) {
|
|
4131
|
-
if (
|
|
4281
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4132
4282
|
collectLintableFiles(child, cwd, patterns, files);
|
|
4133
4283
|
}
|
|
4134
4284
|
continue;
|
|
@@ -4261,7 +4411,7 @@ function normalizeIgnoredPath(filePath, cwd) {
|
|
|
4261
4411
|
}
|
|
4262
4412
|
|
|
4263
4413
|
function normalizeIgnoredPattern(pattern) {
|
|
4264
|
-
return normalizePath(pattern.replace(/^!/, "")
|
|
4414
|
+
return normalizePath(pattern.replace(/^!/, "")).replace(/\/+$/, "");
|
|
4265
4415
|
}
|
|
4266
4416
|
|
|
4267
4417
|
function pathIgnoredByPatterns(target, patterns) {
|
|
@@ -4275,10 +4425,55 @@ function pathIgnoredByPatterns(target, patterns) {
|
|
|
4275
4425
|
return ignored;
|
|
4276
4426
|
}
|
|
4277
4427
|
|
|
4428
|
+
function shouldTraverseDirectory(target, patterns) {
|
|
4429
|
+
return !pathIgnoredByPatterns(target, patterns) || patterns.some(
|
|
4430
|
+
(pattern) => pattern.startsWith("!") && negatedPatternMayMatchDescendant(target, pattern)
|
|
4431
|
+
);
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4434
|
+
function negatedPatternMayMatchDescendant(target, pattern) {
|
|
4435
|
+
pattern = normalizeIgnoredPattern(pattern);
|
|
4436
|
+
if (pattern.startsWith("/")) {
|
|
4437
|
+
pattern = pattern.slice(1);
|
|
4438
|
+
if (target.startsWith("/")) {
|
|
4439
|
+
target = target.slice(1);
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
if (!pattern.includes("/")) {
|
|
4443
|
+
return true;
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
const directoryPattern = pattern.slice(0, pattern.lastIndexOf("/"));
|
|
4447
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4448
|
+
const directoryExpression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4449
|
+
if (directoryExpression.test(target)) {
|
|
4450
|
+
return true;
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
|
|
4454
|
+
const globIndex = pattern.search(/[*?[{]/u);
|
|
4455
|
+
const staticPrefix = (globIndex === -1 ? pattern : pattern.slice(0, globIndex)).replace(/\/+$/u, "");
|
|
4456
|
+
return !staticPrefix ||
|
|
4457
|
+
staticPrefix === target ||
|
|
4458
|
+
staticPrefix.startsWith(`${target}/`) ||
|
|
4459
|
+
target.startsWith(`${staticPrefix}/`);
|
|
4460
|
+
}
|
|
4461
|
+
|
|
4278
4462
|
function matchesIgnorePattern(target, pattern) {
|
|
4463
|
+
const anchored = pattern.startsWith("/");
|
|
4464
|
+
if (anchored) {
|
|
4465
|
+
pattern = pattern.slice(1);
|
|
4466
|
+
if (target.startsWith("/")) {
|
|
4467
|
+
target = target.slice(1);
|
|
4468
|
+
}
|
|
4469
|
+
}
|
|
4279
4470
|
if (pattern.endsWith("/**")) {
|
|
4280
|
-
const
|
|
4281
|
-
|
|
4471
|
+
const directoryPattern = pattern.slice(0, -3);
|
|
4472
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4473
|
+
const expression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4474
|
+
return expression.test(target);
|
|
4475
|
+
}
|
|
4476
|
+
return target === directoryPattern || target.startsWith(`${directoryPattern}/`);
|
|
4282
4477
|
}
|
|
4283
4478
|
if (pattern.startsWith("**/")) {
|
|
4284
4479
|
const suffix = pattern.slice(3);
|
|
@@ -4287,10 +4482,14 @@ function matchesIgnorePattern(target, pattern) {
|
|
|
4287
4482
|
}
|
|
4288
4483
|
}
|
|
4289
4484
|
if (!hasGlobSyntax(pattern)) {
|
|
4485
|
+
if (anchored || pattern.includes("/")) {
|
|
4486
|
+
return target === pattern || target.startsWith(`${pattern}/`);
|
|
4487
|
+
}
|
|
4290
4488
|
return target === pattern || target.endsWith(`/${pattern}`) || target.startsWith(`${pattern}/`);
|
|
4291
4489
|
}
|
|
4292
4490
|
|
|
4293
|
-
const
|
|
4491
|
+
const prefix = anchored || pattern.includes("/") ? "^" : "(^|/)";
|
|
4492
|
+
const expression = new RegExp(`${prefix}${globPatternRegExpSource(pattern)}$`);
|
|
4294
4493
|
return expression.test(target);
|
|
4295
4494
|
}
|
|
4296
4495
|
|
|
@@ -4399,6 +4598,9 @@ function ruleMetaForRuleId(ruleId) {
|
|
|
4399
4598
|
if (FIXABLE_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4400
4599
|
meta.fixable = "code";
|
|
4401
4600
|
}
|
|
4601
|
+
if (SUGGESTION_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4602
|
+
meta.hasSuggestions = true;
|
|
4603
|
+
}
|
|
4402
4604
|
return meta;
|
|
4403
4605
|
}
|
|
4404
4606
|
|
|
@@ -4489,6 +4691,21 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4489
4691
|
if (fixes.length > 0) {
|
|
4490
4692
|
message.fix = fixes.length === 1 ? fixes[0] : fixes;
|
|
4491
4693
|
}
|
|
4694
|
+
const suggestions = (diagnostic.suggestions ?? []).map((suggestion) => {
|
|
4695
|
+
const suggestionFixes = (suggestion.fix ?? []).map((fix) => ({
|
|
4696
|
+
range: fix.range,
|
|
4697
|
+
text: fix.text
|
|
4698
|
+
}));
|
|
4699
|
+
return {
|
|
4700
|
+
desc: suggestion.desc,
|
|
4701
|
+
...(suggestionFixes.length === 0 ? {} : {
|
|
4702
|
+
fix: suggestionFixes.length === 1 ? suggestionFixes[0] : suggestionFixes
|
|
4703
|
+
})
|
|
4704
|
+
};
|
|
4705
|
+
});
|
|
4706
|
+
if (suggestions.length > 0) {
|
|
4707
|
+
message.suggestions = suggestions;
|
|
4708
|
+
}
|
|
4492
4709
|
return message;
|
|
4493
4710
|
}
|
|
4494
4711
|
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utoo/lint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.4",
|
|
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,13 +76,15 @@
|
|
|
76
76
|
"use-at-your-own-risk.js"
|
|
77
77
|
],
|
|
78
78
|
"optionalDependencies": {
|
|
79
|
-
"@utoo/lint-darwin-arm64": "0.
|
|
80
|
-
"@utoo/lint-darwin-x64": "0.
|
|
81
|
-
"@utoo/lint-linux-arm64": "0.
|
|
82
|
-
"@utoo/lint-linux-x64": "0.
|
|
83
|
-
"@utoo/lint-win32-x64": "0.
|
|
79
|
+
"@utoo/lint-darwin-arm64": "0.3.4",
|
|
80
|
+
"@utoo/lint-darwin-x64": "0.3.4",
|
|
81
|
+
"@utoo/lint-linux-arm64": "0.3.4",
|
|
82
|
+
"@utoo/lint-linux-x64": "0.3.4",
|
|
83
|
+
"@utoo/lint-win32-x64": "0.3.4"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
+
"@eslint/eslintrc": "2.1.4",
|
|
87
|
+
"@eslint/js": "8.57.1",
|
|
86
88
|
"jiti": "2.7.0"
|
|
87
89
|
},
|
|
88
90
|
"publishConfig": {
|