@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.
- package/dist/bin/index.mjs +1 -1
- package/dist/{cli-GIOYMybU.mjs → cli-D4YC9Jnb.mjs} +140 -15
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
package/dist/bin/index.mjs
CHANGED
|
@@ -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
|
-
|
|
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 =
|
|
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
|
-
|
|
954
|
-
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
}
|
|
960
|
-
|
|
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,
|
|
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
|
-
|
|
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-
|
|
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.
|
|
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/
|
|
29
|
-
"@alint-js/
|
|
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",
|