@utoo/lint 0.2.9 → 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 +41 -11
- package/bin/fishlint.js +23 -3
- package/bin/migrate.js +476 -10
- package/bin/utoo-lint.js +15 -15
- package/configs/frontend.d.ts +54 -2
- package/configs/frontend.json +15 -0
- package/index.cjs +258 -59
- package/index.d.ts +14 -1
- package/index.js +258 -59
- package/package.json +8 -6
- package/schema.json +41 -1
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,19 @@ 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",
|
|
311
330
|
"promise/no-promise-in-callback",
|
|
312
331
|
"promise/no-return-in-finally",
|
|
313
332
|
"promise/no-return-wrap",
|
|
@@ -352,9 +371,12 @@ const BUILTIN_RULE_IDS = [
|
|
|
352
371
|
"react/no-danger",
|
|
353
372
|
"react/no-danger-with-children",
|
|
354
373
|
"react/no-deprecated",
|
|
374
|
+
"react/no-direct-mutation-state",
|
|
355
375
|
"react/no-find-dom-node",
|
|
376
|
+
"react/no-forward-ref",
|
|
356
377
|
"react/no-is-mounted",
|
|
357
378
|
"react/no-multi-comp",
|
|
379
|
+
"react/no-unstable-nested-components",
|
|
358
380
|
"react/no-redundant-should-component-update",
|
|
359
381
|
"react/no-render-return-value",
|
|
360
382
|
"react/no-string-refs",
|
|
@@ -452,10 +474,15 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
452
474
|
];
|
|
453
475
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
454
476
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
477
|
+
"jest/no-deprecated-functions",
|
|
478
|
+
"jest/no-jasmine-globals",
|
|
455
479
|
"no-extra-semi",
|
|
456
480
|
"@typescript-eslint/no-extra-semi",
|
|
457
481
|
"unused-imports/no-unused-imports"
|
|
458
482
|
]);
|
|
483
|
+
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
484
|
+
"jest/no-focused-tests"
|
|
485
|
+
]);
|
|
459
486
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
460
487
|
|
|
461
488
|
export class UtooLint {
|
|
@@ -765,7 +792,7 @@ function parserOptionsForConfig(config, filePath, cwd) {
|
|
|
765
792
|
|
|
766
793
|
function customRuleEntriesForConfig(config, rules, filePath, cwd) {
|
|
767
794
|
const entries = new Map();
|
|
768
|
-
for (const [ruleId, ruleConfig] of
|
|
795
|
+
for (const [ruleId, ruleConfig] of Object.entries(rulesFromConfig(config, filePath, cwd))) {
|
|
769
796
|
if (!rules.has(ruleId)) {
|
|
770
797
|
continue;
|
|
771
798
|
}
|
|
@@ -822,19 +849,6 @@ function matchingConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
|
822
849
|
return [config];
|
|
823
850
|
}
|
|
824
851
|
|
|
825
|
-
function ruleConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
826
|
-
if (Array.isArray(config)) {
|
|
827
|
-
return config.flatMap((item) => ruleConfigEntries(item, filePath, cwd));
|
|
828
|
-
}
|
|
829
|
-
if (!config || typeof config !== "object" || !config.rules || typeof config.rules !== "object") {
|
|
830
|
-
return [];
|
|
831
|
-
}
|
|
832
|
-
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
833
|
-
return [];
|
|
834
|
-
}
|
|
835
|
-
return Object.entries(config.rules);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
852
|
function configWithoutCustomRules(config, rules) {
|
|
839
853
|
if (Array.isArray(config)) {
|
|
840
854
|
return config.map((item) => configWithoutCustomRules(item, rules));
|
|
@@ -2135,10 +2149,7 @@ function mergeRuleTesterConfig(baseConfig, overrideConfig) {
|
|
|
2135
2149
|
return {
|
|
2136
2150
|
...baseConfig,
|
|
2137
2151
|
...overrideConfig,
|
|
2138
|
-
rules:
|
|
2139
|
-
...(baseConfig.rules ?? {}),
|
|
2140
|
-
...(overrideConfig.rules ?? {})
|
|
2141
|
-
}
|
|
2152
|
+
rules: mergeRuleConfigMaps(baseConfig.rules, overrideConfig.rules)
|
|
2142
2153
|
};
|
|
2143
2154
|
}
|
|
2144
2155
|
|
|
@@ -2597,6 +2608,20 @@ export class CLIEngine {
|
|
|
2597
2608
|
}
|
|
2598
2609
|
}
|
|
2599
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
|
+
|
|
2600
2625
|
export function run(args = [], options = {}) {
|
|
2601
2626
|
const cliArgs = normalizeStringArray(args, "args");
|
|
2602
2627
|
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
@@ -2607,7 +2632,8 @@ export function run(args = [], options = {}) {
|
|
|
2607
2632
|
env,
|
|
2608
2633
|
encoding: options.encoding ?? "utf8",
|
|
2609
2634
|
input: options.input,
|
|
2610
|
-
stdio: options.stdio
|
|
2635
|
+
stdio: options.stdio,
|
|
2636
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
2611
2637
|
});
|
|
2612
2638
|
}
|
|
2613
2639
|
|
|
@@ -2749,8 +2775,9 @@ export function runCli(args = [], options = {}) {
|
|
|
2749
2775
|
extraArgs: parsed.passthroughArgs,
|
|
2750
2776
|
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
2751
2777
|
});
|
|
2752
|
-
const
|
|
2753
|
-
const
|
|
2778
|
+
const usesDefaultTargets = parsed.targets.length === 0;
|
|
2779
|
+
const targets = usesDefaultTargets ? defaultLintTargets(cliOptions) : parsed.targets;
|
|
2780
|
+
const report = lintFiles(targets, { ...cliOptions, useDefaultConfigTargets: usesDefaultTargets });
|
|
2754
2781
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
2755
2782
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
2756
2783
|
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
@@ -2858,7 +2885,8 @@ export function runFishlint(args = [], options = {}) {
|
|
|
2858
2885
|
env,
|
|
2859
2886
|
encoding: options.encoding ?? "utf8",
|
|
2860
2887
|
input: options.input,
|
|
2861
|
-
stdio: options.stdio
|
|
2888
|
+
stdio: options.stdio,
|
|
2889
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
2862
2890
|
});
|
|
2863
2891
|
}
|
|
2864
2892
|
|
|
@@ -3060,9 +3088,13 @@ function booleanFlagValue(arg) {
|
|
|
3060
3088
|
|
|
3061
3089
|
export function lintFiles(paths, options = {}) {
|
|
3062
3090
|
options = withConfigCache(options);
|
|
3091
|
+
const usesDefaultTargets = paths == null || options.useDefaultConfigTargets;
|
|
3063
3092
|
const targets = lintTargetsForInput(paths, options);
|
|
3064
3093
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
3065
|
-
|
|
3094
|
+
let lintPaths = filteredLintPaths(targets, options);
|
|
3095
|
+
if (usesDefaultTargets) {
|
|
3096
|
+
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
3097
|
+
}
|
|
3066
3098
|
if (lintPaths.length === 0) {
|
|
3067
3099
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3068
3100
|
}
|
|
@@ -3152,13 +3184,15 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3152
3184
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
3153
3185
|
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
3154
3186
|
hasConfigSource ||= configured;
|
|
3155
|
-
|
|
3187
|
+
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
3188
|
+
let rules = calculated.rules;
|
|
3189
|
+
const settings = calculated.settings;
|
|
3156
3190
|
if (configured && options.rules) {
|
|
3157
3191
|
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
3158
3192
|
}
|
|
3159
|
-
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
3193
|
+
const signature = configured ? stableConfigSignature({ rules, settings }) : "<native-defaults>";
|
|
3160
3194
|
if (!groups.has(signature)) {
|
|
3161
|
-
groups.set(signature, { paths: [], rules, configured });
|
|
3195
|
+
groups.set(signature, { paths: [], rules, settings, configured });
|
|
3162
3196
|
}
|
|
3163
3197
|
groups.get(signature).paths.push(filePath);
|
|
3164
3198
|
}
|
|
@@ -3188,7 +3222,10 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3188
3222
|
config: undefined,
|
|
3189
3223
|
noConfig: true,
|
|
3190
3224
|
baseConfig: undefined,
|
|
3191
|
-
overrideConfig: {
|
|
3225
|
+
overrideConfig: {
|
|
3226
|
+
rules: allDisabledNativeRules(group.rules),
|
|
3227
|
+
...(group.settings ? { settings: group.settings } : {})
|
|
3228
|
+
},
|
|
3192
3229
|
forceMaterializedConfig: true
|
|
3193
3230
|
}
|
|
3194
3231
|
};
|
|
@@ -3417,12 +3454,12 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
3417
3454
|
);
|
|
3418
3455
|
return {
|
|
3419
3456
|
...configData,
|
|
3420
|
-
rules:
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
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
|
+
)
|
|
3426
3463
|
};
|
|
3427
3464
|
}
|
|
3428
3465
|
|
|
@@ -3517,10 +3554,10 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
3517
3554
|
return {};
|
|
3518
3555
|
}
|
|
3519
3556
|
if (Array.isArray(config)) {
|
|
3520
|
-
return config.reduce(
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3557
|
+
return config.reduce(
|
|
3558
|
+
(rules, entry) => mergeRuleConfigMaps(rules, rulesFromConfig(entry, filePath, cwd)),
|
|
3559
|
+
{}
|
|
3560
|
+
);
|
|
3524
3561
|
}
|
|
3525
3562
|
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
3526
3563
|
return {};
|
|
@@ -3573,12 +3610,64 @@ function defaultLintTargets(options = {}) {
|
|
|
3573
3610
|
return ["."];
|
|
3574
3611
|
}
|
|
3575
3612
|
|
|
3576
|
-
const
|
|
3613
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3614
|
+
if (configHasUnscopedRules(config)) {
|
|
3615
|
+
return ["."];
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
const targets = filePatternsFromConfig(config);
|
|
3577
3619
|
return targets.length > 0
|
|
3578
3620
|
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
3579
3621
|
: ["."];
|
|
3580
3622
|
}
|
|
3581
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
|
+
|
|
3582
3671
|
function resolveConfigPattern(pattern, configDirectory) {
|
|
3583
3672
|
if (isAbsolute(pattern)) {
|
|
3584
3673
|
return pattern;
|
|
@@ -3602,8 +3691,10 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
3602
3691
|
}
|
|
3603
3692
|
|
|
3604
3693
|
const normalized = normalizeIgnoredPath(filePath, cwd ?? process.cwd());
|
|
3605
|
-
const files =
|
|
3606
|
-
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
|
+
))) {
|
|
3607
3698
|
return false;
|
|
3608
3699
|
}
|
|
3609
3700
|
|
|
@@ -3611,6 +3702,23 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
3611
3702
|
return !pathIgnoredByPatterns(normalized, ignores);
|
|
3612
3703
|
}
|
|
3613
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
|
+
|
|
3614
3722
|
function normalizeConfigPatterns(patterns) {
|
|
3615
3723
|
if (!patterns) {
|
|
3616
3724
|
return [];
|
|
@@ -3672,7 +3780,15 @@ function withTemporaryConfig(options, callback) {
|
|
|
3672
3780
|
const rules = shouldMaterializeFileConfig
|
|
3673
3781
|
? materializedRulesFromConfigs(...configs)
|
|
3674
3782
|
: runtimeRulesFromConfigs(...configs);
|
|
3675
|
-
|
|
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) {
|
|
3676
3792
|
if (shouldMaterializeFileConfig) {
|
|
3677
3793
|
return callback({
|
|
3678
3794
|
...options,
|
|
@@ -3684,7 +3800,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
3684
3800
|
}
|
|
3685
3801
|
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
3686
3802
|
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
3687
|
-
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3803
|
+
if (!shouldMaterializeFileConfig && !hasSettings && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3688
3804
|
return callback({
|
|
3689
3805
|
...options,
|
|
3690
3806
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -3696,7 +3812,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
3696
3812
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
3697
3813
|
const configPath = join(tmp, "utlint.config.json");
|
|
3698
3814
|
try {
|
|
3699
|
-
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
3815
|
+
writeFileSync(configPath, JSON.stringify({ rules, ...(hasSettings ? { settings } : {}) }));
|
|
3700
3816
|
return callback({
|
|
3701
3817
|
...options,
|
|
3702
3818
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
@@ -3715,11 +3831,7 @@ function enabledRuleNames(rules) {
|
|
|
3715
3831
|
}
|
|
3716
3832
|
|
|
3717
3833
|
function runtimeRulesFromConfigs(...configs) {
|
|
3718
|
-
|
|
3719
|
-
for (const config of configs) {
|
|
3720
|
-
Object.assign(rules, runtimeRulesFromConfig(config));
|
|
3721
|
-
}
|
|
3722
|
-
return rules;
|
|
3834
|
+
return mergeRuleConfigMaps(...configs.map(runtimeRulesFromConfig));
|
|
3723
3835
|
}
|
|
3724
3836
|
|
|
3725
3837
|
function materializedRulesFromConfigs(...configs) {
|
|
@@ -3731,10 +3843,10 @@ function runtimeRulesFromConfig(config) {
|
|
|
3731
3843
|
return {};
|
|
3732
3844
|
}
|
|
3733
3845
|
if (Array.isArray(config)) {
|
|
3734
|
-
return config.reduce(
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3846
|
+
return config.reduce(
|
|
3847
|
+
(rules, entry) => mergeRuleConfigMaps(rules, runtimeRulesFromConfig(entry)),
|
|
3848
|
+
{}
|
|
3849
|
+
);
|
|
3738
3850
|
}
|
|
3739
3851
|
|
|
3740
3852
|
const rules = {};
|
|
@@ -3744,6 +3856,26 @@ function runtimeRulesFromConfig(config) {
|
|
|
3744
3856
|
return rules;
|
|
3745
3857
|
}
|
|
3746
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
|
+
|
|
3747
3879
|
function enabledRuleNamesFromConfigs(...configs) {
|
|
3748
3880
|
const rules = new Set();
|
|
3749
3881
|
for (const config of configs) {
|
|
@@ -4058,7 +4190,7 @@ function collectGlobFiles(target, cwd, patterns, expression, files) {
|
|
|
4058
4190
|
|
|
4059
4191
|
const child = join(target, entry.name);
|
|
4060
4192
|
if (entry.isDirectory()) {
|
|
4061
|
-
if (
|
|
4193
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4062
4194
|
collectGlobFiles(child, cwd, patterns, expression, files);
|
|
4063
4195
|
}
|
|
4064
4196
|
continue;
|
|
@@ -4128,7 +4260,7 @@ function expandLintTarget(target, cwd, patterns) {
|
|
|
4128
4260
|
if (stat.isFile()) {
|
|
4129
4261
|
return isLintableFilePath(target) && !pathIgnoredByPatterns(normalizeIgnoredPath(target, cwd), patterns) ? [target] : [];
|
|
4130
4262
|
}
|
|
4131
|
-
if (!stat.isDirectory() ||
|
|
4263
|
+
if (!stat.isDirectory() || !shouldTraverseDirectory(normalizeIgnoredPath(target, cwd), patterns)) {
|
|
4132
4264
|
return [];
|
|
4133
4265
|
}
|
|
4134
4266
|
|
|
@@ -4146,7 +4278,7 @@ function collectLintableFiles(target, cwd, patterns, files) {
|
|
|
4146
4278
|
|
|
4147
4279
|
const child = join(target, entry.name);
|
|
4148
4280
|
if (entry.isDirectory()) {
|
|
4149
|
-
if (
|
|
4281
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4150
4282
|
collectLintableFiles(child, cwd, patterns, files);
|
|
4151
4283
|
}
|
|
4152
4284
|
continue;
|
|
@@ -4279,7 +4411,7 @@ function normalizeIgnoredPath(filePath, cwd) {
|
|
|
4279
4411
|
}
|
|
4280
4412
|
|
|
4281
4413
|
function normalizeIgnoredPattern(pattern) {
|
|
4282
|
-
return normalizePath(pattern.replace(/^!/, "")
|
|
4414
|
+
return normalizePath(pattern.replace(/^!/, "")).replace(/\/+$/, "");
|
|
4283
4415
|
}
|
|
4284
4416
|
|
|
4285
4417
|
function pathIgnoredByPatterns(target, patterns) {
|
|
@@ -4293,10 +4425,55 @@ function pathIgnoredByPatterns(target, patterns) {
|
|
|
4293
4425
|
return ignored;
|
|
4294
4426
|
}
|
|
4295
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
|
+
|
|
4296
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
|
+
}
|
|
4297
4470
|
if (pattern.endsWith("/**")) {
|
|
4298
|
-
const
|
|
4299
|
-
|
|
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}/`);
|
|
4300
4477
|
}
|
|
4301
4478
|
if (pattern.startsWith("**/")) {
|
|
4302
4479
|
const suffix = pattern.slice(3);
|
|
@@ -4305,10 +4482,14 @@ function matchesIgnorePattern(target, pattern) {
|
|
|
4305
4482
|
}
|
|
4306
4483
|
}
|
|
4307
4484
|
if (!hasGlobSyntax(pattern)) {
|
|
4485
|
+
if (anchored || pattern.includes("/")) {
|
|
4486
|
+
return target === pattern || target.startsWith(`${pattern}/`);
|
|
4487
|
+
}
|
|
4308
4488
|
return target === pattern || target.endsWith(`/${pattern}`) || target.startsWith(`${pattern}/`);
|
|
4309
4489
|
}
|
|
4310
4490
|
|
|
4311
|
-
const
|
|
4491
|
+
const prefix = anchored || pattern.includes("/") ? "^" : "(^|/)";
|
|
4492
|
+
const expression = new RegExp(`${prefix}${globPatternRegExpSource(pattern)}$`);
|
|
4312
4493
|
return expression.test(target);
|
|
4313
4494
|
}
|
|
4314
4495
|
|
|
@@ -4417,6 +4598,9 @@ function ruleMetaForRuleId(ruleId) {
|
|
|
4417
4598
|
if (FIXABLE_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4418
4599
|
meta.fixable = "code";
|
|
4419
4600
|
}
|
|
4601
|
+
if (SUGGESTION_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4602
|
+
meta.hasSuggestions = true;
|
|
4603
|
+
}
|
|
4420
4604
|
return meta;
|
|
4421
4605
|
}
|
|
4422
4606
|
|
|
@@ -4507,6 +4691,21 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4507
4691
|
if (fixes.length > 0) {
|
|
4508
4692
|
message.fix = fixes.length === 1 ? fixes[0] : fixes;
|
|
4509
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
|
+
}
|
|
4510
4709
|
return message;
|
|
4511
4710
|
}
|
|
4512
4711
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utoo/lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "High-performance JavaScript and TypeScript linter powered by Yuku",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -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": {
|
package/schema.json
CHANGED
|
@@ -28,6 +28,35 @@
|
|
|
28
28
|
"$ref": "#/definitions/ruleSeverity"
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
|
+
"settings": {
|
|
32
|
+
"description": "Shared plugin settings.",
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": true,
|
|
35
|
+
"properties": {
|
|
36
|
+
"jest": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": true,
|
|
39
|
+
"properties": {
|
|
40
|
+
"version": {
|
|
41
|
+
"description": "Jest version used by version-aware Jest rules.",
|
|
42
|
+
"oneOf": [
|
|
43
|
+
{ "type": "integer", "minimum": 1 },
|
|
44
|
+
{ "type": "string", "pattern": "^[0-9]+(?:\\..*)?$" }
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"globalAliases": {
|
|
48
|
+
"description": "Additional global aliases for canonical Jest functions.",
|
|
49
|
+
"type": "object",
|
|
50
|
+
"additionalProperties": {
|
|
51
|
+
"type": "array",
|
|
52
|
+
"items": { "type": "string", "minLength": 1 },
|
|
53
|
+
"uniqueItems": true
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
31
60
|
"files": {
|
|
32
61
|
"description": "File globs this config entry applies to.",
|
|
33
62
|
"oneOf": [
|
|
@@ -37,7 +66,18 @@
|
|
|
37
66
|
{
|
|
38
67
|
"type": "array",
|
|
39
68
|
"items": {
|
|
40
|
-
"
|
|
69
|
+
"oneOf": [
|
|
70
|
+
{
|
|
71
|
+
"type": "string"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": {
|
|
76
|
+
"type": "string"
|
|
77
|
+
},
|
|
78
|
+
"minItems": 1
|
|
79
|
+
}
|
|
80
|
+
]
|
|
41
81
|
}
|
|
42
82
|
}
|
|
43
83
|
]
|