@alint-js/cli 0.0.28 → 0.0.30
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-DEGDq_sM.mjs → cli-fZkZ4dza.mjs} +200 -252
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -1
- package/package.json +6 -4
package/dist/bin/index.mjs
CHANGED
|
@@ -3,18 +3,20 @@ import { inspect } from "node:util";
|
|
|
3
3
|
import { cac } from "cac";
|
|
4
4
|
import { appendFile, mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
5
5
|
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, getStatsDir, installStaticPlugins, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
6
|
-
import { AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForDirectory, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
6
|
+
import { AlintRunCancelledError, AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForDirectory, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
7
7
|
import { isAbsolute, join, relative, resolve } from "pathe";
|
|
8
8
|
import { getBorderCharacters, table } from "table";
|
|
9
9
|
import { errorMessageFrom } from "@moeru/std/error";
|
|
10
|
-
import
|
|
10
|
+
import { createColors } from "tinyrainbow";
|
|
11
11
|
import cliSpinners from "cli-spinners";
|
|
12
12
|
import { relative as relative$1 } from "node:path";
|
|
13
|
+
import fastStringTruncatedWidth from "fast-string-truncated-width";
|
|
14
|
+
import fastStringWidth from "fast-string-width";
|
|
13
15
|
import Gitignore from "gitignore-fs";
|
|
14
16
|
import { Minimatch, minimatch } from "minimatch";
|
|
15
17
|
import { errorMessageFrom as errorMessageFrom$1 } from "@moeru/std";
|
|
16
18
|
//#region package.json
|
|
17
|
-
var version = "0.0.
|
|
19
|
+
var version = "0.0.30";
|
|
18
20
|
//#endregion
|
|
19
21
|
//#region src/cli/commands/command.ts
|
|
20
22
|
function defineCommand(node) {
|
|
@@ -190,7 +192,6 @@ function shouldSkipOptionValue(arg) {
|
|
|
190
192
|
"--cache-location",
|
|
191
193
|
"--config",
|
|
192
194
|
"--cwd",
|
|
193
|
-
"--file-concurrency",
|
|
194
195
|
"--format",
|
|
195
196
|
"--model",
|
|
196
197
|
"--provider-endpoint",
|
|
@@ -545,7 +546,7 @@ function formatJson(result) {
|
|
|
545
546
|
}
|
|
546
547
|
//#endregion
|
|
547
548
|
//#region src/cli/reporters/stylish.ts
|
|
548
|
-
const colors$
|
|
549
|
+
const colors$3 = createColors({ force: true });
|
|
549
550
|
function formatStylish(input, options = {}) {
|
|
550
551
|
const diagnostics = Array.isArray(input) ? input : input.diagnostics;
|
|
551
552
|
const result = Array.isArray(input) ? void 0 : input;
|
|
@@ -590,12 +591,12 @@ function createStyle(color) {
|
|
|
590
591
|
warning: identity
|
|
591
592
|
};
|
|
592
593
|
return {
|
|
593
|
-
error: colors$
|
|
594
|
-
file: colors$
|
|
595
|
-
location: colors$
|
|
596
|
-
ruleId: colors$
|
|
597
|
-
summaryToken: colors$
|
|
598
|
-
warning: colors$
|
|
594
|
+
error: colors$3.red,
|
|
595
|
+
file: colors$3.underline,
|
|
596
|
+
location: colors$3.dim,
|
|
597
|
+
ruleId: colors$3.dim,
|
|
598
|
+
summaryToken: colors$3.cyan,
|
|
599
|
+
warning: colors$3.yellow
|
|
599
600
|
};
|
|
600
601
|
}
|
|
601
602
|
function formatDiagnosticCount(total, cached, label) {
|
|
@@ -640,20 +641,19 @@ function formatDiagnostics(format, result, options = {}) {
|
|
|
640
641
|
function createPlainProgressReporter(options) {
|
|
641
642
|
const writeLine = (line) => options.write(`${line}\n`);
|
|
642
643
|
return {
|
|
643
|
-
|
|
644
|
-
const target = payload.
|
|
645
|
-
writeLine(`scan ${payload.
|
|
644
|
+
onJobStart: (payload) => {
|
|
645
|
+
const target = payload.job.target.name ? `${payload.job.target.kind} ${payload.job.target.name}` : payload.job.target.kind;
|
|
646
|
+
writeLine(`scan ${payload.job.inputPath} > ${target} > ${payload.job.ruleId}`);
|
|
646
647
|
},
|
|
647
648
|
onRunEnd: (payload) => {
|
|
648
649
|
const warnCount = countDiagnostics$1(payload.diagnostics, "warn");
|
|
649
650
|
const errorCount = countDiagnostics$1(payload.diagnostics, "error");
|
|
650
|
-
const state = payload.
|
|
651
|
-
const cached
|
|
652
|
-
|
|
653
|
-
writeLine(`alint ${state}: ${warnCount} warn, ${errorCount} error, ${payload.usage.totalTokens} tokens${cached}${errored}`);
|
|
651
|
+
const state = payload.execution.failed > 0 ? "failed" : "finished";
|
|
652
|
+
const { cached, cancelled, completed, failed, skipped } = payload.execution;
|
|
653
|
+
writeLine(`alint ${state}: ${warnCount} warn, ${errorCount} error, ${payload.usage.totalTokens} tokens, ${completed} completed, ${cached} cached, ${failed} failed, ${cancelled} cancelled, ${skipped} skipped`);
|
|
654
654
|
},
|
|
655
655
|
onRunStart: (payload) => {
|
|
656
|
-
writeLine(`alint started: ${payload.
|
|
656
|
+
writeLine(`alint started: ${payload.jobsTotal} queued jobs`);
|
|
657
657
|
}
|
|
658
658
|
};
|
|
659
659
|
}
|
|
@@ -662,217 +662,150 @@ function countDiagnostics$1(diagnostics, severity) {
|
|
|
662
662
|
}
|
|
663
663
|
//#endregion
|
|
664
664
|
//#region src/cli/reporters/progress/summary.ts
|
|
665
|
-
const colors$
|
|
665
|
+
const colors$2 = createColors({ force: true });
|
|
666
|
+
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
666
667
|
function createSummaryProgressReporter(options) {
|
|
667
668
|
const now = Date.now;
|
|
668
|
-
const state =
|
|
669
|
-
cached: 0,
|
|
670
|
-
completed: 0,
|
|
671
|
-
diagnostics: [],
|
|
672
|
-
errored: 0,
|
|
673
|
-
files: /* @__PURE__ */ new Map(),
|
|
674
|
-
planned: 0,
|
|
675
|
-
spinnerIndex: 0,
|
|
676
|
-
totalTokens: 0
|
|
677
|
-
};
|
|
669
|
+
const state = createInitialState();
|
|
678
670
|
return {
|
|
679
671
|
getRows: () => createRows(state, options, now()),
|
|
680
|
-
onDiagnostic: (
|
|
681
|
-
state.diagnostics
|
|
672
|
+
onDiagnostic: ({ diagnostic }) => {
|
|
673
|
+
state.diagnostics.push(diagnostic);
|
|
682
674
|
},
|
|
683
|
-
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
file.startedAt = payload.startedAt ?? now();
|
|
692
|
-
file.endedAt = void 0;
|
|
675
|
+
onJobEnd: (payload) => {
|
|
676
|
+
const current = state.jobs.get(payload.job.id);
|
|
677
|
+
state.jobs.set(payload.job.id, {
|
|
678
|
+
job: payload.job,
|
|
679
|
+
startedAt: payload.startedAt ?? current?.startedAt,
|
|
680
|
+
state: payload.state
|
|
681
|
+
});
|
|
682
|
+
transition(state.execution, "running", payload.state);
|
|
693
683
|
},
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
state
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
if (payload.state === "completed") {
|
|
701
|
-
state.completed += 1;
|
|
702
|
-
file.completed += 1;
|
|
703
|
-
}
|
|
704
|
-
if (payload.state === "errored") {
|
|
705
|
-
state.errored += 1;
|
|
706
|
-
file.errored += 1;
|
|
707
|
-
}
|
|
708
|
-
if (file.rule?.id === payload.path.rule.id) file.rule = void 0;
|
|
684
|
+
onJobQueued: ({ job }) => {
|
|
685
|
+
state.jobs.set(job.id, {
|
|
686
|
+
job,
|
|
687
|
+
state: "queued"
|
|
688
|
+
});
|
|
689
|
+
state.execution.queued += 1;
|
|
709
690
|
},
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
file.rule = {
|
|
714
|
-
id: payload.path.rule.id,
|
|
691
|
+
onJobStart: (payload) => {
|
|
692
|
+
state.jobs.set(payload.job.id, {
|
|
693
|
+
job: payload.job,
|
|
715
694
|
startedAt: payload.startedAt ?? now(),
|
|
716
|
-
|
|
717
|
-
};
|
|
718
|
-
|
|
695
|
+
state: "running"
|
|
696
|
+
});
|
|
697
|
+
transition(state.execution, "queued", "running");
|
|
719
698
|
},
|
|
720
699
|
onRunEnd: (payload) => {
|
|
721
|
-
state.
|
|
722
|
-
state.
|
|
723
|
-
state.diagnostics = payload.diagnostics;
|
|
724
|
-
state.endedAt = payload.endedAt ?? now();
|
|
725
|
-
state.errored = payload.errored;
|
|
726
|
-
state.planned = payload.planned;
|
|
727
|
-
state.runStartedAt = payload.startedAt ?? state.runStartedAt;
|
|
700
|
+
state.diagnostics = [...payload.diagnostics];
|
|
701
|
+
state.execution = { ...payload.execution };
|
|
728
702
|
state.totalTokens = payload.usage.totalTokens;
|
|
729
703
|
},
|
|
730
|
-
onRunStart: (
|
|
731
|
-
state.cached = 0;
|
|
732
|
-
state.completed = 0;
|
|
704
|
+
onRunStart: ({ jobsTotal }) => {
|
|
733
705
|
state.diagnostics = [];
|
|
734
|
-
state.
|
|
735
|
-
state.
|
|
736
|
-
state.files = /* @__PURE__ */ new Map();
|
|
737
|
-
state.planned = payload.planned;
|
|
738
|
-
state.runStartedAt = payload.startedAt ?? now();
|
|
706
|
+
state.execution = createCounts(jobsTotal);
|
|
707
|
+
state.jobs.clear();
|
|
739
708
|
state.spinnerIndex = 0;
|
|
740
709
|
state.totalTokens = 0;
|
|
741
|
-
for (const file of payload.files ?? []) state.files.set(file.path, createFileState(file));
|
|
742
|
-
},
|
|
743
|
-
onTargetEnd: (payload) => {
|
|
744
|
-
const file = getFileState(state, payload.path.file);
|
|
745
|
-
const target = formatTarget(payload);
|
|
746
|
-
if (file.target === target) file.target = void 0;
|
|
747
710
|
},
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
file.startedAt ??= payload.startedAt ?? now();
|
|
751
|
-
file.target = formatTarget(payload);
|
|
752
|
-
},
|
|
753
|
-
onUsage: (payload) => {
|
|
754
|
-
state.totalTokens = payload.total.totalTokens;
|
|
711
|
+
onUsage: ({ record }) => {
|
|
712
|
+
if (record.totalTokens != null && Number.isFinite(record.totalTokens)) state.totalTokens += record.totalTokens;
|
|
755
713
|
},
|
|
756
714
|
tick: () => {
|
|
757
715
|
state.spinnerIndex = (state.spinnerIndex + 1) % Math.max(options.spinnerFrames.length, 1);
|
|
758
716
|
}
|
|
759
717
|
};
|
|
760
718
|
}
|
|
719
|
+
function completeGraphemeBoundary(input, maximumIndex) {
|
|
720
|
+
let boundary = 0;
|
|
721
|
+
for (const segment of graphemeSegmenter.segment(input)) {
|
|
722
|
+
const end = segment.index + segment.segment.length;
|
|
723
|
+
if (end > maximumIndex) break;
|
|
724
|
+
boundary = end;
|
|
725
|
+
}
|
|
726
|
+
return boundary;
|
|
727
|
+
}
|
|
761
728
|
function countDiagnostics(diagnostics, severity) {
|
|
762
729
|
return diagnostics.filter((diagnostic) => diagnostic.severity === severity).length;
|
|
763
730
|
}
|
|
764
|
-
function
|
|
765
|
-
return [...state.files.values()].filter((file) => file.startedAt === void 0 && file.endedAt === void 0 && (file.file.planned ?? 0) > 0).length;
|
|
766
|
-
}
|
|
767
|
-
function createFileState(file) {
|
|
731
|
+
function createCounts(planned = 0) {
|
|
768
732
|
return {
|
|
769
733
|
cached: 0,
|
|
734
|
+
cancelled: 0,
|
|
770
735
|
completed: 0,
|
|
771
|
-
|
|
772
|
-
|
|
736
|
+
failed: 0,
|
|
737
|
+
planned,
|
|
738
|
+
queued: 0,
|
|
739
|
+
running: 0,
|
|
740
|
+
skipped: 0
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function createInitialState() {
|
|
744
|
+
return {
|
|
745
|
+
diagnostics: [],
|
|
746
|
+
execution: createCounts(),
|
|
747
|
+
jobs: /* @__PURE__ */ new Map(),
|
|
748
|
+
spinnerIndex: 0,
|
|
749
|
+
totalTokens: 0
|
|
773
750
|
};
|
|
774
751
|
}
|
|
775
752
|
function createRows(state, options, now) {
|
|
776
|
-
|
|
777
|
-
const queued = countQueuedFiles(state);
|
|
753
|
+
if (options.rows !== void 0 && options.rows <= 0) return [];
|
|
778
754
|
const warnCount = countDiagnostics(state.diagnostics, "warn");
|
|
779
755
|
const errorCount = countDiagnostics(state.diagnostics, "error");
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
rows.
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
return elapsedMs * planned / completed;
|
|
756
|
+
const runningJobs = [...state.jobs.values()].filter((job) => job.state === "running").sort((left, right) => left.job.index - right.job.index);
|
|
757
|
+
const footerRows = 1;
|
|
758
|
+
const separatorRows = options.rows === void 0 || options.rows >= 2 ? 1 : 0;
|
|
759
|
+
const contentBudget = options.rows === void 0 ? Number.POSITIVE_INFINITY : Math.max(options.rows - footerRows - separatorRows, 0);
|
|
760
|
+
const jobBudget = runningJobs.length > contentBudget ? Math.max(contentBudget - 1, 0) : contentBudget;
|
|
761
|
+
const visible = runningJobs.slice(0, jobBudget).map((job) => formatJobRow(job, state, options, now));
|
|
762
|
+
const hiddenJobs = runningJobs.length - visible.length;
|
|
763
|
+
if (hiddenJobs > 0 && contentBudget > 0) visible.push(fitRow(` └─ … ${hiddenJobs} more running jobs hidden`, options.columns));
|
|
764
|
+
if (separatorRows === 1) visible.push("");
|
|
765
|
+
visible.push(formatFooter(state, warnCount, errorCount, options));
|
|
766
|
+
return options.color ? visible.map((row) => styleRow(row, state, warnCount, errorCount, options)) : visible;
|
|
792
767
|
}
|
|
793
768
|
function fitRow(row, columns) {
|
|
794
769
|
if (columns <= 0) return "";
|
|
795
|
-
if (row
|
|
796
|
-
|
|
797
|
-
|
|
770
|
+
if (fastStringWidth(row) <= columns) return row;
|
|
771
|
+
let limit = columns;
|
|
772
|
+
while (limit > 0) {
|
|
773
|
+
const result = fastStringTruncatedWidth(row, {
|
|
774
|
+
ellipsis: "…",
|
|
775
|
+
limit
|
|
776
|
+
});
|
|
777
|
+
const index = completeGraphemeBoundary(row, result.index);
|
|
778
|
+
const visible = row.slice(0, index);
|
|
779
|
+
const fitted = `${visible}${visible.includes("\x1B") ? "\x1B[0m" : ""}${result.ellipsed ? "…" : ""}`;
|
|
780
|
+
const overflow = fastStringWidth(fitted) - columns;
|
|
781
|
+
if (overflow <= 0) return fitted;
|
|
782
|
+
limit -= overflow;
|
|
783
|
+
}
|
|
784
|
+
return "";
|
|
798
785
|
}
|
|
799
786
|
function formatDuration(ms) {
|
|
800
|
-
if (ms === void 0 || !Number.isFinite(ms)) return "?";
|
|
801
787
|
return `${(Math.max(ms, 0) / 1e3).toFixed(1)}s`;
|
|
802
788
|
}
|
|
803
|
-
function
|
|
804
|
-
|
|
805
|
-
}
|
|
806
|
-
function formatFilePath(filePath, cwd) {
|
|
807
|
-
if (!cwd) return filePath;
|
|
808
|
-
return relative$1(cwd, filePath) || filePath;
|
|
809
|
-
}
|
|
810
|
-
function formatFileRows(file, state, options, now) {
|
|
811
|
-
const firstRow = formatFileSummaryRow(file, state, options);
|
|
812
|
-
if (!file.rule) return [firstRow];
|
|
813
|
-
const elapsed = now - file.rule.startedAt;
|
|
814
|
-
const done = file.completed + file.cached + file.errored;
|
|
815
|
-
const estimated = estimateTotal(file.startedAt === void 0 ? elapsed : now - file.startedAt, done, file.file.planned ?? 0);
|
|
816
|
-
return [firstRow, fitRow(` ${file.rule.target} > ${file.rule.id} (${formatDuration(elapsed)}, ${formatEstimatedDuration(estimated)})`, options.columns)];
|
|
817
|
-
}
|
|
818
|
-
function formatFileSummaryRow(file, state, options) {
|
|
819
|
-
const prefix = `${options.spinnerFrames[state.spinnerIndex] ?? ""} ${formatFilePath(file.file.path, options.cwd)}`;
|
|
820
|
-
const counter = `${file.completed}/${file.cached}/${file.errored}/${file.file.planned ?? 0}`;
|
|
821
|
-
return fitRow(`${prefix}${" ".repeat(Math.max(1, options.columns - prefix.length - counter.length))}${counter}`, options.columns);
|
|
822
|
-
}
|
|
823
|
-
function formatFooter(state, warnCount, errorCount, queued, options, now) {
|
|
824
|
-
const endedAt = state.endedAt ?? now;
|
|
825
|
-
const elapsed = state.runStartedAt === void 0 ? void 0 : endedAt - state.runStartedAt;
|
|
826
|
-
const completed = state.completed + state.cached + state.errored;
|
|
827
|
-
const estimated = elapsed === void 0 ? void 0 : estimateTotal(elapsed, completed, state.planned);
|
|
828
|
-
const estimatedTokens = completed > 0 && state.planned > 0 ? Math.ceil(state.totalTokens * state.planned / completed).toLocaleString("en-US") : "?";
|
|
829
|
-
return fitRow([
|
|
830
|
-
`${formatDuration(elapsed)} -> ${formatEstimatedDuration(estimated)}`,
|
|
831
|
-
`${state.totalTokens.toLocaleString("en-US")} tokens -> ~${estimatedTokens} tokens`,
|
|
832
|
-
`${queued} queued / ${state.cached} cached / ${warnCount} warn / ${errorCount} error`
|
|
833
|
-
].join(" | "), options.columns);
|
|
834
|
-
}
|
|
835
|
-
function formatIdleRow(state, options) {
|
|
836
|
-
const prefix = `${options.spinnerFrames[state.spinnerIndex] ?? ""} alint`;
|
|
837
|
-
const counter = `${state.completed}/${state.cached}/${state.errored}/${state.planned}`;
|
|
838
|
-
return fitRow(`${prefix}${" ".repeat(Math.max(1, options.columns - prefix.length - counter.length))}${counter}`, options.columns);
|
|
839
|
-
}
|
|
840
|
-
function formatQueuedRow(queued, options) {
|
|
841
|
-
return fitRow(` ${queued} ${queued === 1 ? "file" : "files"} queued`, options.columns);
|
|
842
|
-
}
|
|
843
|
-
function formatTarget(payload) {
|
|
844
|
-
return payload.path.target.name ? `${payload.path.target.kind} ${payload.path.target.name}` : payload.path.target.kind;
|
|
845
|
-
}
|
|
846
|
-
function getActiveFiles(state) {
|
|
847
|
-
return [...state.files.values()].filter((file) => file.startedAt !== void 0 && file.endedAt === void 0).sort((left, right) => left.file.index - right.file.index);
|
|
848
|
-
}
|
|
849
|
-
function getFileState(state, file) {
|
|
850
|
-
const existingFile = state.files.get(file.path);
|
|
851
|
-
if (existingFile) {
|
|
852
|
-
existingFile.file = {
|
|
853
|
-
...existingFile.file,
|
|
854
|
-
...file,
|
|
855
|
-
planned: file.planned ?? existingFile.file.planned
|
|
856
|
-
};
|
|
857
|
-
return existingFile;
|
|
858
|
-
}
|
|
859
|
-
const nextFile = createFileState({
|
|
860
|
-
...file,
|
|
861
|
-
planned: file.planned ?? (state.files.size === 0 ? state.planned : void 0)
|
|
862
|
-
});
|
|
863
|
-
state.files.set(file.path, nextFile);
|
|
864
|
-
return nextFile;
|
|
789
|
+
function formatFooter(state, warnCount, errorCount, options) {
|
|
790
|
+
const { cached, failed, queued, running } = state.execution;
|
|
791
|
+
return fitRow(`${running} running / ${queued} queued / ${cached} cached / ${warnCount} warn / ${errorCount} error / ${failed} failed / ${state.totalTokens} tokens`, options.columns);
|
|
865
792
|
}
|
|
866
|
-
function
|
|
867
|
-
|
|
868
|
-
|
|
793
|
+
function formatJobRow(jobState, state, options, now) {
|
|
794
|
+
const spinner = options.spinnerFrames[state.spinnerIndex] ?? "";
|
|
795
|
+
const inputPath = options.cwd ? relative$1(options.cwd, jobState.job.inputPath) || "." : jobState.job.inputPath;
|
|
796
|
+
const target = jobState.job.target.name ? `${jobState.job.target.kind} ${jobState.job.target.name}` : jobState.job.target.kind;
|
|
797
|
+
const startedAt = jobState.startedAt ?? now;
|
|
798
|
+
return fitRow(`${spinner} ${inputPath} > ${target} > ${jobState.job.ruleId} (${formatDuration(now - startedAt)})`, options.columns);
|
|
869
799
|
}
|
|
870
800
|
function styleRow(row, state, warnCount, errorCount, options) {
|
|
871
801
|
let styledRow = row;
|
|
872
802
|
const spinner = options.spinnerFrames[state.spinnerIndex] ?? "";
|
|
873
|
-
if (spinner) styledRow =
|
|
874
|
-
|
|
875
|
-
|
|
803
|
+
if (spinner) styledRow = styledRow.replace(spinner, colors$2.cyan(spinner));
|
|
804
|
+
return styledRow.replace(/\//g, colors$2.gray("/")).replace(`${warnCount} warn`, colors$2.yellow(`${warnCount} warn`)).replace(`${errorCount} error`, (errorCount > 0 ? colors$2.red : colors$2.gray)(`${errorCount} error`)).replace(`${state.execution.failed} failed`, (state.execution.failed > 0 ? colors$2.red : colors$2.gray)(`${state.execution.failed} failed`));
|
|
805
|
+
}
|
|
806
|
+
function transition(counts, from, to) {
|
|
807
|
+
counts[from] -= 1;
|
|
808
|
+
counts[to] += 1;
|
|
876
809
|
}
|
|
877
810
|
//#endregion
|
|
878
811
|
//#region src/cli/reporters/progress/tty.ts
|
|
@@ -936,6 +869,7 @@ function createCliProgressReporter(options) {
|
|
|
936
869
|
color: options.color,
|
|
937
870
|
columns: options.columns,
|
|
938
871
|
cwd: options.cwd,
|
|
872
|
+
rows: options.rows,
|
|
939
873
|
spinnerFrames: cliSpinners.dots.frames
|
|
940
874
|
});
|
|
941
875
|
const renderer = createTtyProgressRenderer({
|
|
@@ -961,20 +895,16 @@ function createRenderingProgressReporter(summary, renderer) {
|
|
|
961
895
|
summary.onDiagnostic?.(payload);
|
|
962
896
|
renderer.render();
|
|
963
897
|
},
|
|
964
|
-
|
|
965
|
-
summary.
|
|
966
|
-
renderer.render();
|
|
967
|
-
},
|
|
968
|
-
onFileStart: (payload) => {
|
|
969
|
-
summary.onFileStart?.(payload);
|
|
898
|
+
onJobEnd: (payload) => {
|
|
899
|
+
summary.onJobEnd?.(payload);
|
|
970
900
|
renderer.render();
|
|
971
901
|
},
|
|
972
|
-
|
|
973
|
-
summary.
|
|
902
|
+
onJobQueued: (payload) => {
|
|
903
|
+
summary.onJobQueued?.(payload);
|
|
974
904
|
renderer.render();
|
|
975
905
|
},
|
|
976
|
-
|
|
977
|
-
summary.
|
|
906
|
+
onJobStart: (payload) => {
|
|
907
|
+
summary.onJobStart?.(payload);
|
|
978
908
|
renderer.render();
|
|
979
909
|
},
|
|
980
910
|
onRunEnd: (payload) => {
|
|
@@ -985,14 +915,6 @@ function createRenderingProgressReporter(summary, renderer) {
|
|
|
985
915
|
summary.onRunStart?.(payload);
|
|
986
916
|
renderer.start();
|
|
987
917
|
},
|
|
988
|
-
onTargetEnd: (payload) => {
|
|
989
|
-
summary.onTargetEnd?.(payload);
|
|
990
|
-
renderer.render();
|
|
991
|
-
},
|
|
992
|
-
onTargetStart: (payload) => {
|
|
993
|
-
summary.onTargetStart?.(payload);
|
|
994
|
-
renderer.render();
|
|
995
|
-
},
|
|
996
918
|
onUsage: (payload) => {
|
|
997
919
|
summary.onUsage?.(payload);
|
|
998
920
|
renderer.render();
|
|
@@ -1174,18 +1096,20 @@ async function walkFiles(root, options) {
|
|
|
1174
1096
|
}
|
|
1175
1097
|
//#endregion
|
|
1176
1098
|
//#region src/cli/commands/lint/errors.ts
|
|
1177
|
-
|
|
1178
|
-
|
|
1099
|
+
const colors$1 = createColors({ force: true });
|
|
1100
|
+
function formatCancelledError(error, color) {
|
|
1101
|
+
return `${color ? colors$1.red("error") : "error"} ${error.message}\n`;
|
|
1179
1102
|
}
|
|
1180
|
-
function
|
|
1181
|
-
const failure = error.failure;
|
|
1182
|
-
if (!failure) return "alint run failed";
|
|
1183
|
-
const target = failure.target ? failure.target.name ? `${failure.target.kind} ${failure.target.name}` : failure.target.kind : void 0;
|
|
1103
|
+
function formatRunError(error, color) {
|
|
1184
1104
|
return [
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
].
|
|
1105
|
+
`${color ? colors$1.red("error") : "error"} ${error.message}`,
|
|
1106
|
+
...error.failures.map(formatFailure),
|
|
1107
|
+
""
|
|
1108
|
+
].join("\n");
|
|
1109
|
+
}
|
|
1110
|
+
function formatFailure(failure) {
|
|
1111
|
+
const target = failure.job.target.name ? `${failure.job.target.kind} ${failure.job.target.name}` : failure.job.target.kind;
|
|
1112
|
+
return ` [${failure.kind}] ${failure.job.inputPath} > ${target} > ${failure.job.ruleId}: ${failure.message}`;
|
|
1189
1113
|
}
|
|
1190
1114
|
//#endregion
|
|
1191
1115
|
//#region src/cli/commands/lint/runner.ts
|
|
@@ -1198,14 +1122,12 @@ function resolveConfigRunner(config) {
|
|
|
1198
1122
|
function resolveRunnerConfig(setupConfig, config, options) {
|
|
1199
1123
|
const cache = resolveRunnerCacheConfig(setupConfig.runner?.cache, config.runner?.cache, options);
|
|
1200
1124
|
const stats = resolveRunnerStatsConfig(setupConfig.runner?.stats, config.runner?.stats, options);
|
|
1201
|
-
const fileConcurrency = parsePositiveIntegerOption(options.fileConcurrency, "--file-concurrency");
|
|
1202
1125
|
const ruleConcurrency = parsePositiveIntegerOption(options.ruleConcurrency, "--rule-concurrency");
|
|
1203
1126
|
const timeoutMs = parsePositiveIntegerOption(options.timeoutMs, "--timeout-ms");
|
|
1204
1127
|
const runner = {
|
|
1205
1128
|
...setupConfig.runner ?? {},
|
|
1206
1129
|
...config.runner ?? {},
|
|
1207
1130
|
cache,
|
|
1208
|
-
fileConcurrency: fileConcurrency ?? config.runner?.fileConcurrency ?? setupConfig.runner?.fileConcurrency,
|
|
1209
1131
|
ruleConcurrency: ruleConcurrency ?? config.runner?.ruleConcurrency ?? setupConfig.runner?.ruleConcurrency,
|
|
1210
1132
|
stats,
|
|
1211
1133
|
timeoutMs: timeoutMs ?? config.runner?.timeoutMs ?? setupConfig.runner?.timeoutMs
|
|
@@ -1450,8 +1372,9 @@ function toStatsUsageRecord(record) {
|
|
|
1450
1372
|
function createStatsCollector() {
|
|
1451
1373
|
const counts = {
|
|
1452
1374
|
cached: 0,
|
|
1375
|
+
cancelled: 0,
|
|
1453
1376
|
completed: 0,
|
|
1454
|
-
|
|
1377
|
+
failed: 0,
|
|
1455
1378
|
planned: 0
|
|
1456
1379
|
};
|
|
1457
1380
|
let startedAt;
|
|
@@ -1461,10 +1384,11 @@ function createStatsCollector() {
|
|
|
1461
1384
|
durationMs: () => startedAt !== void 0 && endedAt !== void 0 ? endedAt - startedAt : void 0,
|
|
1462
1385
|
reporter: {
|
|
1463
1386
|
onRunEnd: (payload) => {
|
|
1464
|
-
counts.cached = payload.cached;
|
|
1465
|
-
counts.
|
|
1466
|
-
counts.
|
|
1467
|
-
counts.
|
|
1387
|
+
counts.cached = payload.execution.cached;
|
|
1388
|
+
counts.cancelled = payload.execution.cancelled;
|
|
1389
|
+
counts.completed = payload.execution.completed;
|
|
1390
|
+
counts.failed = payload.execution.failed;
|
|
1391
|
+
counts.planned = payload.execution.planned;
|
|
1468
1392
|
endedAt = payload.endedAt;
|
|
1469
1393
|
},
|
|
1470
1394
|
onRunStart: (payload) => {
|
|
@@ -1476,46 +1400,50 @@ function createStatsCollector() {
|
|
|
1476
1400
|
function mergeProgressReporters(base, extra) {
|
|
1477
1401
|
if (!base) return extra;
|
|
1478
1402
|
if (!extra) return base;
|
|
1403
|
+
const baseState = {
|
|
1404
|
+
disabled: false,
|
|
1405
|
+
reporter: base
|
|
1406
|
+
};
|
|
1407
|
+
const extraState = {
|
|
1408
|
+
disabled: false,
|
|
1409
|
+
reporter: extra
|
|
1410
|
+
};
|
|
1411
|
+
let firstFailure;
|
|
1412
|
+
const deliver = (state, callback) => {
|
|
1413
|
+
if (state.disabled) return;
|
|
1414
|
+
try {
|
|
1415
|
+
callback(state.reporter);
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
state.disabled = true;
|
|
1418
|
+
firstFailure ??= normalizeReporterError(error);
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
const deliverBoth = (callback) => {
|
|
1422
|
+
deliver(baseState, callback);
|
|
1423
|
+
deliver(extraState, callback);
|
|
1424
|
+
};
|
|
1479
1425
|
return {
|
|
1480
1426
|
onDiagnostic: (payload) => {
|
|
1481
|
-
|
|
1482
|
-
extra.onDiagnostic?.(payload);
|
|
1427
|
+
deliverBoth((reporter) => reporter.onDiagnostic?.(payload));
|
|
1483
1428
|
},
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
extra.onFileEnd?.(payload);
|
|
1429
|
+
onJobEnd: (payload) => {
|
|
1430
|
+
deliverBoth((reporter) => reporter.onJobEnd?.(payload));
|
|
1487
1431
|
},
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
extra.onFileStart?.(payload);
|
|
1432
|
+
onJobQueued: (payload) => {
|
|
1433
|
+
deliverBoth((reporter) => reporter.onJobQueued?.(payload));
|
|
1491
1434
|
},
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
extra.onRuleEnd?.(payload);
|
|
1495
|
-
},
|
|
1496
|
-
onRuleStart: (payload) => {
|
|
1497
|
-
base.onRuleStart?.(payload);
|
|
1498
|
-
extra.onRuleStart?.(payload);
|
|
1435
|
+
onJobStart: (payload) => {
|
|
1436
|
+
deliverBoth((reporter) => reporter.onJobStart?.(payload));
|
|
1499
1437
|
},
|
|
1500
1438
|
onRunEnd: (payload) => {
|
|
1501
|
-
|
|
1502
|
-
|
|
1439
|
+
deliverBoth((reporter) => reporter.onRunEnd?.(payload));
|
|
1440
|
+
if (firstFailure) throw firstFailure;
|
|
1503
1441
|
},
|
|
1504
1442
|
onRunStart: (payload) => {
|
|
1505
|
-
|
|
1506
|
-
extra.onRunStart?.(payload);
|
|
1507
|
-
},
|
|
1508
|
-
onTargetEnd: (payload) => {
|
|
1509
|
-
base.onTargetEnd?.(payload);
|
|
1510
|
-
extra.onTargetEnd?.(payload);
|
|
1511
|
-
},
|
|
1512
|
-
onTargetStart: (payload) => {
|
|
1513
|
-
base.onTargetStart?.(payload);
|
|
1514
|
-
extra.onTargetStart?.(payload);
|
|
1443
|
+
deliverBoth((reporter) => reporter.onRunStart?.(payload));
|
|
1515
1444
|
},
|
|
1516
1445
|
onUsage: (payload) => {
|
|
1517
|
-
|
|
1518
|
-
extra.onUsage?.(payload);
|
|
1446
|
+
deliverBoth((reporter) => reporter.onUsage?.(payload));
|
|
1519
1447
|
}
|
|
1520
1448
|
};
|
|
1521
1449
|
}
|
|
@@ -1537,11 +1465,21 @@ async function writeRunStats(target, collector, result, cwd) {
|
|
|
1537
1465
|
await store.record(createRunStat({
|
|
1538
1466
|
cwd,
|
|
1539
1467
|
durationMs: collector.durationMs(),
|
|
1540
|
-
ruleCounts:
|
|
1468
|
+
ruleCounts: {
|
|
1469
|
+
cached: result.execution.cached,
|
|
1470
|
+
cancelled: result.execution.cancelled,
|
|
1471
|
+
completed: result.execution.completed,
|
|
1472
|
+
failed: result.execution.failed,
|
|
1473
|
+
planned: result.execution.planned
|
|
1474
|
+
},
|
|
1541
1475
|
usage: result.usage
|
|
1542
1476
|
}));
|
|
1543
1477
|
} catch {}
|
|
1544
1478
|
}
|
|
1479
|
+
function normalizeReporterError(error) {
|
|
1480
|
+
if (error instanceof Error) return error;
|
|
1481
|
+
return new Error(error != null ? String(error) : "Unknown progress reporter error.");
|
|
1482
|
+
}
|
|
1545
1483
|
//#endregion
|
|
1546
1484
|
//#region src/cli/commands/lint/index.ts
|
|
1547
1485
|
const lint = defineCommand({
|
|
@@ -1592,11 +1530,15 @@ async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
|
1592
1530
|
columns: io.stderr.columns ?? 80,
|
|
1593
1531
|
cwd: io.cwd,
|
|
1594
1532
|
isTty: io.stderr.isTTY === true,
|
|
1533
|
+
rows: io.stderr.rows,
|
|
1595
1534
|
write: (chunk) => io.stderr.write(chunk)
|
|
1596
1535
|
}) : void 0;
|
|
1597
1536
|
const restoreProgressConsole = progress ? interceptConsoleOutput({ write: progress.write }) : void 0;
|
|
1598
1537
|
const statsTarget = resolveStatsWrite(runner?.stats, io.env);
|
|
1599
1538
|
const statsCollector = statsTarget ? createStatsCollector() : void 0;
|
|
1539
|
+
const persistStats = async (runResult) => {
|
|
1540
|
+
if (statsTarget && statsCollector) await writeRunStats(statsTarget, statsCollector, runResult, io.cwd);
|
|
1541
|
+
};
|
|
1600
1542
|
let result;
|
|
1601
1543
|
try {
|
|
1602
1544
|
result = await runAlint({
|
|
@@ -1614,14 +1556,20 @@ async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
|
1614
1556
|
restoreProgressConsole?.();
|
|
1615
1557
|
progress?.dispose();
|
|
1616
1558
|
if (error instanceof AlintRunError) {
|
|
1559
|
+
await persistStats(error.result);
|
|
1617
1560
|
io.stderr.write(formatRunError(error, io.stderr.isTTY === true));
|
|
1618
1561
|
return 2;
|
|
1619
1562
|
}
|
|
1563
|
+
if (error instanceof AlintRunCancelledError) {
|
|
1564
|
+
await persistStats(error.result);
|
|
1565
|
+
io.stderr.write(formatCancelledError(error, io.stderr.isTTY === true));
|
|
1566
|
+
return 2;
|
|
1567
|
+
}
|
|
1620
1568
|
throw error;
|
|
1621
1569
|
}
|
|
1622
1570
|
restoreProgressConsole?.();
|
|
1623
1571
|
progress?.dispose();
|
|
1624
|
-
|
|
1572
|
+
await persistStats(result);
|
|
1625
1573
|
io.stdout.write(formatDiagnostics(options.format, result, { color: io.stdout.isTTY === true }));
|
|
1626
1574
|
return result.diagnostics.some((diagnostic) => diagnostic.severity === "error") ? 1 : 0;
|
|
1627
1575
|
}
|
|
@@ -2292,7 +2240,7 @@ async function executeCli(argv, io) {
|
|
|
2292
2240
|
pendingResult = result;
|
|
2293
2241
|
return result;
|
|
2294
2242
|
};
|
|
2295
|
-
cli.option("--no-cache", "Disable cache for this run").option("--cache-location <path>", "Path to the alint cache file or directory").option("-c, --config <path>", "Path to alint config file").option("--
|
|
2243
|
+
cli.option("--no-cache", "Disable cache for this run").option("--cache-location <path>", "Path to the alint cache file or directory").option("-c, --config <path>", "Path to alint config file").option("--format <format>", "Reporter format", { default: "stylish" }).option("--model <model>", "Force a model override").option("-l, --lang <language>", "Ask model-backed rules to write diagnostics in this language").option("--progress", "Show run progress").option("--rule-concurrency <count>", "Maximum rule executions across the entire run").option("--no-stats", "Do not record run stats for this run").option("--timeout-ms <ms>", "Rule execution timeout in milliseconds").version(version).help();
|
|
2296
2244
|
registerCommandTree(cli, commandTree, {
|
|
2297
2245
|
globalOptions,
|
|
2298
2246
|
interceptConsoleOutput,
|
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-fZkZ4dza.mjs";
|
|
2
2
|
import { ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated } from "@alint-js/config";
|
|
3
3
|
import { defineConfig } from "@alint-js/core";
|
|
4
4
|
export { defineConfig, executeCli, formatDiagnostics, formatJson, formatStylish, ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated };
|
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.30",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -17,16 +17,18 @@
|
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@clack/prompts": "^1.7.0",
|
|
20
|
-
"@moeru/std": "^0.1.0-beta.
|
|
20
|
+
"@moeru/std": "^0.1.0-beta.20",
|
|
21
21
|
"cac": "^7.0.0",
|
|
22
22
|
"cli-spinners": "^3.4.0",
|
|
23
|
+
"fast-string-truncated-width": "^3.0.3",
|
|
24
|
+
"fast-string-width": "^3.0.2",
|
|
23
25
|
"gitignore-fs": "^2.2.3",
|
|
24
26
|
"minimatch": "^10.2.5",
|
|
25
27
|
"pathe": "^2.0.3",
|
|
26
28
|
"table": "^6.9.0",
|
|
27
29
|
"tinyrainbow": "^3.1.0",
|
|
28
|
-
"@alint-js/
|
|
29
|
-
"@alint-js/
|
|
30
|
+
"@alint-js/core": "0.0.30",
|
|
31
|
+
"@alint-js/config": "0.0.30"
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
32
34
|
"@pnpm/find-workspace-dir": "^1000.1.5",
|