@utoo/lint 0.1.2 → 0.1.3

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 CHANGED
@@ -18,8 +18,10 @@ Run the linter with:
18
18
  pnpm exec utoo-lint src
19
19
  ```
20
20
 
21
- If no target is provided, `utoo-lint` scans the current directory. It skips
22
- `.git`, `.zig-cache`, `node_modules`, `vendor`, and `zig-out`.
21
+ If no target is provided, `utoo-lint` uses `files` from `utoo.json` or
22
+ `utoo-lint.json`. When no config file or `files` entry exists, it scans the
23
+ current directory. It skips `.git`, `.zig-cache`, `node_modules`, `vendor`, and
24
+ `zig-out`.
23
25
 
24
26
  Use a config file:
25
27
 
@@ -89,6 +91,10 @@ const report = lintFiles(["src"], {
89
91
  console.log(report.diagnostics);
90
92
  ```
91
93
 
94
+ Calling `lintFiles()` without patterns follows the same default target behavior
95
+ as the CLI, so migration scripts usually do not need to expand config `files`
96
+ manually.
97
+
92
98
  CommonJS is supported through `require("@utoo/lint")`.
93
99
 
94
100
  ## Binary Resolution
package/bin/utoo-lint.js CHANGED
@@ -1,23 +1,20 @@
1
1
  #!/usr/bin/env node
2
- import { spawnSync } from "node:child_process";
3
2
 
4
- import { resolveBinary } from "../lib/binary.js";
3
+ import { runCli } from "../index.js";
5
4
 
6
5
  if (process.argv[2] === "migrate") {
7
6
  const { runMigrate } = await import("./migrate.js");
8
7
  process.exit(await runMigrate(process.argv.slice(3)));
9
8
  }
10
9
 
11
- let binary;
10
+ let result;
12
11
  try {
13
- binary = resolveBinary();
12
+ result = runCli(process.argv.slice(2), { stdio: "inherit" });
14
13
  } catch (error) {
15
14
  console.error(error.message);
16
15
  process.exit(1);
17
16
  }
18
17
 
