@utoo/lint 0.0.9 → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 utoo-lint contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -7,7 +7,7 @@ High performance linter for JavaScript and TypeScript written by Zig.
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- npm install -D @utoo/lint
10
+ pnpm add -D @utoo/lint
11
11
  ```
12
12
 
13
13
  ## CLI
@@ -15,28 +15,30 @@ npm install -D @utoo/lint
15
15
  Run the linter with:
16
16
 
17
17
  ```bash
18
- npx utoo-lint src
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
 
26
28
  ```bash
27
- npx utoo-lint --config=utoo.json src
29
+ pnpm exec utoo-lint --config=utoo.json src
28
30
  ```
29
31
 
30
32
  Run a focused rule set:
31
33
 
32
34
  ```bash
33
- npx utoo-lint --rules=no-debugger,no-console src
35
+ pnpm exec utoo-lint --rules=no-debugger,no-console src
34
36
  ```
35
37
 
36
38
  Use machine-readable output:
37
39
 
38
40
  ```bash
39
- npx utoo-lint --format=json src
41
+ pnpm exec utoo-lint --format=json src
40
42
  ```
41
43
 
42
44
  ## Configuration
@@ -66,14 +68,14 @@ cp node_modules/@utoo/lint/configs/frontend.json utoo.json
66
68
  Convert an existing ESLint config into the native utoo format:
67
69
 
68
70
  ```bash
69
- npx utoo-lint migrate eslint --from eslint.config.js --output utoo.json
71
+ pnpm exec utoo-lint migrate eslint --from eslint.config.js --output utoo.json
70
72
  ```
71
73
 
72
74
  The package also provides compatibility bins for common replacement flows:
73
75
 
74
76
  ```bash
75
- npx eslint --config utoo.json src
76
- npx fishlint eslint --disable-setup --config utoo.json --glob src
77
+ pnpm exec eslint --config utoo.json src
78
+ pnpm exec fishlint eslint --disable-setup --config utoo.json --glob src
77
79
  ```
78
80
 
79
81
  ## JavaScript API
@@ -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/eslint.js CHANGED
File without changes
package/bin/migrate.js CHANGED
@@ -183,7 +183,6 @@ function migrateEslintConfig(options) {
183
183
  const supportedRules = [];
184
184
  const unsupportedRules = [];
185
185
  const ignoredRules = [];
186
- const optionDroppedRules = [];
187
186
 
188
187
  for (const entry of entries) {
189
188
  addPatterns(files, entry.files);
@@ -200,11 +199,8 @@ function migrateEslintConfig(options) {
200
199
  unsupportedRules.push(ruleId);
201
200
  continue;
202
201
  }
203
- rules[ruleId] = severityOnly(ruleConfig);
202
+ rules[ruleId] = migratableRuleConfig(ruleConfig);
204
203
  supportedRules.push(ruleId);
205
- if (Array.isArray(ruleConfig) && ruleConfig.length > 1) {
206
- optionDroppedRules.push(ruleId);
207
- }
208
204
  }
209
205
  }
210
206
 
@@ -227,7 +223,7 @@ function migrateEslintConfig(options) {
227
223
  supportedRules: uniqueSorted(supportedRules),
228
224
  unsupportedRules: uniqueSorted(unsupportedRules),
229
225
  ignoredRules: uniqueByRuleId(ignoredRules),
230
- optionDroppedRules: uniqueSorted(optionDroppedRules)
226
+ optionDroppedRules: []
231
227
  }
232
228
  };
233
229
  }
@@ -295,8 +291,8 @@ function addPatterns(target, value) {
295
291
  }
296
292
  }
297
293
 
