@alint-js/cli 0.0.9 → 0.0.10

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as executeCli } from "../cli-GIOYMybU.mjs";
2
+ import { t as executeCli } from "../cli-D4YC9Jnb.mjs";
3
3
  import process from "node:process";
4
4
  //#region src/bin/index.ts
5
5
  executeCli(process.argv, {
@@ -3,7 +3,7 @@ import { inspect } from "node:util";
3
3
  import { cac } from "cac";
4
4
  import { getGlobalSetupConfigPath, getProjectSetupConfigPath, getStatsDir, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
5
5
  import { AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForFile, runAlint } from "@alint-js/core";
6
- import { join, relative, resolve } from "pathe";
6
+ import { isAbsolute, join, relative, resolve } from "pathe";
7
7
  import { getBorderCharacters, table } from "table";
8
8
  import { errorMessageFrom } from "@moeru/std/error";
9
9
  import { appendFile, mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
@@ -11,7 +11,7 @@ import c, { createColors } from "tinyrainbow";
11
11
  import cliSpinners from "cli-spinners";
12
12
  import { relative as relative$1 } from "node:path";
13
13
  import Gitignore from "gitignore-fs";
14
- import { minimatch } from "minimatch";
14
+ import { Minimatch, minimatch } from "minimatch";
15
15
  import { errorMessageFrom as errorMessageFrom$1 } from "@moeru/std";
16
16
  //#region src/cli/commands/command.ts
17
17
  function defineCommand(node) {
@@ -936,9 +936,28 @@ function createRenderingProgressReporter(summary, renderer) {
936
936
  }
937
937
  //#endregion
938
938
  //#region src/cli/commands/lint/discovery.ts
939
- async function resolveLintFiles(files, config, cwd) {
939
+ const minimatchOptions = { dot: true };
940
+ var NoFilesFoundError = class extends Error {
941
+ globInputPaths;
942
+ pattern;
943
+ constructor(pattern, options) {
944
+ super(`No files matching "${pattern}" were found${options.globInputPaths ? "" : " (glob input is disabled)"}.`);
945
+ this.name = "NoFilesFoundError";
946
+ this.globInputPaths = options.globInputPaths;
947
+ this.pattern = pattern;
948
+ }
949
+ };
950
+ async function findFiles(options) {
951
+ const { config, cwd, errorOnUnmatchedPattern = true, globInputPaths = true, inputs } = options;
940
952
  const gitignore = shouldFilterGitignoredFiles(config) ? new Gitignore() : void 0;
941
- const candidates = files.length > 0 ? files : await discoverLintFiles(config, cwd, gitignore);
953
+ const candidates = await resolveInputFiles({
954
+ config,
955
+ cwd,
956
+ errorOnUnmatchedPattern,
957
+ gitignore,
958
+ globInputPaths,
959
+ inputs: inputs.length > 0 ? inputs : ["."]
960
+ });
942
961
  if (!gitignore || candidates.length === 0) return candidates;
943
962
  const lintFiles = [];
944
963
  for (const file of candidates) {
@@ -950,31 +969,122 @@ async function resolveLintFiles(files, config, cwd) {
950
969
  function collectGlobalIgnorePatterns(config) {
951
970
  return normalizeConfig(config).flatMap((item) => isGlobalIgnoreItem(item) ? [...item.ignores] : []);
952
971
  }
953
- async function discoverLintFiles(config, cwd, gitignore) {
954
- if (!hasDiscoveryFilePatterns(config)) return [];
955
- const candidates = (await walkFiles(cwd, {
956
- cwd,
957
- gitignore,
958
- ignoredPatterns: collectGlobalIgnorePatterns(config)
959
- })).map((file) => normalizeRelativePath(cwd, file)).filter((file) => matchesDiscoveryFile(file, config, { cwd }));
960
- return [...new Set(candidates)].sort();
972
+ function getGlobParent(input) {
973
+ const segments = input.replaceAll("\\", "/").split("/");
974
+ const parentSegments = [];
975
+ for (const segment of segments) {
976
+ if (isGlobPattern(segment)) break;
977
+ parentSegments.push(segment);
978
+ }
979
+ const parent = parentSegments.join("/");
980
+ return parent === "" ? "." : parent;
961
981
  }
962
982
  function isGlobalIgnoreItem(item) {
963
983
  const keys = Object.keys(item).filter((key) => item[key] !== void 0);
964
984
  return item.ignores !== void 0 && keys.every((key) => key === "ignores" || key === "name");
965
985
  }
986
+ function isGlobPattern(input) {
987
+ return new Minimatch(input, minimatchOptions).hasMagic();
988
+ }
989
+ function isNodeError$1(error) {
990
+ return error instanceof Error && "code" in error;
991
+ }
992
+ function matchesGlob(filePath, pattern) {
993
+ return minimatch(filePath, pattern.replaceAll("\\", "/"), minimatchOptions);
994
+ }
966
995
  function matchesIgnoredDirectory(relativePath, patterns) {
967
- return patterns.some((pattern) => minimatch(relativePath, pattern, { dot: true }) || minimatch(`${relativePath}/`, pattern, { dot: true }) || minimatch(`${relativePath}/__alint__`, pattern, { dot: true }));
996
+ return patterns.some((pattern) => minimatch(relativePath, pattern, minimatchOptions) || minimatch(`${relativePath}/`, pattern, minimatchOptions) || minimatch(`${relativePath}/__alint__`, pattern, minimatchOptions));
997
+ }
998
+ function normalizeGlobPattern(cwd, pattern) {
999
+ return isAbsolute(pattern) ? normalizeRelativePath(cwd, pattern) : pattern.replaceAll("\\", "/");
968
1000
  }
969
1001
  function normalizeRelativePath(cwd, filePath) {
970
1002
  return relative(cwd, filePath).replaceAll("\\", "/");
971
1003
  }
1004
+ async function resolveInputFiles(options) {
1005
+ const hasFilePatterns = hasDiscoveryFilePatterns(options.config);
1006
+ const ignoredPatterns = collectGlobalIgnorePatterns(options.config);
1007
+ const candidates = [];
1008
+ for (const input of options.inputs) {
1009
+ const path = resolve(options.cwd, input);
1010
+ const stats = await statPath(path);
1011
+ if (stats?.isFile()) {
1012
+ candidates.push(input);
1013
+ continue;
1014
+ }
1015
+ if (stats?.isDirectory()) {
1016
+ if (!hasFilePatterns) continue;
1017
+ if (await shouldPruneDirectory(path, {
1018
+ cwd: options.cwd,
1019
+ gitignore: options.gitignore,
1020
+ ignoredPatterns
1021
+ })) continue;
1022
+ const directoryFiles = (await walkFiles(path, {
1023
+ cwd: options.cwd,
1024
+ gitignore: options.gitignore,
1025
+ ignoredPatterns
1026
+ })).sort();
1027
+ for (const directoryFile of directoryFiles) {
1028
+ const relativePath = normalizeRelativePath(options.cwd, directoryFile);
1029
+ if (hasFilePatterns && matchesDiscoveryFile(relativePath, options.config, { cwd: options.cwd })) candidates.push(relativePath);
1030
+ }
1031
+ continue;
1032
+ }
1033
+ if (options.globInputPaths && isGlobPattern(input)) {
1034
+ const matches = await searchGlob({
1035
+ config: options.config,
1036
+ cwd: options.cwd,
1037
+ gitignore: options.gitignore,
1038
+ hasFilePatterns,
1039
+ ignoredPatterns,
1040
+ pattern: input
1041
+ });
1042
+ if (matches.length === 0 && options.errorOnUnmatchedPattern) throw new NoFilesFoundError(input, { globInputPaths: options.globInputPaths });
1043
+ candidates.push(...matches);
1044
+ continue;
1045
+ }
1046
+ if (options.errorOnUnmatchedPattern) throw new NoFilesFoundError(input, { globInputPaths: options.globInputPaths });
1047
+ }
1048
+ return [...new Set(candidates)];
1049
+ }
1050
+ async function searchGlob(options) {
1051
+ const root = resolve(options.cwd, getGlobParent(options.pattern));
1052
+ const rootStats = await statPath(root);
1053
+ const pattern = normalizeGlobPattern(options.cwd, options.pattern);
1054
+ if (!rootStats?.isDirectory()) return [];
1055
+ const files = (await walkFiles(root, {
1056
+ cwd: options.cwd,
1057
+ gitignore: options.gitignore,
1058
+ ignoredPatterns: options.ignoredPatterns
1059
+ })).sort();
1060
+ const candidates = [];
1061
+ for (const file of files) {
1062
+ const relativePath = normalizeRelativePath(options.cwd, file);
1063
+ if (matchesGlob(relativePath, pattern) && shouldIncludeGlobCandidate(relativePath, options.config, {
1064
+ cwd: options.cwd,
1065
+ hasFilePatterns: options.hasFilePatterns
1066
+ })) candidates.push(relativePath);
1067
+ }
1068
+ return candidates;
1069
+ }
972
1070
  function shouldFilterGitignoredFiles(config) {
973
1071
  return normalizeConfig(config).some((item) => item.ignore?.gitignore === true);
974
1072
  }
1073
+ function shouldIncludeGlobCandidate(filePath, config, options) {
1074
+ if (options.hasFilePatterns) return matchesDiscoveryFile(filePath, config, { cwd: options.cwd });
1075
+ return !resolveConfigForFile(filePath, config, { cwd: options.cwd }).ignored;
1076
+ }
975
1077
  async function shouldPruneDirectory(path, options) {
976
1078
  if (matchesIgnoredDirectory(normalizeRelativePath(options.cwd, path), options.ignoredPatterns)) return true;
977
- return await options.gitignore?.ignores(path) === true;
1079
+ return await options.gitignore?.ignores(`${path}/`) === true;
1080
+ }
1081
+ async function statPath(path) {
1082
+ try {
1083
+ return await stat(path);
1084
+ } catch (error) {
1085
+ if (isNodeError$1(error) && (error.code === "ENOENT" || error.code === "ENOTDIR")) return;
1086
+ throw error;
1087
+ }
978
1088
  }
979
1089
  async function walkFiles(root, options) {
980
1090
  const entries = await readdir(root, { withFileTypes: true });
@@ -1388,7 +1498,22 @@ function isNodeError(error) {
1388
1498
  async function runLintCommand(files, options, io, interceptConsoleOutput) {
1389
1499
  if (options.config) await assertConfigExists(io.cwd, options.config);
1390
1500
  const [setupConfig, config] = await Promise.all([loadMergedSetupConfig(io), loadAlintConfig(io.cwd, options.config)]);
1391
- const lintFiles = await resolveLintFiles(files, config, io.cwd);
1501
+ let lintFiles;
1502
+ try {
1503
+ lintFiles = await findFiles({
1504
+ config,
1505
+ cwd: io.cwd,
1506
+ errorOnUnmatchedPattern: true,
1507
+ globInputPaths: true,
1508
+ inputs: files
1509
+ });
1510
+ } catch (error) {
1511
+ if (error instanceof NoFilesFoundError) {
1512
+ io.stderr.write(`${error.message}\n`);
1513
+ return 2;
1514
+ }
1515
+ throw error;
1516
+ }
1392
1517
  const runner = resolveRunnerConfig(setupConfig, { runner: resolveConfigRunner(config) }, options);
1393
1518
  const progress = shouldEnableProgress(options, io) ? createCliProgressReporter({
1394
1519
  color: io.stderr.isTTY === true,
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-GIOYMybU.mjs";
1
+ import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-D4YC9Jnb.mjs";
2
2
  export { executeCli, formatDiagnostics, formatJson, formatStylish };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alint-js/cli",
3
3
  "type": "module",
4
- "version": "0.0.9",
4
+ "version": "0.0.10",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.mts",
@@ -25,8 +25,8 @@
25
25
  "pathe": "^2.0.3",
26
26
  "table": "^6.9.0",
27
27
  "tinyrainbow": "^3.1.0",
28
- "@alint-js/config": "0.0.9",
29
- "@alint-js/core": "0.0.9"
28
+ "@alint-js/core": "0.0.10",
29
+ "@alint-js/config": "0.0.10"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^26.0.1",