19
- const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
20
-
21
18
  if (result.error) {
22
19
  console.error(`utoo-lint: failed to run native binary: ${result.error.message}`);
23
20
  process.exit(1);
package/index.cjs CHANGED
@@ -465,7 +465,7 @@ class UtooLint {
465
465
  this.options = { ...options };
466
466
  }
467
467
 
468
- async lintFiles(patterns = ["."], options = {}) {
468
+ async lintFiles(patterns, options = {}) {
469
469
  const mergedOptions = mergeLintOptions(this.options, options);
470
470
  const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
471
471
  const customRuleFilterMap = customRuleMapForConfig(customRuleConfig, new Map());
@@ -670,6 +670,152 @@ function run(args = [], options = {}) {
670
670
  });
671
671
  }
672
672
 
673
+ const UTOO_LINT_CLI_VALUE_FLAGS = new Set(["--config", "-c", "--format", "-f", "--rules", "--threads"]);
674
+
675
+ function parseUtooLintCliArgs(args = []) {
676
+ const values = normalizeStringArray(args, "args");
677
+ const passthroughArgs = [];
678
+ const targets = [];
679
+ const options = {};
680
+ let help = false;
681
+ let versionFlag = false;
682
+
683
+ for (let index = 0; index < values.length; index += 1) {
684
+ const arg = values[index];
685
+ if (arg === "--") {
686
+ targets.push(...values.slice(index + 1));
687
+ break;
688
+ }
689
+ if (arg === "--help" || arg === "-h") {
690
+ help = true;
691
+ passthroughArgs.push(arg);
692
+ continue;
693
+ }
694
+ if (arg === "--version" || arg === "-v") {
695
+ versionFlag = true;
696
+ continue;
697
+ }
698
+ if (UTOO_LINT_CLI_VALUE_FLAGS.has(arg)) {
699
+ const value = values[index + 1];
700
+ if (!value) {
701
+ throw new Error(`utoo-lint: ${arg} requires a value`);
702
+ }
703
+ appendCliOption(passthroughArgs, options, arg, value);
704
+ index += 1;
705
+ continue;
706
+ }
707
+ if (arg.startsWith("--config=")) {
708
+ appendCliOption(passthroughArgs, options, "--config", arg.slice("--config=".length));
709
+ continue;
710
+ }
711
+ if (arg.startsWith("--format=")) {
712
+ appendCliOption(passthroughArgs, options, "--format", arg.slice("--format=".length));
713
+ continue;
714
+ }
715
+ if (arg.startsWith("--rules=")) {
716
+ appendCliOption(passthroughArgs, options, "--rules", arg.slice("--rules=".length));
717
+ continue;
718
+ }
719
+ if (arg.startsWith("--threads=")) {
720
+ appendCliOption(passthroughArgs, options, "--threads", arg.slice("--threads=".length));
721
+ continue;
722
+ }
723
+ if (arg === "--no-config") {
724
+ options.noConfig = true;
725
+ delete options.config;
726
+ continue;
727
+ }
728
+ if (arg === "--json") {
729
+ passthroughArgs.push(arg);
730
+ continue;
731
+ }
732
+ if (arg.startsWith("-")) {
733
+ passthroughArgs.push(arg);
734
+ continue;
735
+ }
736
+ targets.push(arg);
737
+ }
738
+
739
+ return { help, options, passthroughArgs, targets, version: versionFlag };
740
+ }
741
+
742
+ function appendCliOption(passthroughArgs, options, flag, value) {
743
+ if (value == null || value === "") {
744
+ throw new Error(`utoo-lint: ${flag} requires a value`);
745
+ }
746
+ switch (flag) {
747
+ case "--config":
748
+ case "-c":
749
+ options.config = value;
750
+ delete options.noConfig;
751
+ return;
752
+ case "--format":
753
+ case "-f":
754
+ options.format = value;
755
+ return;
756
+ case "--rules":
757
+ options.rules = value;
758
+ return;
759
+ case "--threads":
760
+ options.threads = value;
761
+ return;
762
+ default:
763
+ passthroughArgs.push(`${flag}=${value}`);
764
+ }
765
+ }
766
+
767
+ function completedRunResult(status, stdout, stderr, options = {}) {
768
+ const inherited = options.stdio === "inherit";
769
+ if (inherited) {
770
+ if (stdout) {
771
+ process.stdout.write(stdout);
772
+ }
773
+ if (stderr) {
774
+ process.stderr.write(stderr);
775
+ }
776
+ }
777
+ return {
778
+ status,
779
+ signal: null,
780
+ error: undefined,
781
+ stdout: inherited ? null : stdout,
782
+ stderr: inherited ? null : stderr,
783
+ output: [null, inherited ? null : stdout, inherited ? null : stderr],
784
+ pid: 0
785
+ };
786
+ }
787
+
788
+ function runCli(args = [], options = {}) {
789
+ const parsed = parseUtooLintCliArgs(args);
790
+ if (parsed.version) {
791
+ return completedRunResult(0, `v${version}\n`, "", options);
792
+ }
793
+ if (parsed.help) {
794
+ return run(parsed.passthroughArgs, options);
795
+ }
796
+
797
+ const cliOptions = {
798
+ ...options,
799
+ ...parsed.options
800
+ };
801
+ const targets = parsed.targets.length > 0 ? parsed.targets : defaultLintTargets(cliOptions);
802
+ const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, cliOptions);
803
+ const lintPaths = filteredLintPaths(targets, cliOptions);
804
+ if (lintPaths.length === 0) {
805
+ return completedRunResult(ignoredDiagnostics.length > 0 ? 1 : 0, "", "", options);
806
+ }
807
+
808
+ return withTemporaryConfig(cliOptions, (resolvedOptions) => {
809
+ const cliArgs = buildRunCliArgs(lintPaths, resolvedOptions, parsed.passthroughArgs);
810
+ return run(cliArgs, {
811
+ ...resolvedOptions,
812
+ stdio: options.stdio,
813
+ encoding: options.encoding,
814
+ input: options.input
815
+ });
816
+ });
817
+ }
818
+
673
819
  function runFishlint(args = [], options = {}) {
674
820
  const cliArgs = normalizeStringArray(args, "args");
675
821
  const env = options.env ? { ...process.env, ...options.env } : { ...process.env };
@@ -882,14 +1028,15 @@ function booleanFlagValue(arg) {
882
1028
  return true;
883
1029
  }
884
1030
 
885
- function lintFiles(paths = ["."], options = {}) {
886
- return withTemporaryConfig(options, (resolvedOptions) => {
887
- const ignoredDiagnostics = ignoredLintPathDiagnostics(paths, resolvedOptions);
888
- const lintPaths = filteredLintPaths(paths, resolvedOptions);
889
- if (lintPaths.length === 0) {
890
- return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics.length > 0 ? 1 : 0 };
891
- }
1031
+ function lintFiles(paths, options = {}) {
1032
+ const targets = lintTargetsForInput(paths, options);
1033
+ const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
1034
+ const lintPaths = filteredLintPaths(targets, options);
1035
+ if (lintPaths.length === 0) {
1036
+ return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics.length > 0 ? 1 : 0 };
1037
+ }
892
1038
 
1039
+ return withTemporaryConfig(options, (resolvedOptions) => {
893
1040
  const cliArgs = buildLintArgs(lintPaths, resolvedOptions);
894
1041
  const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
895
1042
 
@@ -981,6 +1128,21 @@ function lintText(code, options = {}) {
981
1128
  }
982
1129
 
983
1130
  function buildLintArgs(paths, options) {
1131
+ return buildNativeLintArgs(paths, {
1132
+ ...options,
1133
+ format: "json",
1134
+ extraArgs: options.extraArgs
1135
+ });
1136
+ }
1137
+
1138
+ function buildRunCliArgs(paths, options, passthroughArgs) {
1139
+ return buildNativeLintArgs(paths, {
1140
+ ...options,
1141
+ extraArgs: passthroughArgs
1142
+ });
1143
+ }
1144
+
1145
+ function buildNativeLintArgs(paths, options) {
984
1146
  const cliArgs = [];
985
1147
 
986
1148
  if (options.config) {
@@ -999,7 +1161,9 @@ function buildLintArgs(paths, options) {
999
1161
  cliArgs.push(`--threads=${options.threads}`);
1000
1162
  }
1001
1163
 
1002
- cliArgs.push("--format=json");
1164
+ if (options.format) {
1165
+ cliArgs.push(`--format=${options.format}`);
1166
+ }
1003
1167
 
1004
1168
  if (options.extraArgs) {
1005
1169
  cliArgs.push(...normalizeStringArray(options.extraArgs, "extraArgs"));
@@ -1206,6 +1370,37 @@ function configDataFromFileConfig(options, filePath) {
1206
1370
  return configDataFromConfig(config, filePath, options.cwd);
1207
1371
  }
1208
1372
 
1373
+ function lintTargetsForInput(paths, options = {}) {
1374
+ if (paths == null) {
1375
+ return defaultLintTargets(options);
1376
+ }
1377
+ return normalizeStringArray(Array.isArray(paths) ? paths : [paths], "paths");
1378
+ }
1379
+
1380
+ function defaultLintTargets(options = {}) {
1381
+ if (options.noConfig) {
1382
+ return ["."];
1383
+ }
1384
+
1385
+ const configPath = configPathForOptions(options);
1386
+ if (!configPath) {
1387
+ return ["."];
1388
+ }
1389
+
1390
+ const targets = filePatternsFromConfig(readConfig(configPath, options.cwd));
1391
+ return targets.length > 0 ? targets : ["."];
1392
+ }
1393
+
1394
+ function filePatternsFromConfig(config) {
1395
+ if (!config) {
1396
+ return [];
1397
+ }
1398
+ if (Array.isArray(config)) {
1399
+ return config.flatMap((entry) => filePatternsFromConfig(entry));
1400
+ }
1401
+ return normalizeConfigPatterns(config.files);
1402
+ }
1403
+
1209
1404
  function configAppliesToFile(config, filePath, cwd) {
1210
1405
  if (!filePath) {
1211
1406
  return true;
@@ -1230,6 +1425,9 @@ function normalizeConfigPatterns(patterns) {
1230
1425
  if (typeof value === "string") {
1231
1426
  return [value];
1232
1427
  }
1428
+ if (Array.isArray(value)) {
1429
+ return normalizeConfigPatterns(value);
1430
+ }
1233
1431
  return [];
1234
1432
  });
1235
1433
  }
@@ -3741,6 +3939,9 @@ function matchesIgnorePattern(target, pattern) {
3741
3939
  }
3742
3940
 
3743
3941
  function matchesConfigFilePattern(target, pattern) {
3942
+ if (!hasGlobSyntax(pattern)) {
3943
+ return target === pattern || target.startsWith(`${pattern}/`) || target.endsWith(`/${pattern}`);
3944
+ }
3744
3945
  const expression = new RegExp(`^${globPatternRegExpSource(pattern)}$`);
3745
3946
  return expression.test(target);
3746
3947
  }
@@ -4107,6 +4308,7 @@ module.exports = {
4107
4308
  platformPackageName,
4108
4309
  resolveBinary,
4109
4310
  run,
4311
+ runCli,
4110
4312
  runFishlint,
4111
4313
  translateFishlintArgs,
4112
4314
  version
package/index.d.ts CHANGED
@@ -82,6 +82,7 @@ export interface LintOptions {
82
82
  env?: Record<string, string | undefined>;
83
83
  threads?: number;
84
84
  rules?: string[] | string;
85
+ format?: "text" | "json" | string;
85
86
  config?: string;
86
87
  configFile?: string;
87
88
  noConfig?: boolean;
@@ -309,6 +310,7 @@ export function loadESLint(options?: { useFlatConfig?: boolean; cwd?: string }):
309
310
  export function lintFiles(patterns?: string | string[], options?: LintOptions): LintReport;
310
311
  export function lintText(code: string, options?: TextLintOptions): LintReport;
311
312
  export function run(args?: string[], options?: LintOptions): unknown;
313
+ export function runCli(args?: string[], options?: LintOptions): unknown;
312
314
  export function runFishlint(args?: string[], options?: LintOptions): unknown;
313
315
  export function translateFishlintArgs(args?: string[], options?: { command?: string; warn?: (message: string) => void }): string[];
314
316
  export function resolveBinary(options?: { env?: Record<string, string | undefined>; platform?: string; arch?: string }): string;
package/index.js CHANGED
@@ -468,7 +468,7 @@ export class UtooLint {
468
468
  this.options = { ...options };
469
469
  }
470
470
 
471
- async lintFiles(patterns = ["."], options = {}) {
471
+ async lintFiles(patterns, options = {}) {
472
472
  const mergedOptions = mergeLintOptions(this.options, options);
473
473
  const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
474
474
  const customRuleFilterMap = customRuleMapForConfig(customRuleConfig, new Map());
@@ -2503,6 +2503,152 @@ export function run(args = [], options = {}) {
2503
2503
  });
2504
2504
  }
2505
2505
 
2506
+ const UTOO_LINT_CLI_VALUE_FLAGS = new Set(["--config", "-c", "--format", "-f", "--rules", "--threads"]);
2507
+
2508
+ function parseUtooLintCliArgs(args = []) {
2509
+ const values = normalizeStringArray(args, "args");
2510
+ const passthroughArgs = [];
2511
+ const targets = [];
2512
+ const options = {};
2513
+ let help = false;
2514
+ let versionFlag = false;
2515
+
2516
+ for (let index = 0; index < values.length; index += 1) {
2517
+ const arg = values[index];
2518
+ if (arg === "--") {
2519
+ targets.push(...values.slice(index + 1));
2520
+ break;
2521
+ }
2522
+ if (arg === "--help" || arg === "-h") {
2523
+ help = true;
2524
+ passthroughArgs.push(arg);
2525
+ continue;
2526
+ }
2527
+ if (arg === "--version" || arg === "-v") {
2528
+ versionFlag = true;
2529
+ continue;
2530
+ }
2531
+ if (UTOO_LINT_CLI_VALUE_FLAGS.has(arg)) {
2532
+ const value = values[index + 1];
2533
+ if (!value) {
2534
+ throw new Error(`utoo-lint: ${arg} requires a value`);
2535
+ }
2536
+ appendCliOption(passthroughArgs, options, arg, value);
2537
+ index += 1;
2538
+ continue;
2539
+ }
2540
+ if (arg.startsWith("--config=")) {
2541
+ appendCliOption(passthroughArgs, options, "--config", arg.slice("--config=".length));
2542
+ continue;
2543
+ }
2544
+ if (arg.startsWith("--format=")) {
2545
+ appendCliOption(passthroughArgs, options, "--format", arg.slice("--format=".length));
2546
+ continue;
2547
+ }
2548
+ if (arg.startsWith("--rules=")) {
2549
+ appendCliOption(passthroughArgs, options, "--rules", arg.slice("--rules=".length));
2550
+ continue;
2551
+ }
2552
+ if (arg.startsWith("--threads=")) {
2553
+ appendCliOption(passthroughArgs, options, "--threads", arg.slice("--threads=".length));
2554
+ continue;
2555
+ }
2556
+ if (arg === "--no-config") {
2557
+ options.noConfig = true;
2558
+ delete options.config;
2559
+ continue;
2560
+ }
2561
+ if (arg === "--json") {
2562
+ passthroughArgs.push(arg);
2563
+ continue;
2564
+ }
2565
+ if (arg.startsWith("-")) {
2566
+ passthroughArgs.push(arg);
2567
+ continue;
2568
+ }
2569
+ targets.push(arg);
2570
+ }
2571
+
2572
+ return { help, options, passthroughArgs, targets, version: versionFlag };
2573
+ }
2574
+
2575
+ function appendCliOption(passthroughArgs, options, flag, value) {
2576
+ if (value == null || value === "") {
2577
+ throw new Error(`utoo-lint: ${flag} requires a value`);
2578
+ }
2579
+ switch (flag) {
2580
+ case "--config":
2581
+ case "-c":
2582
+ options.config = value;
2583
+ delete options.noConfig;
2584
+ return;
2585
+ case "--format":
2586
+ case "-f":
2587
+ options.format = value;
2588
+ return;
2589
+ case "--rules":
2590
+ options.rules = value;
2591
+ return;
2592
+ case "--threads":
2593
+ options.threads = value;
2594
+ return;
2595
+ default:
2596
+ passthroughArgs.push(`${flag}=${value}`);
2597
+ }
2598
+ }
2599
+
2600
+ function completedRunResult(status, stdout, stderr, options = {}) {
2601
+ const inherited = options.stdio === "inherit";
2602
+ if (inherited) {
2603
+ if (stdout) {
2604
+ process.stdout.write(stdout);
2605
+ }
2606
+ if (stderr) {
2607
+ process.stderr.write(stderr);
2608
+ }
2609
+ }
2610
+ return {
2611
+ status,
2612
+ signal: null,
2613
+ error: undefined,
2614
+ stdout: inherited ? null : stdout,
2615
+ stderr: inherited ? null : stderr,
2616
+ output: [null, inherited ? null : stdout, inherited ? null : stderr],
2617
+ pid: 0
2618
+ };
2619
+ }
2620
+
2621
+ export function runCli(args = [], options = {}) {
2622
+ const parsed = parseUtooLintCliArgs(args);
2623
+ if (parsed.version) {
2624
+ return completedRunResult(0, `v${version}\n`, "", options);
2625
+ }
2626
+ if (parsed.help) {
2627
+ return run(parsed.passthroughArgs, options);
2628
+ }
2629
+
2630
+ const cliOptions = {
2631
+ ...options,
2632
+ ...parsed.options
2633
+ };
2634
+ const targets = parsed.targets.length > 0 ? parsed.targets : defaultLintTargets(cliOptions);
2635
+ const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, cliOptions);
2636
+ const lintPaths = filteredLintPaths(targets, cliOptions);
2637
+ if (lintPaths.length === 0) {
2638
+ return completedRunResult(ignoredDiagnostics.length > 0 ? 1 : 0, "", "", options);
2639
+ }
2640
+
2641
+ return withTemporaryConfig(cliOptions, (resolvedOptions) => {
2642
+ const cliArgs = buildRunCliArgs(lintPaths, resolvedOptions, parsed.passthroughArgs);
2643
+ return run(cliArgs, {
2644
+ ...resolvedOptions,
2645
+ stdio: options.stdio,
2646
+ encoding: options.encoding,
2647
+ input: options.input
2648
+ });
2649
+ });
2650
+ }
2651
+
2506
2652
  export function runFishlint(args = [], options = {}) {
2507
2653
  const cliArgs = normalizeStringArray(args, "args");
2508
2654
  const env = options.env ? { ...process.env, ...options.env } : { ...process.env };
@@ -2715,14 +2861,15 @@ function booleanFlagValue(arg) {
2715
2861
  return true;
2716
2862
  }
2717
2863
 
2718
- export function lintFiles(paths = ["."], options = {}) {
2719
- return withTemporaryConfig(options, (resolvedOptions) => {
2720
- const ignoredDiagnostics = ignoredLintPathDiagnostics(paths, resolvedOptions);
2721
- const lintPaths = filteredLintPaths(paths, resolvedOptions);
2722
- if (lintPaths.length === 0) {
2723
- return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics.length > 0 ? 1 : 0 };
2724
- }
2864
+ export function lintFiles(paths, options = {}) {
2865
+ const targets = lintTargetsForInput(paths, options);
2866
+ const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
2867
+ const lintPaths = filteredLintPaths(targets, options);
2868
+ if (lintPaths.length === 0) {
2869
+ return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics.length > 0 ? 1 : 0 };
2870
+ }
2725
2871
 
2872
+ return withTemporaryConfig(options, (resolvedOptions) => {
2726
2873
  const cliArgs = buildLintArgs(lintPaths, resolvedOptions);
2727
2874
  const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
2728
2875
 
@@ -2814,6 +2961,21 @@ export function lintText(code, options = {}) {
2814
2961
  }
2815
2962
 
2816
2963
  function buildLintArgs(paths, options) {
2964
+ return buildNativeLintArgs(paths, {
2965
+ ...options,
2966
+ format: "json",
2967
+ extraArgs: options.extraArgs
2968
+ });
2969
+ }
2970
+
2971
+ function buildRunCliArgs(paths, options, passthroughArgs) {
2972
+ return buildNativeLintArgs(paths, {
2973
+ ...options,
2974
+ extraArgs: passthroughArgs
2975
+ });
2976
+ }
2977
+
2978
+ function buildNativeLintArgs(paths, options) {
2817
2979
  const cliArgs = [];
2818
2980
 
2819
2981
  if (options.config) {
@@ -2832,7 +2994,9 @@ function buildLintArgs(paths, options) {
2832
2994
  cliArgs.push(`--threads=${options.threads}`);
2833
2995
  }
2834
2996
 
2835
- cliArgs.push("--format=json");
2997
+ if (options.format) {
2998
+ cliArgs.push(`--format=${options.format}`);
2999
+ }
2836
3000
 
2837
3001
  if (options.extraArgs) {
2838
3002
  cliArgs.push(...normalizeStringArray(options.extraArgs, "extraArgs"));
@@ -3039,6 +3203,37 @@ function configDataFromFileConfig(options, filePath) {
3039
3203
  return configDataFromConfig(config, filePath, options.cwd);
3040
3204
  }
3041
3205
 
3206
+ function lintTargetsForInput(paths, options = {}) {
3207
+ if (paths == null) {
3208
+ return defaultLintTargets(options);
3209
+ }
3210
+ return normalizeStringArray(Array.isArray(paths) ? paths : [paths], "paths");
3211
+ }
3212
+
3213
+ function defaultLintTargets(options = {}) {
3214
+ if (options.noConfig) {
3215
+ return ["."];
3216
+ }
3217
+
3218
+ const configPath = configPathForOptions(options);
3219
+ if (!configPath) {
3220
+ return ["."];
3221
+ }
3222
+
3223
+ const targets = filePatternsFromConfig(readConfig(configPath, options.cwd));
3224
+ return targets.length > 0 ? targets : ["."];
3225
+ }
3226
+
3227
+ function filePatternsFromConfig(config) {
3228
+ if (!config) {
3229
+ return [];
3230
+ }
3231
+ if (Array.isArray(config)) {
3232
+ return config.flatMap((entry) => filePatternsFromConfig(entry));
3233
+ }
3234
+ return normalizeConfigPatterns(config.files);
3235
+ }
3236
+
3042
3237
  function configAppliesToFile(config, filePath, cwd) {
3043
3238
  if (!filePath) {
3044
3239
  return true;
@@ -3063,6 +3258,9 @@ function normalizeConfigPatterns(patterns) {
3063
3258
  if (typeof value === "string") {
3064
3259
  return [value];
3065
3260
  }
3261
+ if (Array.isArray(value)) {
3262
+ return normalizeConfigPatterns(value);
3263
+ }
3066
3264
  return [];
3067
3265
  });
3068
3266
  }
@@ -3744,6 +3942,9 @@ function matchesIgnorePattern(target, pattern) {
3744
3942
  }
3745
3943
 
3746
3944
  function matchesConfigFilePattern(target, pattern) {
3945
+ if (!hasGlobSyntax(pattern)) {
3946
+ return target === pattern || target.startsWith(`${pattern}/`) || target.endsWith(`/${pattern}`);
3947
+ }
3747
3948
  const expression = new RegExp(`^${globPatternRegExpSource(pattern)}$`);
3748
3949
  return expression.test(target);
3749
3950
  }
package/lib/binary.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const { existsSync } = require("node:fs");
1
+ const { chmodSync, existsSync, statSync } = require("node:fs");
2
2
  const { join } = require("node:path");
3
3
 
4
4
  const here = __dirname;
@@ -26,7 +26,7 @@ function resolveBinary(options = {}) {
26
26
 
27
27
  if (env.UTOO_LINT_BIN) {
28
28
  if (existsSync(env.UTOO_LINT_BIN)) {
29
- return env.UTOO_LINT_BIN;
29
+ return ensureExecutable(env.UTOO_LINT_BIN, platform);
30
30
  }
31
31
  throw new Error(`utoo-lint: UTOO_LINT_BIN does not exist: ${env.UTOO_LINT_BIN}`);
32
32
  }
@@ -47,7 +47,7 @@ function resolveBinary(options = {}) {
47
47
  try {
48
48
  const resolved = candidate();
49
49
  if (existsSync(resolved)) {
50
- return resolved;
50
+ return ensureExecutable(resolved, platform);
51
51
  }
52
52
  } catch {}
53
53
  }
@@ -58,6 +58,21 @@ function resolveBinary(options = {}) {
58
58
  );
59
59
  }
60
60
 
61
+ function ensureExecutable(path, platform) {
62
+ if (platform === "win32") {
63
+ return path;
64
+ }
65
+ try {
66
+ const mode = statSync(path).mode;
67
+ if ((mode & 0o111) === 0) {
68
+ chmodSync(path, mode | 0o755);
69
+ }
70
+ } catch {
71
+ // Let spawn surface the actual filesystem error if chmod is not permitted.
72
+ }
73
+ return path;
74
+ }
75
+
61
76
  module.exports = {
62
77
  platformPackageName,
63
78
  resolveBinary
package/lib/binary.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync } from "node:fs";
1
+ import { chmodSync, existsSync, statSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { createRequire } from "node:module";
4
4
  import { fileURLToPath } from "node:url";
@@ -29,7 +29,7 @@ export function resolveBinary(options = {}) {
29
29
 
30
30
  if (env.UTOO_LINT_BIN) {
31
31
  if (existsSync(env.UTOO_LINT_BIN)) {
32
- return env.UTOO_LINT_BIN;
32
+ return ensureExecutable(env.UTOO_LINT_BIN, platform);
33
33
  }
34
34
  throw new Error(`utoo-lint: UTOO_LINT_BIN does not exist: ${env.UTOO_LINT_BIN}`);
35
35
  }
@@ -50,7 +50,7 @@ export function resolveBinary(options = {}) {
50
50
  try {
51
51
  const resolved = candidate();
52
52
  if (existsSync(resolved)) {
53
- return resolved;
53
+ return ensureExecutable(resolved, platform);
54
54
  }
55
55
  } catch {}
56
56
  }
@@ -60,3 +60,18 @@ export function resolveBinary(options = {}) {
60
60
  "Run `./scripts/package-npm.sh` from the repository root, or install the matching optional dependency."
61
61
  );
62
62
  }
63
+
64
+ function ensureExecutable(path, platform) {
65
+ if (platform === "win32") {
66
+ return path;
67
+ }
68
+ try {
69
+ const mode = statSync(path).mode;
70
+ if ((mode & 0o111) === 0) {
71
+ chmodSync(path, mode | 0o755);
72
+ }
73
+ } catch {
74
+ // Let spawn surface the actual filesystem error if chmod is not permitted.
75
+ }
76
+ return path;
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utoo/lint",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Experimental JavaScript and TypeScript linter powered by Yuku",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -70,11 +70,11 @@
70
70
  "use-at-your-own-risk.js"
71
71
  ],
72
72
  "optionalDependencies": {
73
- "@utoo/lint-darwin-arm64": "0.1.2",
74
- "@utoo/lint-darwin-x64": "0.1.2",
75
- "@utoo/lint-linux-arm64": "0.1.2",
76
- "@utoo/lint-linux-x64": "0.1.2",
77
- "@utoo/lint-win32-x64": "0.1.2"
73
+ "@utoo/lint-darwin-arm64": "0.1.3",
74
+ "@utoo/lint-darwin-x64": "0.1.3",
75
+ "@utoo/lint-linux-arm64": "0.1.3",
76
+ "@utoo/lint-linux-x64": "0.1.3",
77
+ "@utoo/lint-win32-x64": "0.1.3"
78
78
  },
79
79
  "publishConfig": {
80
80
  "access": "public",