@visulima/vis 1.0.0-alpha.1 → 1.0.0-alpha.11
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/CHANGELOG.md +403 -12
- package/LICENSE.md +283 -0
- package/README.md +254 -9
- package/dist/bin.js +9 -146
- package/dist/config/index.d.ts +1818 -0
- package/dist/config/index.js +2 -0
- package/dist/generate/index.d.ts +157 -0
- package/dist/generate/index.js +3 -0
- package/dist/packem_chunks/applyDefaults.js +336 -0
- package/dist/packem_chunks/bin.js +9577 -0
- package/dist/packem_chunks/doctor-probe.js +112 -0
- package/dist/packem_chunks/fix.js +234 -0
- package/dist/packem_chunks/handler.js +99 -0
- package/dist/packem_chunks/handler10.js +53 -0
- package/dist/packem_chunks/handler11.js +32 -0
- package/dist/packem_chunks/handler12.js +100 -0
- package/dist/packem_chunks/handler13.js +25 -0
- package/dist/packem_chunks/handler14.js +916 -0
- package/dist/packem_chunks/handler15.js +206 -0
- package/dist/packem_chunks/handler16.js +124 -0
- package/dist/packem_chunks/handler17.js +13 -0
- package/dist/packem_chunks/handler18.js +106 -0
- package/dist/packem_chunks/handler19.js +19 -0
- package/dist/packem_chunks/handler2.js +75 -0
- package/dist/packem_chunks/handler20.js +29 -0
- package/dist/packem_chunks/handler21.js +222 -0
- package/dist/packem_chunks/handler22.js +237 -0
- package/dist/packem_chunks/handler23.js +101 -0
- package/dist/packem_chunks/handler24.js +110 -0
- package/dist/packem_chunks/handler25.js +402 -0
- package/dist/packem_chunks/handler26.js +13 -0
- package/dist/packem_chunks/handler27.js +63 -0
- package/dist/packem_chunks/handler28.js +34 -0
- package/dist/packem_chunks/handler29.js +458 -0
- package/dist/packem_chunks/handler3.js +95 -0
- package/dist/packem_chunks/handler30.js +170 -0
- package/dist/packem_chunks/handler31.js +530 -0
- package/dist/packem_chunks/handler32.js +214 -0
- package/dist/packem_chunks/handler33.js +119 -0
- package/dist/packem_chunks/handler34.js +630 -0
- package/dist/packem_chunks/handler35.js +283 -0
- package/dist/packem_chunks/handler36.js +542 -0
- package/dist/packem_chunks/handler37.js +762 -0
- package/dist/packem_chunks/handler38.js +989 -0
- package/dist/packem_chunks/handler39.js +574 -0
- package/dist/packem_chunks/handler4.js +90 -0
- package/dist/packem_chunks/handler40.js +1685 -0
- package/dist/packem_chunks/handler41.js +1088 -0
- package/dist/packem_chunks/handler42.js +797 -0
- package/dist/packem_chunks/handler43.js +2658 -0
- package/dist/packem_chunks/handler44.js +3886 -0
- package/dist/packem_chunks/handler45.js +2574 -0
- package/dist/packem_chunks/handler46.js +3769 -0
- package/dist/packem_chunks/handler47.js +1491 -0
- package/dist/packem_chunks/handler5.js +174 -0
- package/dist/packem_chunks/handler6.js +95 -0
- package/dist/packem_chunks/handler7.js +115 -0
- package/dist/packem_chunks/handler8.js +12 -0
- package/dist/packem_chunks/handler9.js +29 -0
- package/dist/packem_chunks/heal-accept.js +522 -0
- package/dist/packem_chunks/heal.js +673 -0
- package/dist/packem_chunks/index.js +873 -0
- package/dist/packem_chunks/loader.js +23 -0
- package/dist/packem_shared/VisUpdateApp-D-Yz_wvg.js +1316 -0
- package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +5 -0
- package/dist/packem_shared/ai-analysis-CHeB1joD.js +367 -0
- package/dist/packem_shared/ai-cache-Be_jexe4.js +142 -0
- package/dist/packem_shared/ai-fix-B9iQVcD2.js +379 -0
- package/dist/packem_shared/cache-directory-2qvs4goY.js +98 -0
- package/dist/packem_shared/catalog-BJTtyi-O.js +1371 -0
- package/dist/packem_shared/dependency-scan-A0KSklpG.js +188 -0
- package/dist/packem_shared/docker-2iZzc280.js +181 -0
- package/dist/packem_shared/failure-log-Cz3Z4SKL.js +100 -0
- package/dist/packem_shared/flakiness-goTxXuCX.js +180 -0
- package/dist/packem_shared/otel-DCvqCTz_.js +158 -0
- package/dist/packem_shared/otelPlugin-DFaLDvJf.js +3 -0
- package/dist/packem_shared/registry-CbqXI0rc.js +272 -0
- package/dist/packem_shared/run-summary-utils-PVMl4aIh.js +130 -0
- package/dist/packem_shared/runtime-check-Cobi3p6l.js +127 -0
- package/dist/packem_shared/selectors-SM69TfqC.js +194 -0
- package/dist/packem_shared/symbols-Ta7g2nU-.js +14 -0
- package/dist/packem_shared/toolchain-BdZd9eBi.js +975 -0
- package/dist/packem_shared/typosquats-C-bCh3PX.js +1210 -0
- package/dist/packem_shared/use-measured-height-CNP0vT4M.js +20 -0
- package/dist/packem_shared/utils-CthVdBPS.js +40 -0
- package/dist/packem_shared/xxh3-Ck8mXNg1.js +239 -0
- package/index.js +773 -0
- package/package.json +82 -21
- package/schemas/project.schema.json +420 -0
- package/schemas/vis-config.schema.json +501 -0
- package/skills/vis/SKILL.md +96 -0
- package/templates/buildkite-ci/.buildkite/pipeline.yml.tera +85 -0
- package/templates/buildkite-ci/template.yml +20 -0
- package/dist/ai-analysis.d.ts +0 -40
- package/dist/ai-cache.d.ts +0 -21
- package/dist/bin.d.ts +0 -1
- package/dist/catalog.d.ts +0 -110
- package/dist/commands/affected.d.ts +0 -3
- package/dist/commands/ai.d.ts +0 -3
- package/dist/commands/analyze.d.ts +0 -3
- package/dist/commands/check.d.ts +0 -3
- package/dist/commands/graph.d.ts +0 -3
- package/dist/commands/hook/constants.d.ts +0 -8
- package/dist/commands/hook/index.d.ts +0 -3
- package/dist/commands/hook/install.d.ts +0 -7
- package/dist/commands/hook/migrate.d.ts +0 -27
- package/dist/commands/hook/uninstall.d.ts +0 -3
- package/dist/commands/migrate/constants.d.ts +0 -12
- package/dist/commands/migrate/deps.d.ts +0 -32
- package/dist/commands/migrate/index.d.ts +0 -3
- package/dist/commands/migrate/json.d.ts +0 -20
- package/dist/commands/migrate/lint-staged.d.ts +0 -62
- package/dist/commands/migrate/types.d.ts +0 -20
- package/dist/commands/run.d.ts +0 -3
- package/dist/commands/staged.d.ts +0 -3
- package/dist/commands/update.d.ts +0 -3
- package/dist/config.d.ts +0 -40
- package/dist/config.js +0 -1
- package/dist/package-manager.d.ts +0 -23
- package/dist/workspace.d.ts +0 -58
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { readLastRunSummary } from '@visulima/task-runner';
|
|
2
|
+
import { p as pail } from './bin.js';
|
|
3
|
+
import { l as listRunSummaries, r as readRunSummaryById } from '../packem_shared/run-summary-utils-PVMl4aIh.js';
|
|
4
|
+
|
|
5
|
+
const VALID_FORMATS = /* @__PURE__ */ new Set(["json", "table"]);
|
|
6
|
+
const resolveWorkspaceRoot = (workspaceRoot) => workspaceRoot ?? process.cwd();
|
|
7
|
+
const formatDuration = (ms) => {
|
|
8
|
+
if (ms === void 0) {
|
|
9
|
+
return "-";
|
|
10
|
+
}
|
|
11
|
+
if (ms < 1e3) {
|
|
12
|
+
return `${String(ms)}ms`;
|
|
13
|
+
}
|
|
14
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
15
|
+
};
|
|
16
|
+
const formatStatus = (task) => {
|
|
17
|
+
if (task.exitCode === void 0) {
|
|
18
|
+
return task.cacheStatus;
|
|
19
|
+
}
|
|
20
|
+
if (task.exitCode === 0) {
|
|
21
|
+
return task.cacheStatus === "MISS" ? "OK" : task.cacheStatus;
|
|
22
|
+
}
|
|
23
|
+
return `FAIL(${String(task.exitCode)})`;
|
|
24
|
+
};
|
|
25
|
+
const padCell = (value, width) => {
|
|
26
|
+
if (value.length >= width) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
return value + " ".repeat(width - value.length);
|
|
30
|
+
};
|
|
31
|
+
const isFailedTask = (task) => task.exitCode !== void 0 && task.exitCode !== 0;
|
|
32
|
+
const renderRunHeader = (summary, logger) => {
|
|
33
|
+
logger.info(`Run ${summary.id}`);
|
|
34
|
+
logger.info(` start: ${summary.startTime}`);
|
|
35
|
+
logger.info(` end: ${summary.endTime}`);
|
|
36
|
+
logger.info(` duration: ${formatDuration(summary.duration)}`);
|
|
37
|
+
logger.info(
|
|
38
|
+
` totals: ${String(summary.stats.total)} total · ${String(summary.stats.succeeded)} ok · ${String(summary.stats.cached)} cached · ${String(summary.stats.skipped)} skipped · ${String(summary.stats.failed)} failed`
|
|
39
|
+
);
|
|
40
|
+
logger.info(` env: node ${summary.environment.nodeVersion} · ${summary.environment.platform}/${summary.environment.arch}`);
|
|
41
|
+
logger.info("");
|
|
42
|
+
};
|
|
43
|
+
const renderTaskTable = (tasks, logger) => {
|
|
44
|
+
if (tasks.length === 0) {
|
|
45
|
+
logger.info("(no tasks match the current filter)");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const rows = tasks.map((task) => ({
|
|
49
|
+
duration: formatDuration(task.duration),
|
|
50
|
+
hash: task.hash ? task.hash.slice(0, 12) : "-",
|
|
51
|
+
status: formatStatus(task),
|
|
52
|
+
taskId: task.taskId
|
|
53
|
+
}));
|
|
54
|
+
const widths = {
|
|
55
|
+
duration: Math.max("duration".length, ...rows.map((r) => r.duration.length)),
|
|
56
|
+
hash: Math.max("hash".length, ...rows.map((r) => r.hash.length)),
|
|
57
|
+
status: Math.max("status".length, ...rows.map((r) => r.status.length)),
|
|
58
|
+
taskId: Math.max("task".length, ...rows.map((r) => r.taskId.length))
|
|
59
|
+
};
|
|
60
|
+
logger.info(
|
|
61
|
+
` ${padCell("task", widths.taskId)} ${padCell("status", widths.status)} ${padCell("duration", widths.duration)} ${padCell("hash", widths.hash)}`
|
|
62
|
+
);
|
|
63
|
+
logger.info(` ${"-".repeat(widths.taskId)} ${"-".repeat(widths.status)} ${"-".repeat(widths.duration)} ${"-".repeat(widths.hash)}`);
|
|
64
|
+
for (const row of rows) {
|
|
65
|
+
logger.info(
|
|
66
|
+
` ${padCell(row.taskId, widths.taskId)} ${padCell(row.status, widths.status)} ${padCell(row.duration, widths.duration)} ${padCell(row.hash, widths.hash)}`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const renderTaskDetail = (summary, task, logger) => {
|
|
71
|
+
renderRunHeader(summary, logger);
|
|
72
|
+
logger.info(`Task ${task.taskId}`);
|
|
73
|
+
logger.info(` status: ${formatStatus(task)}`);
|
|
74
|
+
logger.info(` cache: ${task.cacheStatus}`);
|
|
75
|
+
logger.info(` duration: ${formatDuration(task.duration)}`);
|
|
76
|
+
logger.info(` exit: ${task.exitCode === void 0 ? "-" : String(task.exitCode)}`);
|
|
77
|
+
logger.info(` hash: ${task.hash ?? "(none)"}`);
|
|
78
|
+
logger.info(` start: ${task.startTime ?? "-"}`);
|
|
79
|
+
logger.info(` end: ${task.endTime ?? "-"}`);
|
|
80
|
+
if (task.dependencies.length > 0) {
|
|
81
|
+
logger.info(` deps: ${task.dependencies.join(", ")}`);
|
|
82
|
+
}
|
|
83
|
+
logger.info("");
|
|
84
|
+
pail.info(`Drill into hash inputs with: vis cache why ${task.taskId} --run ${summary.id}`);
|
|
85
|
+
};
|
|
86
|
+
const renderListJson = (entries) => {
|
|
87
|
+
process.stdout.write(
|
|
88
|
+
`${JSON.stringify(
|
|
89
|
+
entries.map((entry) => ({
|
|
90
|
+
id: entry.id,
|
|
91
|
+
mtime: new Date(entry.mtimeMs).toISOString(),
|
|
92
|
+
path: entry.path
|
|
93
|
+
})),
|
|
94
|
+
void 0,
|
|
95
|
+
2
|
|
96
|
+
)}
|
|
97
|
+
`
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
const renderListTable = (entries, logger) => {
|
|
101
|
+
if (entries.length === 0) {
|
|
102
|
+
pail.info("No recorded runs found in .task-runner/runs/. Run with --summarize to record a run.");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const widths = {
|
|
106
|
+
id: Math.max("id".length, ...entries.map((entry) => entry.id.length)),
|
|
107
|
+
mtime: 24
|
|
108
|
+
};
|
|
109
|
+
logger.info(` ${padCell("id", widths.id)} ${padCell("mtime", widths.mtime)}`);
|
|
110
|
+
logger.info(` ${"-".repeat(widths.id)} ${"-".repeat(widths.mtime)}`);
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
logger.info(` ${padCell(entry.id, widths.id)} ${new Date(entry.mtimeMs).toISOString()}`);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const filterTasks = (summary, options) => {
|
|
116
|
+
let tasks = summary.tasks;
|
|
117
|
+
if (options.task !== void 0) {
|
|
118
|
+
tasks = tasks.filter((t) => t.taskId === options.task);
|
|
119
|
+
}
|
|
120
|
+
if (options.failed) {
|
|
121
|
+
tasks = tasks.filter((t) => isFailedTask(t));
|
|
122
|
+
}
|
|
123
|
+
return tasks;
|
|
124
|
+
};
|
|
125
|
+
const runReplay = async (options, logger) => {
|
|
126
|
+
const { failed, format, runId, task: taskFilter, workspaceRoot } = options;
|
|
127
|
+
const summary = runId === void 0 ? await readLastRunSummary(workspaceRoot) : await readRunSummaryById(workspaceRoot, runId);
|
|
128
|
+
if (!summary) {
|
|
129
|
+
if (format === "json") {
|
|
130
|
+
process.stdout.write(`${JSON.stringify({ error: "no-summary", runId: runId ?? null }, void 0, 2)}
|
|
131
|
+
`);
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (runId === void 0) {
|
|
136
|
+
pail.error("No previous run summary found. Run a task first to populate `.task-runner/last-summary.json`.");
|
|
137
|
+
} else {
|
|
138
|
+
pail.error(`Run summary "${runId}" not found in .task-runner/runs/.`);
|
|
139
|
+
}
|
|
140
|
+
process.exitCode = 1;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const filteredTasks = filterTasks(summary, { failed, task: taskFilter });
|
|
144
|
+
if (taskFilter !== void 0 && filteredTasks.length === 0) {
|
|
145
|
+
if (format === "json") {
|
|
146
|
+
process.stdout.write(`${JSON.stringify({ error: "task-not-in-summary", runId: summary.id, taskId: taskFilter }, void 0, 2)}
|
|
147
|
+
`);
|
|
148
|
+
process.exitCode = 1;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
pail.error(`Task "${taskFilter}" was not part of run ${summary.id}.`);
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (summary.stats.failed > 0) {
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
}
|
|
158
|
+
if (format === "json") {
|
|
159
|
+
process.stdout.write(
|
|
160
|
+
`${JSON.stringify(
|
|
161
|
+
{
|
|
162
|
+
duration: summary.duration,
|
|
163
|
+
endTime: summary.endTime,
|
|
164
|
+
environment: summary.environment,
|
|
165
|
+
runId: summary.id,
|
|
166
|
+
startTime: summary.startTime,
|
|
167
|
+
stats: summary.stats,
|
|
168
|
+
tasks: filteredTasks.map((t) => ({
|
|
169
|
+
cacheStatus: t.cacheStatus,
|
|
170
|
+
dependencies: t.dependencies,
|
|
171
|
+
duration: t.duration,
|
|
172
|
+
endTime: t.endTime,
|
|
173
|
+
exitCode: t.exitCode,
|
|
174
|
+
hash: t.hash ?? null,
|
|
175
|
+
startTime: t.startTime,
|
|
176
|
+
taskId: t.taskId
|
|
177
|
+
}))
|
|
178
|
+
},
|
|
179
|
+
void 0,
|
|
180
|
+
2
|
|
181
|
+
)}
|
|
182
|
+
`
|
|
183
|
+
);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (taskFilter !== void 0) {
|
|
187
|
+
renderTaskDetail(summary, filteredTasks[0], logger);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
renderRunHeader(summary, logger);
|
|
191
|
+
renderTaskTable(filteredTasks, logger);
|
|
192
|
+
};
|
|
193
|
+
const replayExecute = async ({ logger, options, workspaceRoot: wsRoot }) => {
|
|
194
|
+
const workspaceRoot = resolveWorkspaceRoot(wsRoot);
|
|
195
|
+
const format = options.format ?? "table";
|
|
196
|
+
if (!VALID_FORMATS.has(format)) {
|
|
197
|
+
pail.error(`Invalid --format: ${format}. Expected "table" or "json".`);
|
|
198
|
+
process.exitCode = 1;
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (options.list === true) {
|
|
202
|
+
const entries = await listRunSummaries(workspaceRoot);
|
|
203
|
+
if (format === "json") {
|
|
204
|
+
renderListJson(entries);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
renderListTable(entries, logger);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await runReplay(
|
|
211
|
+
{
|
|
212
|
+
failed: options.failed === true,
|
|
213
|
+
format,
|
|
214
|
+
runId: options.run,
|
|
215
|
+
task: options.task,
|
|
216
|
+
workspaceRoot
|
|
217
|
+
},
|
|
218
|
+
logger
|
|
219
|
+
);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export { replayExecute as default, replayExecute, runReplay };
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { createRequire as __cjs_createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const __cjs_require = __cjs_createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
|
|
6
|
+
|
|
7
|
+
const __cjs_getBuiltinModule = (module) => {
|
|
8
|
+
// Check if we're in Node.js and version supports getBuiltinModule
|
|
9
|
+
if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
|
|
10
|
+
const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
|
|
11
|
+
// Node.js 20.16.0+ and 22.3.0+
|
|
12
|
+
if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
|
|
13
|
+
return __cjs_getProcess.getBuiltinModule(module);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Fallback to createRequire
|
|
17
|
+
return __cjs_require(module);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
writeFileSync
|
|
22
|
+
} = __cjs_getBuiltinModule("node:fs");
|
|
23
|
+
import { readFileSync, isAccessibleSync } from '@visulima/fs';
|
|
24
|
+
import { join, relative, basename, resolve } from '@visulima/path';
|
|
25
|
+
import zeptomatch from 'zeptomatch';
|
|
26
|
+
import { sortPackageJsonStringWithOptions } from '#native';
|
|
27
|
+
import { p as pail, q as readPnpmWorkspacePatterns, o as resolveWorkspacePatterns } from './bin.js';
|
|
28
|
+
import { e as errorMessage } from '../packem_shared/utils-CthVdBPS.js';
|
|
29
|
+
|
|
30
|
+
const findPackageJsonFiles = (root) => {
|
|
31
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32
|
+
const results = [];
|
|
33
|
+
const addFile = (filePath) => {
|
|
34
|
+
const resolved = resolve(filePath);
|
|
35
|
+
if (!seen.has(resolved) && isAccessibleSync(resolved)) {
|
|
36
|
+
seen.add(resolved);
|
|
37
|
+
results.push(resolved);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
addFile(join(root, "package.json"));
|
|
41
|
+
const pnpmPatterns = readPnpmWorkspacePatterns(root);
|
|
42
|
+
if (pnpmPatterns) {
|
|
43
|
+
const projectDirectories = resolveWorkspacePatterns(root, pnpmPatterns);
|
|
44
|
+
for (const dir of projectDirectories) {
|
|
45
|
+
addFile(join(root, dir, "package.json"));
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
const rootPkgPath = join(root, "package.json");
|
|
49
|
+
if (isAccessibleSync(rootPkgPath)) {
|
|
50
|
+
const rootPkg = JSON.parse(readFileSync(rootPkgPath));
|
|
51
|
+
const patterns = Array.isArray(rootPkg.workspaces) ? rootPkg.workspaces : rootPkg.workspaces?.packages;
|
|
52
|
+
if (patterns) {
|
|
53
|
+
const projectDirectories = resolveWorkspacePatterns(root, patterns);
|
|
54
|
+
for (const dir of projectDirectories) {
|
|
55
|
+
addFile(join(root, dir, "package.json"));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return results;
|
|
61
|
+
};
|
|
62
|
+
const detectIndent = (contents) => {
|
|
63
|
+
const match = /\n([ \t]+)/.exec(contents);
|
|
64
|
+
return match?.[1] ?? " ";
|
|
65
|
+
};
|
|
66
|
+
const resolveIndentOverride = (raw) => {
|
|
67
|
+
if (raw === void 0 || raw === "") {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
if (raw === "tab" || raw === String.raw`\t`) {
|
|
71
|
+
return " ";
|
|
72
|
+
}
|
|
73
|
+
if (/^\d+$/.test(raw)) {
|
|
74
|
+
return " ".repeat(Number.parseInt(raw, 10));
|
|
75
|
+
}
|
|
76
|
+
return raw;
|
|
77
|
+
};
|
|
78
|
+
const splitList = (raw) => {
|
|
79
|
+
if (raw === void 0) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const items = Array.isArray(raw) ? raw : [raw];
|
|
83
|
+
return items.flatMap((item) => item.split(",")).map((item) => item.trim()).filter((item) => item.length > 0);
|
|
84
|
+
};
|
|
85
|
+
const detectLineEnding = (contents) => contents.includes("\r\n") ? "crlf" : "lf";
|
|
86
|
+
const ALLOWED_LINE_ENDINGS = /* @__PURE__ */ new Set(["auto", "crlf", "lf"]);
|
|
87
|
+
const validateLineEnding = (raw) => {
|
|
88
|
+
if (raw === void 0 || raw === "") {
|
|
89
|
+
return "auto";
|
|
90
|
+
}
|
|
91
|
+
if (ALLOWED_LINE_ENDINGS.has(raw)) {
|
|
92
|
+
return raw;
|
|
93
|
+
}
|
|
94
|
+
pail.error(`--line-ending must be one of: auto, lf, crlf (got "${raw}")`);
|
|
95
|
+
process.exit(2);
|
|
96
|
+
};
|
|
97
|
+
const filterByIgnore = (files, patterns, cwd) => {
|
|
98
|
+
if (patterns.length === 0) {
|
|
99
|
+
return files;
|
|
100
|
+
}
|
|
101
|
+
return files.filter((absolute) => {
|
|
102
|
+
const relPath = relative(cwd, absolute);
|
|
103
|
+
const base = basename(absolute);
|
|
104
|
+
return !patterns.some((pattern) => {
|
|
105
|
+
const target = pattern.includes("/") ? relPath : base;
|
|
106
|
+
return zeptomatch(pattern, target);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
const applySortOrder = (object, sortOrder) => {
|
|
111
|
+
if (sortOrder.length === 0) {
|
|
112
|
+
return object;
|
|
113
|
+
}
|
|
114
|
+
const result = {};
|
|
115
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
116
|
+
for (const key of sortOrder) {
|
|
117
|
+
if (Object.hasOwn(object, key)) {
|
|
118
|
+
result[key] = object[key];
|
|
119
|
+
consumed.add(key);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const key of Object.keys(object)) {
|
|
123
|
+
if (!consumed.has(key)) {
|
|
124
|
+
result[key] = object[key];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
const restoreUnsortedSections = (sorted, original, unsorted) => {
|
|
130
|
+
if (unsorted.length === 0) {
|
|
131
|
+
return sorted;
|
|
132
|
+
}
|
|
133
|
+
const result = { ...sorted };
|
|
134
|
+
for (const key of unsorted) {
|
|
135
|
+
if (Object.hasOwn(original, key)) {
|
|
136
|
+
result[key] = original[key];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
};
|
|
141
|
+
const sortContents = (contents, config) => {
|
|
142
|
+
const indent = config.indent ?? detectIndent(contents);
|
|
143
|
+
const lineEnding = config.lineEnding === "auto" ? detectLineEnding(contents) : config.lineEnding;
|
|
144
|
+
const compact = sortPackageJsonStringWithOptions(contents, {
|
|
145
|
+
pretty: false,
|
|
146
|
+
sortScripts: config.sortScripts
|
|
147
|
+
});
|
|
148
|
+
let parsed = JSON.parse(compact);
|
|
149
|
+
if (config.unsorted.length > 0) {
|
|
150
|
+
const original = JSON.parse(contents);
|
|
151
|
+
parsed = restoreUnsortedSections(parsed, original, config.unsorted);
|
|
152
|
+
}
|
|
153
|
+
parsed = applySortOrder(parsed, config.sortOrder);
|
|
154
|
+
let output = JSON.stringify(parsed, null, indent);
|
|
155
|
+
if (config.finalNewline) {
|
|
156
|
+
output += "\n";
|
|
157
|
+
}
|
|
158
|
+
if (lineEnding === "crlf") {
|
|
159
|
+
output = output.replaceAll("\n", "\r\n");
|
|
160
|
+
}
|
|
161
|
+
return output;
|
|
162
|
+
};
|
|
163
|
+
const execute = async ({ options, visConfig, workspaceRoot: wsRoot }) => {
|
|
164
|
+
const cwd = wsRoot ?? process.cwd();
|
|
165
|
+
const config = visConfig?.["sortPackageJson"];
|
|
166
|
+
const check = options.check || false;
|
|
167
|
+
const normalized = {
|
|
168
|
+
finalNewline: options.finalNewline ?? config?.finalNewline ?? true,
|
|
169
|
+
ignore: [...splitList(options.ignore), ...config?.ignore ?? []],
|
|
170
|
+
indent: resolveIndentOverride(options.indent ?? config?.indent),
|
|
171
|
+
lineEnding: validateLineEnding(options.lineEnding ?? config?.lineEnding),
|
|
172
|
+
sortOrder: [...splitList(options.sortOrder), ...config?.sortOrder ?? []],
|
|
173
|
+
sortScripts: options.sortScripts || config?.sortScripts || false,
|
|
174
|
+
unsorted: [...splitList(options.unsorted), ...config?.unsorted ?? []]
|
|
175
|
+
};
|
|
176
|
+
const allFiles = findPackageJsonFiles(cwd);
|
|
177
|
+
const files = filterByIgnore(allFiles, normalized.ignore, cwd);
|
|
178
|
+
if (files.length === 0) {
|
|
179
|
+
pail.info(allFiles.length === 0 ? "No package.json files found." : "All package.json files were excluded by --ignore.");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
let unsortedCount = 0;
|
|
183
|
+
let sortedCount = 0;
|
|
184
|
+
let errorCount = 0;
|
|
185
|
+
for (const filePath of files) {
|
|
186
|
+
try {
|
|
187
|
+
const contents = readFileSync(filePath);
|
|
188
|
+
let sorted;
|
|
189
|
+
try {
|
|
190
|
+
sorted = sortContents(contents, normalized);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
pail.error(`${filePath}: ${errorMessage(error)}`);
|
|
193
|
+
errorCount++;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (contents === sorted) {
|
|
197
|
+
sortedCount++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
unsortedCount++;
|
|
201
|
+
if (check) {
|
|
202
|
+
pail.warn(`${filePath} is not sorted`);
|
|
203
|
+
} else {
|
|
204
|
+
writeFileSync(filePath, sorted, "utf8");
|
|
205
|
+
pail.success(`Sorted ${filePath}`);
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
pail.error(`${filePath}: ${errorMessage(error)}`);
|
|
209
|
+
errorCount++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (check) {
|
|
213
|
+
if (unsortedCount > 0) {
|
|
214
|
+
pail.info(`${unsortedCount} file${unsortedCount === 1 ? "" : "s"} not sorted, ${sortedCount} already sorted`);
|
|
215
|
+
process.exitCode = 1;
|
|
216
|
+
} else {
|
|
217
|
+
pail.info(`All ${sortedCount} package.json file${sortedCount === 1 ? " is" : "s are"} sorted`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
const parts = [];
|
|
221
|
+
if (unsortedCount > 0) {
|
|
222
|
+
parts.push(`sorted ${unsortedCount} file${unsortedCount === 1 ? "" : "s"}`);
|
|
223
|
+
}
|
|
224
|
+
if (sortedCount > 0) {
|
|
225
|
+
parts.push(`${sortedCount} already sorted`);
|
|
226
|
+
}
|
|
227
|
+
if (errorCount > 0) {
|
|
228
|
+
parts.push(`${errorCount} error${errorCount === 1 ? "" : "s"}`);
|
|
229
|
+
}
|
|
230
|
+
pail.info(parts.join(", "));
|
|
231
|
+
}
|
|
232
|
+
if (errorCount > 0) {
|
|
233
|
+
process.exitCode = 1;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
export { execute as default };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { createRequire as __cjs_createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const __cjs_require = __cjs_createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
|
|
6
|
+
|
|
7
|
+
const __cjs_getBuiltinModule = (module) => {
|
|
8
|
+
// Check if we're in Node.js and version supports getBuiltinModule
|
|
9
|
+
if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
|
|
10
|
+
const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
|
|
11
|
+
// Node.js 20.16.0+ and 22.3.0+
|
|
12
|
+
if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
|
|
13
|
+
return __cjs_getProcess.getBuiltinModule(module);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Fallback to createRequire
|
|
17
|
+
return __cjs_require(module);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
readdirSync
|
|
22
|
+
} = __cjs_getBuiltinModule("node:fs");
|
|
23
|
+
import { dim, green, yellow, red } from '@visulima/colorize';
|
|
24
|
+
import { isAccessibleSync, readJsonSync } from '@visulima/fs';
|
|
25
|
+
import { join } from '@visulima/path';
|
|
26
|
+
import { enforceProjectConstraints } from '@visulima/task-runner';
|
|
27
|
+
import { d as discoverWorkspace, b as buildProjectGraph } from './bin.js';
|
|
28
|
+
import { a as analyzeFlakiness } from '../packem_shared/flakiness-goTxXuCX.js';
|
|
29
|
+
import { c as checkRuntimeVersions } from '../packem_shared/runtime-check-Cobi3p6l.js';
|
|
30
|
+
|
|
31
|
+
const icon = (ok) => ok ? green("✓") : red("✗");
|
|
32
|
+
const execute = async ({ logger, options, visConfig, workspaceRoot: wsRoot }) => {
|
|
33
|
+
if (!wsRoot) {
|
|
34
|
+
throw new Error("Could not determine workspace root.");
|
|
35
|
+
}
|
|
36
|
+
const { config, packageJsons, workspace } = discoverWorkspace(wsRoot, visConfig);
|
|
37
|
+
const projectGraph = buildProjectGraph(wsRoot, workspace, packageJsons);
|
|
38
|
+
const projectCount = Object.keys(workspace.projects).length;
|
|
39
|
+
const targetCount = new Set(Object.values(workspace.projects).flatMap((p) => Object.keys(p.targets ?? {}))).size;
|
|
40
|
+
const runtimeFindings = checkRuntimeVersions(wsRoot);
|
|
41
|
+
let constraintViolations = 0;
|
|
42
|
+
if (config.constraints) {
|
|
43
|
+
constraintViolations = enforceProjectConstraints(projectGraph, config.constraints).length;
|
|
44
|
+
}
|
|
45
|
+
const flakyStats = analyzeFlakiness(wsRoot, { minRuns: 2 });
|
|
46
|
+
let cacheHitRate;
|
|
47
|
+
const runsDir = join(wsRoot, ".task-runner", "runs");
|
|
48
|
+
if (isAccessibleSync(runsDir)) {
|
|
49
|
+
const files = readdirSync(runsDir).filter((f) => f.endsWith(".json")).sort();
|
|
50
|
+
let totalTasks = 0;
|
|
51
|
+
let cachedTasks = 0;
|
|
52
|
+
for (const file of files.slice(-20)) {
|
|
53
|
+
try {
|
|
54
|
+
const data = readJsonSync(join(runsDir, file));
|
|
55
|
+
if (data.stats) {
|
|
56
|
+
totalTasks += data.stats.total ?? 0;
|
|
57
|
+
cachedTasks += data.stats.cached ?? 0;
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (totalTasks > 0) {
|
|
64
|
+
cacheHitRate = `${(cachedTasks / totalTasks * 100).toFixed(0)}%`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (options.json) {
|
|
68
|
+
logger.info(
|
|
69
|
+
JSON.stringify(
|
|
70
|
+
{
|
|
71
|
+
cacheHitRate: cacheHitRate ?? null,
|
|
72
|
+
constraintViolations,
|
|
73
|
+
flakyTasks: flakyStats.length,
|
|
74
|
+
projects: projectCount,
|
|
75
|
+
runtimeIssues: runtimeFindings.length,
|
|
76
|
+
targets: targetCount
|
|
77
|
+
},
|
|
78
|
+
null,
|
|
79
|
+
2
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
logger.info("");
|
|
85
|
+
logger.info(` ${dim("VIS STATUS")}`);
|
|
86
|
+
logger.info("");
|
|
87
|
+
logger.info(` ${icon(true)} ${String(projectCount)} projects · ${String(targetCount)} unique targets`);
|
|
88
|
+
logger.info(
|
|
89
|
+
` ${icon(runtimeFindings.length === 0)} Runtime: ${runtimeFindings.length === 0 ? green("OK") : yellow(`${String(runtimeFindings.length)} issue(s)`)}`
|
|
90
|
+
);
|
|
91
|
+
logger.info(
|
|
92
|
+
` ${icon(constraintViolations === 0)} Constraints: ${constraintViolations === 0 ? green("OK") : red(`${String(constraintViolations)} violation(s)`)}`
|
|
93
|
+
);
|
|
94
|
+
logger.info(` ${icon(flakyStats.length === 0)} Flaky tasks: ${flakyStats.length === 0 ? green("none") : yellow(String(flakyStats.length))}`);
|
|
95
|
+
if (cacheHitRate) {
|
|
96
|
+
logger.info(` ${icon(true)} Cache hit rate: ${cacheHitRate} (last 20 runs)`);
|
|
97
|
+
}
|
|
98
|
+
logger.info("");
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export { execute as default };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createTaskGraph } from '@visulima/task-runner';
|
|
2
|
+
import { d as discoverWorkspace, b as buildProjectGraph } from './bin.js';
|
|
3
|
+
|
|
4
|
+
const findShortestPathToRoot = (graph, target) => {
|
|
5
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
6
|
+
for (const [parent, deps] of Object.entries(graph.dependencies)) {
|
|
7
|
+
for (const dep of deps) {
|
|
8
|
+
const list = reverse.get(dep) ?? [];
|
|
9
|
+
list.push(parent);
|
|
10
|
+
reverse.set(dep, list);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (!graph.tasks[target]) {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const visited = /* @__PURE__ */ new Set([target]);
|
|
17
|
+
const queue = [{ node: target, path: [target] }];
|
|
18
|
+
while (queue.length > 0) {
|
|
19
|
+
const current = queue.shift();
|
|
20
|
+
if (graph.roots.includes(current.node)) {
|
|
21
|
+
return current.path;
|
|
22
|
+
}
|
|
23
|
+
for (const parent of reverse.get(current.node) ?? []) {
|
|
24
|
+
if (visited.has(parent)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
visited.add(parent);
|
|
28
|
+
queue.push({ node: parent, path: [parent, ...current.path] });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return [target];
|
|
32
|
+
};
|
|
33
|
+
const collectParents = (graph, target) => {
|
|
34
|
+
const parents = [];
|
|
35
|
+
for (const [parent, deps] of Object.entries(graph.dependencies)) {
|
|
36
|
+
if (deps.includes(target)) {
|
|
37
|
+
parents.push(parent);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return parents.sort();
|
|
41
|
+
};
|
|
42
|
+
const execute = async ({ argument, logger, visConfig, workspaceRoot: wsRoot }) => {
|
|
43
|
+
if (!wsRoot) {
|
|
44
|
+
throw new Error("Could not determine workspace root.");
|
|
45
|
+
}
|
|
46
|
+
const taskId = argument[0];
|
|
47
|
+
if (!taskId) {
|
|
48
|
+
throw new Error("No task ID specified. Usage: vis task-why <project>:<target>");
|
|
49
|
+
}
|
|
50
|
+
if (!taskId.includes(":")) {
|
|
51
|
+
throw new Error(`Invalid task ID "${taskId}" — expected format "project:target".`);
|
|
52
|
+
}
|
|
53
|
+
const { packageJsons, workspace } = discoverWorkspace(wsRoot, visConfig);
|
|
54
|
+
const projectGraph = buildProjectGraph(wsRoot, workspace, packageJsons);
|
|
55
|
+
const [projectName, targetName] = taskId.split(":", 2);
|
|
56
|
+
const project = workspace.projects[projectName];
|
|
57
|
+
if (!project) {
|
|
58
|
+
throw new Error(`Unknown project "${projectName}".`);
|
|
59
|
+
}
|
|
60
|
+
if (!project.targets?.[targetName]) {
|
|
61
|
+
throw new Error(`Project "${projectName}" has no target "${targetName}".`);
|
|
62
|
+
}
|
|
63
|
+
const allInitialTasks = Object.entries(workspace.projects).flatMap(
|
|
64
|
+
([name, proj]) => Object.keys(proj.targets ?? {}).map((t) => {
|
|
65
|
+
return {
|
|
66
|
+
id: `${name}:${t}`,
|
|
67
|
+
outputs: [],
|
|
68
|
+
overrides: {},
|
|
69
|
+
target: { project: name, target: t }
|
|
70
|
+
};
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
const graph = createTaskGraph(allInitialTasks, { projectGraph, workspace });
|
|
74
|
+
if (!graph.tasks[taskId]) {
|
|
75
|
+
throw new Error(`Task "${taskId}" is not reachable in the graph.`);
|
|
76
|
+
}
|
|
77
|
+
const path = findShortestPathToRoot(graph, taskId);
|
|
78
|
+
const parents = collectParents(graph, taskId);
|
|
79
|
+
logger.info("");
|
|
80
|
+
logger.info(`Why ${taskId}?`);
|
|
81
|
+
logger.info("");
|
|
82
|
+
if (path && path.length > 1) {
|
|
83
|
+
logger.info("Shortest path from a root to this task:");
|
|
84
|
+
for (const [index, node] of path.entries()) {
|
|
85
|
+
const prefix = index === 0 ? " " : `${" ".repeat(index + 1)}└─ `;
|
|
86
|
+
logger.info(`${prefix}${node}`);
|
|
87
|
+
}
|
|
88
|
+
logger.info("");
|
|
89
|
+
} else {
|
|
90
|
+
logger.info(" This task is itself a root — nothing upstream depends on it.");
|
|
91
|
+
logger.info("");
|
|
92
|
+
}
|
|
93
|
+
if (parents.length > 0) {
|
|
94
|
+
logger.info(`Directly depended on by ${parents.length} task(s):`);
|
|
95
|
+
for (const parent of parents) {
|
|
96
|
+
logger.info(` - ${parent}`);
|
|
97
|
+
}
|
|
98
|
+
logger.info("");
|
|
99
|
+
}
|
|
100
|
+
const directDeps = graph.dependencies[taskId] ?? [];
|
|
101
|
+
if (directDeps.length > 0) {
|
|
102
|
+
logger.info(`This task depends on ${directDeps.length} task(s):`);
|
|
103
|
+
for (const dep of [...directDeps].sort()) {
|
|
104
|
+
logger.info(` - ${dep}`);
|
|
105
|
+
}
|
|
106
|
+
logger.info("");
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export { execute as default };
|