298
- function severityOnly(ruleConfig) {
299
- return Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
294
+ function migratableRuleConfig(ruleConfig) {
295
+ return Array.isArray(ruleConfig) ? [...ruleConfig] : ruleConfig;
300
296
  }
301
297
 
302
298
  function sortObjectByKey(object) {
@@ -326,9 +322,6 @@ function writeReport(report, options, stream) {
326
322
  stream.write(`utoo-lint migrate eslint: wrote ${report.output}\n`);
327
323
  }
328
324
  stream.write(`utoo-lint migrate eslint: migrated ${report.supportedRules.length} supported rule(s)\n`);
329
- if (report.optionDroppedRules.length > 0) {
330
- stream.write(`utoo-lint migrate eslint: dropped options for ${report.optionDroppedRules.length} rule(s): ${report.optionDroppedRules.join(", ")}\n`);
331
- }
332
325
  if (report.ignoredRules.length > 0) {
333
326
  stream.write(`utoo-lint migrate eslint: ignored ${report.ignoredRules.length} rule(s): ${report.ignoredRules.map((rule) => rule.ruleId).join(", ")}\n`);
334
327
  }
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
@@ -83,9 +83,13 @@ process.stdout.write(json);
83
83
  const BUILTIN_RULE_IDS = [
84
84
  "accessor-pairs",
85
85
  "array-callback-return",
86
+ "arrow-body-style",
86
87
  "block-scoped-var",
88
+ "camelcase",
87
89
  "capitalized-comments",
90
+ "complexity",
88
91
  "consistent-return",
92
+ "consistent-this",
89
93
  "constructor-super",
90
94
  "curly",
91
95
  "default-case",
@@ -97,11 +101,23 @@ const BUILTIN_RULE_IDS = [
97
101
  "for-direction",
98
102
  "func-name-matching",
99
103
  "func-names",
104
+ "func-style",
100
105
  "getter-return",
101
106
  "grouped-accessor-pairs",
102
107
  "guard-for-in",
108
+ "id-denylist",
109
+ "id-length",
110
+ "id-match",
111
+ "init-declarations",
103
112
  "linebreak-style",
104
113
  "logical-assignment-operators",
114
+ "max-classes-per-file",
115
+ "max-depth",
116
+ "max-lines",
117
+ "max-lines-per-function",
118
+ "max-nested-callbacks",
119
+ "max-params",
120
+ "max-statements",
105
121
  "new-cap",
106
122
  "new-parens",
107
123
  "no-alert",
@@ -119,6 +135,7 @@ const BUILTIN_RULE_IDS = [
119
135
  "no-cond-assign",
120
136
  "no-console",
121
137
  "no-const-assign",
138
+ "no-constant-binary-expression",
122
139
  "no-constant-condition",
123
140
  "no-constructor-return",
124
141
  "no-continue",
@@ -155,6 +172,7 @@ const BUILTIN_RULE_IDS = [
155
172
  "no-global-is-finite",
156
173
  "no-global-is-nan",
157
174
  "no-implicit-coercion",
175
+ "no-implicit-globals",
158
176
  "no-implied-eval",
159
177
  "no-import-assign",
160
178
  "no-inline-comments",
@@ -196,6 +214,13 @@ const BUILTIN_RULE_IDS = [
196
214
  "no-promise-executor-return",
197
215
  "no-proto",
198
216
  "no-prototype-builtins",
217
+ "no-redeclare",
218
+ "no-restricted-exports",
219
+ "no-restricted-globals",
220
+ "no-restricted-imports",
221
+ "no-restricted-modules",
222
+ "no-restricted-properties",
223
+ "no-restricted-syntax",
199
224
  "no-regex-spaces",
200
225
  "no-return-assign",
201
226
  "no-return-await",
@@ -204,6 +229,7 @@ const BUILTIN_RULE_IDS = [
204
229
  "no-self-compare",
205
230
  "no-sequences",
206
231
  "no-setter-return",
232
+ "no-shadow",
207
233
  "no-shadow-restricted-names",
208
234
  "no-sparse-arrays",
209
235
  "no-tabs",
@@ -214,15 +240,21 @@ const BUILTIN_RULE_IDS = [
214
240
  "no-trailing-spaces",
215
241
  "no-undef",
216
242
  "no-undef-init",
243
+ "no-unassigned-vars",
217
244
  "no-underscore-dangle",
218
245
  "no-undefined",
219
246
  "no-unneeded-ternary",
220
247
  "no-unreachable",
248
+ "no-unreachable-loop",
221
249
  "no-unsafe-finally",
222
250
  "no-unsafe-negation",
251
+ "no-unsafe-optional-chaining",
223
252
  "no-unused-expressions",
224
253
  "no-unused-labels",
254
+ "no-unused-private-class-members",
225
255
  "no-unused-vars",
256
+ "no-use-before-define",
257
+ "no-useless-backreference",
226
258
  "no-useless-call",
227
259
  "no-useless-catch",
228
260
  "no-useless-computed-key",
@@ -238,13 +270,16 @@ const BUILTIN_RULE_IDS = [
238
270
  "object-shorthand",
239
271
  "one-var",
240
272
  "operator-assignment",
273
+ "prefer-arrow-callback",
241
274
  "prefer-const",
242
275
  "prefer-destructuring",
243
276
  "prefer-exponentiation-operator",
277
+ "prefer-named-capture-group",
244
278
  "prefer-numeric-literals",
245
279
  "prefer-object-has-own",
246
280
  "prefer-object-spread",
247
281
  "prefer-promise-reject-errors",
282
+ "preserve-caught-error",
248
283
  "prefer-regex-literals",
249
284
  "prefer-rest-params",
250
285
  "prefer-spread",
@@ -252,8 +287,13 @@ const BUILTIN_RULE_IDS = [
252
287
  "radix",
253
288
  "require-await",
254
289
  "require-atomic-updates",
290
+ "require-unicode-regexp",
255
291
  "require-yield",
292
+ "sort-imports",
293
+ "sort-keys",
294
+ "sort-vars",
256
295
  "spaced-comment",
296
+ "strict",
257
297
  "symbol-description",
258
298
  "unicode-bom",
259
299
  "use-isnan",
@@ -261,6 +301,7 @@ const BUILTIN_RULE_IDS = [
261
301
  "vars-on-top",
262
302
  "wrap-iife",
263
303
  "yoda",
304
+ "eslint-comments/no-restricted-disable",
264
305
  "import/default",
265
306
  "import/export",
266
307
  "import/first",
@@ -274,22 +315,59 @@ const BUILTIN_RULE_IDS = [
274
315
  "import/no-named-as-default-member",
275
316
  "import/no-unresolved",
276
317
  "import/no-self-import",
318
+ "jsx-a11y/alt-text",
319
+ "jsx-a11y/anchor-has-content",
277
320
  "jsx-a11y/aria-props",
321
+ "jsx-a11y/aria-proptypes",
322
+ "jsx-a11y/aria-role",
323
+ "jsx-a11y/aria-unsupported-elements",
278
324
  "jsx-a11y/iframe-has-title",
279
325
  "jsx-a11y/img-redundant-alt",
280
326
  "jsx-a11y/no-access-key",
327
+ "jsx-a11y/no-distracting-elements",
328
+ "jsx-a11y/role-has-required-aria-props",
329
+ "jsx-a11y/role-supports-aria-props",
330
+ "jsx-a11y/scope",
331
+ "react/button-has-type",
332
+ "react/default-props-match-prop-types",
333
+ "react/display-name",
334
+ "react/forbid-prop-types",
281
335
  "react/jsx-boolean-value",
336
+ "react/jsx-filename-extension",
337
+ "react/jsx-key",
338
+ "react/jsx-no-bind",
282
339
  "react/jsx-no-comment-textnodes",
283
340
  "react/jsx-no-duplicate-props",
341
+ "react/jsx-no-undef",
342
+ "react/jsx-uses-react",
343
+ "react/jsx-uses-vars",
284
344
  "react/jsx-no-target-blank",
285
345
  "react/jsx-pascal-case",
346
+ "react/no-access-state-in-setstate",
347
+ "react/no-array-index-key",
348
+ "react/no-children-prop",
286
349
  "react/no-danger",
350
+ "react/no-danger-with-children",
351
+ "react/no-deprecated",
287
352
  "react/no-find-dom-node",
288
353
  "react/no-is-mounted",
354
+ "react/no-multi-comp",
355
+ "react/no-redundant-should-component-update",
289
356
  "react/no-render-return-value",
357
+ "react/no-string-refs",
358
+ "react/no-this-in-sfc",
359
+ "react/no-typos",
290
360
  "react/no-unescaped-entities",
361
+ "react/no-unknown-property",
291
362
  "react/no-unused-prop-types",
363
+ "react/no-unused-state",
364
+ "react/no-will-update-set-state",
365
+ "react/prefer-es6-class",
292
366
  "react/prop-types",
367
+ "react/require-render-return",
368
+ "react/self-closing-comp",
369
+ "react/style-prop-object",
370
+ "react/void-dom-elements-no-children",
293
371
  "react-hooks/rules-of-hooks",
294
372
  "@typescript-eslint/adjacent-overload-signatures",
295
373
  "@typescript-eslint/array-type",
@@ -313,6 +391,7 @@ const BUILTIN_RULE_IDS = [
313
391
  "@typescript-eslint/no-extra-non-null-assertion",
314
392
  "@typescript-eslint/no-inferrable-types",
315
393
  "@typescript-eslint/no-invalid-void-type",
394
+ "@typescript-eslint/no-loop-func",
316
395
  "@typescript-eslint/no-loss-of-precision",
317
396
  "@typescript-eslint/no-misused-new",
318
397
  "@typescript-eslint/no-namespace",
@@ -386,7 +465,7 @@ class UtooLint {
386
465
  this.options = { ...options };
387
466
  }
388
467
 
389
- async lintFiles(patterns = ["."], options = {}) {
468
+ async lintFiles(patterns, options = {}) {
390
469
  const mergedOptions = mergeLintOptions(this.options, options);
391
470
  const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
392
471
  const customRuleFilterMap = customRuleMapForConfig(customRuleConfig, new Map());
@@ -591,6 +670,152 @@ function run(args = [], options = {}) {
591
670
  });
592
671
  }
593
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
+
594
819
  function runFishlint(args = [], options = {}) {
595
820
  const cliArgs = normalizeStringArray(args, "args");
596
821
  const env = options.env ? { ...process.env, ...options.env } : { ...process.env };
@@ -803,14 +1028,15 @@ function booleanFlagValue(arg) {
803
1028
  return true;
804
1029
  }
805
1030
 
806
- function lintFiles(paths = ["."], options = {}) {
807
- return withTemporaryConfig(options, (resolvedOptions) => {
808
- const ignoredDiagnostics = ignoredLintPathDiagnostics(paths, resolvedOptions);
809
- const lintPaths = filteredLintPaths(paths, resolvedOptions);
810
- if (lintPaths.length === 0) {
811
- return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics.length > 0 ? 1 : 0 };
812
- }
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
+ }
813
1038
 
1039
+ return withTemporaryConfig(options, (resolvedOptions) => {
814
1040
  const cliArgs = buildLintArgs(lintPaths, resolvedOptions);
815
1041
  const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
816
1042
 
@@ -902,6 +1128,21 @@ function lintText(code, options = {}) {
902
1128
  }
903
1129
 
904
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) {
905
1146
  const cliArgs = [];
906
1147
 
907
1148
  if (options.config) {
@@ -920,7 +1161,9 @@ function buildLintArgs(paths, options) {
920
1161
  cliArgs.push(`--threads=${options.threads}`);
921
1162
  }
922
1163
 
923
- cliArgs.push("--format=json");
1164
+ if (options.format) {
1165
+ cliArgs.push(`--format=${options.format}`);
1166
+ }
924
1167
 
925
1168
  if (options.extraArgs) {
926
1169
  cliArgs.push(...normalizeStringArray(options.extraArgs, "extraArgs"));
@@ -1127,6 +1370,37 @@ function configDataFromFileConfig(options, filePath) {
1127
1370
  return configDataFromConfig(config, filePath, options.cwd);
1128
1371
  }
1129
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
+
1130
1404
  function configAppliesToFile(config, filePath, cwd) {
1131
1405
  if (!filePath) {
1132
1406
  return true;
@@ -1151,6 +1425,9 @@ function normalizeConfigPatterns(patterns) {
1151
1425
  if (typeof value === "string") {
1152
1426
  return [value];
1153
1427
  }
1428
+ if (Array.isArray(value)) {
1429
+ return normalizeConfigPatterns(value);
1430
+ }
1154
1431
  return [];
1155
1432
  });
1156
1433
  }
@@ -3662,6 +3939,9 @@ function matchesIgnorePattern(target, pattern) {
3662
3939
  }
3663
3940
 
3664
3941
  function matchesConfigFilePattern(target, pattern) {
3942
+ if (!hasGlobSyntax(pattern)) {
3943
+ return target === pattern || target.startsWith(`${pattern}/`) || target.endsWith(`/${pattern}`);
3944
+ }
3665
3945
  const expression = new RegExp(`^${globPatternRegExpSource(pattern)}$`);
3666
3946
  return expression.test(target);
3667
3947
  }
@@ -4028,6 +4308,7 @@ module.exports = {
4028
4308
  platformPackageName,
4029
4309
  resolveBinary,
4030
4310
  run,
4311
+ runCli,
4031
4312
  runFishlint,
4032
4313
  translateFishlintArgs,
4033
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
@@ -86,9 +86,13 @@ process.stdout.write(json);
86
86
  const BUILTIN_RULE_IDS = [
87
87
  "accessor-pairs",
88
88
  "array-callback-return",
89
+ "arrow-body-style",
89
90
  "block-scoped-var",
91
+ "camelcase",
90
92
  "capitalized-comments",
93
+ "complexity",
91
94
  "consistent-return",
95
+ "consistent-this",
92
96
  "constructor-super",
93
97
  "curly",
94
98
  "default-case",
@@ -100,11 +104,23 @@ const BUILTIN_RULE_IDS = [
100
104
  "for-direction",
101
105
  "func-name-matching",
102
106
  "func-names",
107
+ "func-style",
103
108
  "getter-return",
104
109
  "grouped-accessor-pairs",
105
110
  "guard-for-in",
111
+ "id-denylist",
112
+ "id-length",
113
+ "id-match",
114
+ "init-declarations",
106
115
  "linebreak-style",
107
116
  "logical-assignment-operators",
117
+ "max-classes-per-file",
118
+ "max-depth",
119
+ "max-lines",
120
+ "max-lines-per-function",
121
+ "max-nested-callbacks",
122
+ "max-params",
123
+ "max-statements",
108
124
  "new-cap",
109
125
  "new-parens",
110
126
  "no-alert",
@@ -122,6 +138,7 @@ const BUILTIN_RULE_IDS = [
122
138
  "no-cond-assign",
123
139
  "no-console",
124
140
  "no-const-assign",
141
+ "no-constant-binary-expression",
125
142
  "no-constant-condition",
126
143
  "no-constructor-return",
127
144
  "no-continue",
@@ -158,6 +175,7 @@ const BUILTIN_RULE_IDS = [
158
175
  "no-global-is-finite",
159
176
  "no-global-is-nan",
160
177
  "no-implicit-coercion",
178
+ "no-implicit-globals",
161
179
  "no-implied-eval",
162
180
  "no-import-assign",
163
181
  "no-inline-comments",
@@ -199,6 +217,13 @@ const BUILTIN_RULE_IDS = [
199
217
  "no-promise-executor-return",
200
218
  "no-proto",
201
219
  "no-prototype-builtins",
220
+ "no-redeclare",
221
+ "no-restricted-exports",
222
+ "no-restricted-globals",
223
+ "no-restricted-imports",
224
+ "no-restricted-modules",
225
+ "no-restricted-properties",
226
+ "no-restricted-syntax",
202
227
  "no-regex-spaces",
203
228
  "no-return-assign",
204
229
  "no-return-await",
@@ -207,6 +232,7 @@ const BUILTIN_RULE_IDS = [
207
232
  "no-self-compare",
208
233
  "no-sequences",
209
234
  "no-setter-return",
235
+ "no-shadow",
210
236
  "no-shadow-restricted-names",
211
237
  "no-sparse-arrays",
212
238
  "no-tabs",
@@ -217,15 +243,21 @@ const BUILTIN_RULE_IDS = [
217
243
  "no-trailing-spaces",
218
244
  "no-undef",
219
245
  "no-undef-init",
246
+ "no-unassigned-vars",
220
247
  "no-underscore-dangle",
221
248
  "no-undefined",
222
249
  "no-unneeded-ternary",
223
250
  "no-unreachable",
251
+ "no-unreachable-loop",
224
252
  "no-unsafe-finally",
225
253
  "no-unsafe-negation",
254
+ "no-unsafe-optional-chaining",
226
255
  "no-unused-expressions",
227
256
  "no-unused-labels",
257
+ "no-unused-private-class-members",
228
258
  "no-unused-vars",
259
+ "no-use-before-define",
260
+ "no-useless-backreference",
229
261
  "no-useless-call",
230
262
  "no-useless-catch",
231
263
  "no-useless-computed-key",
@@ -241,13 +273,16 @@ const BUILTIN_RULE_IDS = [
241
273
  "object-shorthand",
242
274
  "one-var",
243
275
  "operator-assignment",
276
+ "prefer-arrow-callback",
244
277
  "prefer-const",
245
278
  "prefer-destructuring",
246
279
  "prefer-exponentiation-operator",
280
+ "prefer-named-capture-group",
247
281
  "prefer-numeric-literals",
248
282
  "prefer-object-has-own",
249
283
  "prefer-object-spread",
250
284
  "prefer-promise-reject-errors",
285
+ "preserve-caught-error",
251
286
  "prefer-regex-literals",
252
287
  "prefer-rest-params",
253
288
  "prefer-spread",
@@ -255,8 +290,13 @@ const BUILTIN_RULE_IDS = [
255
290
  "radix",
256
291
  "require-await",
257
292
  "require-atomic-updates",
293
+ "require-unicode-regexp",
258
294
  "require-yield",
295
+ "sort-imports",
296
+ "sort-keys",
297
+ "sort-vars",
259
298
  "spaced-comment",
299
+ "strict",
260
300
  "symbol-description",
261
301
  "unicode-bom",
262
302
  "use-isnan",
@@ -264,6 +304,7 @@ const BUILTIN_RULE_IDS = [
264
304
  "vars-on-top",
265
305
  "wrap-iife",
266
306
  "yoda",
307
+ "eslint-comments/no-restricted-disable",
267
308
  "import/default",
268
309
  "import/export",
269
310
  "import/first",
@@ -277,22 +318,59 @@ const BUILTIN_RULE_IDS = [
277
318
  "import/no-named-as-default-member",
278
319
  "import/no-unresolved",
279
320
  "import/no-self-import",
321
+ "jsx-a11y/alt-text",
322
+ "jsx-a11y/anchor-has-content",
280
323
  "jsx-a11y/aria-props",
324
+ "jsx-a11y/aria-proptypes",
325
+ "jsx-a11y/aria-role",
326
+ "jsx-a11y/aria-unsupported-elements",
281
327
  "jsx-a11y/iframe-has-title",
282
328
  "jsx-a11y/img-redundant-alt",
283
329
  "jsx-a11y/no-access-key",
330
+ "jsx-a11y/no-distracting-elements",
331
+ "jsx-a11y/role-has-required-aria-props",
332
+ "jsx-a11y/role-supports-aria-props",
333
+ "jsx-a11y/scope",
334
+ "react/button-has-type",
335
+ "react/default-props-match-prop-types",
336
+ "react/display-name",
337
+ "react/forbid-prop-types",
284
338
  "react/jsx-boolean-value",
339
+ "react/jsx-filename-extension",
340
+ "react/jsx-key",
341
+ "react/jsx-no-bind",
285
342
  "react/jsx-no-comment-textnodes",
286
343
  "react/jsx-no-duplicate-props",
344
+ "react/jsx-no-undef",
345
+ "react/jsx-uses-react",
346
+ "react/jsx-uses-vars",
287
347
  "react/jsx-no-target-blank",
288
348
  "react/jsx-pascal-case",
349
+ "react/no-access-state-in-setstate",
350
+ "react/no-array-index-key",
351
+ "react/no-children-prop",
289
352
  "react/no-danger",
353
+ "react/no-danger-with-children",
354
+ "react/no-deprecated",
290
355
  "react/no-find-dom-node",
291
356
  "react/no-is-mounted",
357
+ "react/no-multi-comp",
358
+ "react/no-redundant-should-component-update",
292
359
  "react/no-render-return-value",
360
+ "react/no-string-refs",
361
+ "react/no-this-in-sfc",
362
+ "react/no-typos",
293
363
  "react/no-unescaped-entities",
364
+ "react/no-unknown-property",
294
365
  "react/no-unused-prop-types",
366
+ "react/no-unused-state",
367
+ "react/no-will-update-set-state",
368
+ "react/prefer-es6-class",
295
369
  "react/prop-types",
370
+ "react/require-render-return",
371
+ "react/self-closing-comp",
372
+ "react/style-prop-object",
373
+ "react/void-dom-elements-no-children",
296
374
  "react-hooks/rules-of-hooks",
297
375
  "@typescript-eslint/adjacent-overload-signatures",
298
376
  "@typescript-eslint/array-type",
@@ -316,6 +394,7 @@ const BUILTIN_RULE_IDS = [
316
394
  "@typescript-eslint/no-extra-non-null-assertion",
317
395
  "@typescript-eslint/no-inferrable-types",
318
396
  "@typescript-eslint/no-invalid-void-type",
397
+ "@typescript-eslint/no-loop-func",
319
398
  "@typescript-eslint/no-loss-of-precision",
320
399
  "@typescript-eslint/no-misused-new",
321
400
  "@typescript-eslint/no-namespace",
@@ -389,7 +468,7 @@ export class UtooLint {
389
468
  this.options = { ...options };
390
469
  }
391
470
 
392
- async lintFiles(patterns = ["."], options = {}) {
471
+ async lintFiles(patterns, options = {}) {
393
472
  const mergedOptions = mergeLintOptions(this.options, options);
394
473
  const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
395
474
  const customRuleFilterMap = customRuleMapForConfig(customRuleConfig, new Map());
@@ -2424,6 +2503,152 @@ export function run(args = [], options = {}) {
2424
2503
  });
2425
2504
  }
2426
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
+
2427
2652
  export function runFishlint(args = [], options = {}) {
2428
2653
  const cliArgs = normalizeStringArray(args, "args");
2429
2654
  const env = options.env ? { ...process.env, ...options.env } : { ...process.env };
@@ -2636,14 +2861,15 @@ function booleanFlagValue(arg) {
2636
2861
  return true;
2637
2862
  }
2638
2863
 
2639
- export function lintFiles(paths = ["."], options = {}) {
2640
- return withTemporaryConfig(options, (resolvedOptions) => {
2641
- const ignoredDiagnostics = ignoredLintPathDiagnostics(paths, resolvedOptions);
2642
- const lintPaths = filteredLintPaths(paths, resolvedOptions);
2643
- if (lintPaths.length === 0) {
2644
- return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics.length > 0 ? 1 : 0 };
2645
- }
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
+ }
2646
2871
 
2872
+ return withTemporaryConfig(options, (resolvedOptions) => {
2647
2873
  const cliArgs = buildLintArgs(lintPaths, resolvedOptions);
2648
2874
  const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
2649
2875
 
@@ -2735,6 +2961,21 @@ export function lintText(code, options = {}) {
2735
2961
  }
2736
2962
 
2737
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) {
2738
2979
  const cliArgs = [];
2739
2980
 
2740
2981
  if (options.config) {
@@ -2753,7 +2994,9 @@ function buildLintArgs(paths, options) {
2753
2994
  cliArgs.push(`--threads=${options.threads}`);
2754
2995
  }
2755
2996
 
2756
- cliArgs.push("--format=json");
2997
+ if (options.format) {
2998
+ cliArgs.push(`--format=${options.format}`);
2999
+ }
2757
3000
 
2758
3001
  if (options.extraArgs) {
2759
3002
  cliArgs.push(...normalizeStringArray(options.extraArgs, "extraArgs"));
@@ -2960,6 +3203,37 @@ function configDataFromFileConfig(options, filePath) {
2960
3203
  return configDataFromConfig(config, filePath, options.cwd);
2961
3204
  }
2962
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
+
2963
3237
  function configAppliesToFile(config, filePath, cwd) {
2964
3238
  if (!filePath) {
2965
3239
  return true;
@@ -2984,6 +3258,9 @@ function normalizeConfigPatterns(patterns) {
2984
3258
  if (typeof value === "string") {
2985
3259
  return [value];
2986
3260
  }
3261
+ if (Array.isArray(value)) {
3262
+ return normalizeConfigPatterns(value);
3263
+ }
2987
3264
  return [];
2988
3265
  });
2989
3266
  }
@@ -3665,6 +3942,9 @@ function matchesIgnorePattern(target, pattern) {
3665
3942
  }
3666
3943
 
3667
3944
  function matchesConfigFilePattern(target, pattern) {
3945
+ if (!hasGlobSyntax(pattern)) {
3946
+ return target === pattern || target.startsWith(`${pattern}/`) || target.endsWith(`/${pattern}`);
3947
+ }
3668
3948
  const expression = new RegExp(`^${globPatternRegExpSource(pattern)}$`);
3669
3949
  return expression.test(target);
3670
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.0.9",
3
+ "version": "0.1.3",
4
4
  "description": "Experimental JavaScript and TypeScript linter powered by Yuku",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -70,14 +70,14 @@
70
70
  "use-at-your-own-risk.js"
71
71
  ],
72
72
  "optionalDependencies": {
73
- "@utoo/lint-darwin-arm64": "0.0.9",
74
- "@utoo/lint-darwin-x64": "0.0.9",
75
- "@utoo/lint-linux-arm64": "0.0.9",
76
- "@utoo/lint-linux-x64": "0.0.9",
77
- "@utoo/lint-win32-x64": "0.0.9"
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",
81
81
  "registry": "https://registry.npmjs.org/"
82
82
  }
83
- }
83
+ }