@visulima/task-runner 1.0.0-alpha.2 → 1.0.0-alpha.20
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 +310 -0
- package/README.md +198 -52
- package/dist/index.d.ts +3795 -34
- package/dist/index.js +1 -20
- package/dist/packem_chunks/index.js +31 -0
- package/dist/packem_shared/Cache-C8FfeXpg.js +2 -0
- package/dist/packem_shared/CompositeLifeCycle-C6aee9GK.js +1 -0
- package/dist/packem_shared/FileAccessTracker-DBz_w4wl.js +50 -0
- package/dist/packem_shared/FingerprintManager-CYW2EwLc.js +2 -0
- package/dist/packem_shared/HttpRemoteCache-CpPl6lzE.js +1 -0
- package/dist/packem_shared/INPUT_URI_SCHEMES-Csrd0tlg.js +1 -0
- package/dist/packem_shared/IncrementalFileHasher-B-V3i2x-.js +1 -0
- package/dist/packem_shared/LogReporter-3R3oWj-Q.js +13 -0
- package/dist/packem_shared/ReapiRemoteCache-BXJip5wH.js +251 -0
- package/dist/packem_shared/TaskOrchestrator-CYj5MLwz.js +6 -0
- package/dist/packem_shared/TerminalBuffer-BtZy7TpT.js +3 -0
- package/dist/packem_shared/TrackedTaskExecutor-CtYLL3vS.js +1 -0
- package/dist/packem_shared/V2_ROOT-injxWBrl.js +1 -0
- package/dist/packem_shared/actionDigestForTaskHash-BOL4fZ9v.js +1 -0
- package/dist/packem_shared/archive-CDfGy5Lm.js +1 -0
- package/dist/packem_shared/buildForwardDependencyMap-DudUDFze.js +3 -0
- package/dist/packem_shared/collectFiles-W4bnBRpb.js +1 -0
- package/dist/packem_shared/collectNodeModulesBinDirs-CD-eDrtO.js +1 -0
- package/dist/packem_shared/computeTaskHash-CaPdG1BA.js +1 -0
- package/dist/packem_shared/containsBlob-DAU8R7GH.js +1 -0
- package/dist/packem_shared/createInputHandler-CkDCpPYy.js +1 -0
- package/dist/packem_shared/createTaskGraph-D8Jn_Dn9.js +1 -0
- package/dist/packem_shared/defaultTaskRunner-DMHpavzm.js +2 -0
- package/dist/packem_shared/detectFrameworks-WVZJOPgN.js +1 -0
- package/dist/packem_shared/detectScriptShell-CaTDk5cW.js +1 -0
- package/dist/packem_shared/digestBuffer-g11aCaDx.js +1 -0
- package/dist/packem_shared/enforceProjectConstraints-dNc1SwRi.js +1 -0
- package/dist/packem_shared/expandArguments-D7qvc6Rp.js +1 -0
- package/dist/packem_shared/expandShortcut-BErNHNXZ.js +1 -0
- package/dist/packem_shared/expandTokensInString-DVSFEdWu.js +1 -0
- package/dist/packem_shared/expandWildcard-DE0dOOZF.js +1 -0
- package/dist/packem_shared/extractPackageName-BeL6Gc3a.js +1 -0
- package/dist/packem_shared/findCycle-BY8-jmzB.js +1 -0
- package/dist/packem_shared/formatTimingTable-CP3rsDwf.js +7 -0
- package/dist/packem_shared/generateRunSummary-L9Z2NfWn.js +1 -0
- package/dist/packem_shared/getCurrentBranch-D-qoZByx.js +1 -0
- package/dist/packem_shared/getMainWorktreeRoot-DB9P2wDL.js +1 -0
- package/dist/packem_shared/isNativeAvailable-CkTjxb7P.js +1 -0
- package/dist/packem_shared/parseCommands-BHsXoUCd.js +1 -0
- package/dist/packem_shared/parsePartition-Bt1jBjZH.js +1 -0
- package/dist/packem_shared/projectGraphToDot-FN6oHDGH.js +250 -0
- package/dist/packem_shared/resolveCacheMode--4y60ODd.js +1 -0
- package/dist/packem_shared/resolveOutputs-CzGGEbcP.js +1 -0
- package/dist/packem_shared/runConcurrentFallback-BhJCT2LA.js +3 -0
- package/dist/packem_shared/runConcurrently-D1Ytsjaj.js +1 -0
- package/dist/packem_shared/runTeardown-DAn1xFWJ.js +1 -0
- package/dist/packem_shared/shell-quote-BhmqDUL1.js +1 -0
- package/dist/packem_shared/stripQuotes-jkZb0CL9.js +1 -0
- package/dist/packem_shared/toChromeTrace-DxN5NQIU.js +1 -0
- package/dist/packem_shared/tracked-executor-B90U4Um3.js +3 -0
- package/dist/packem_shared/utils-BH2W5Wml.js +1 -0
- package/dist/packem_shared/withRestart-DKtEGsQA.js +1 -0
- package/index.js +603 -0
- package/package.json +31 -19
- package/binding.js +0 -204
- package/dist/affected.d.ts +0 -48
- package/dist/cache.d.ts +0 -103
- package/dist/default-task-runner.d.ts +0 -44
- package/dist/file-access-tracker.d.ts +0 -53
- package/dist/fingerprint.d.ts +0 -45
- package/dist/framework-inference.d.ts +0 -35
- package/dist/graph-visualizer.d.ts +0 -74
- package/dist/incremental-hasher.d.ts +0 -58
- package/dist/life-cycle.d.ts +0 -36
- package/dist/lockfile-hasher.d.ts +0 -73
- package/dist/native-binding.d.ts +0 -64
- package/dist/packem_shared/Cache-IYpTYVUC.js +0 -298
- package/dist/packem_shared/CompositeLifeCycle-7AtYw1dv.js +0 -112
- package/dist/packem_shared/FileAccessTracker-CrtBAt5D.js +0 -239
- package/dist/packem_shared/FingerprintManager-D6Y0erg-.js +0 -227
- package/dist/packem_shared/IncrementalFileHasher-Ds3J6dgb.js +0 -151
- package/dist/packem_shared/RemoteCache-BDqrnDEi.js +0 -179
- package/dist/packem_shared/TaskOrchestrator-BvYs3ONw.js +0 -342
- package/dist/packem_shared/TaskScheduler-CJilHDta.js +0 -111
- package/dist/packem_shared/TrackedTaskExecutor-BGUKFE-7.js +0 -164
- package/dist/packem_shared/collectFiles-ClXHnHhg.js +0 -22
- package/dist/packem_shared/computeTaskHash-BoCnnvIJ.js +0 -356
- package/dist/packem_shared/createTaskGraph-CcsFaSrz.js +0 -164
- package/dist/packem_shared/defaultTaskRunner-CrW4v5Ye.js +0 -79
- package/dist/packem_shared/detectFrameworks-CeFzKE6J.js +0 -101
- package/dist/packem_shared/extractPackageName-CbVNW-dr.js +0 -189
- package/dist/packem_shared/filterAffectedTasks-I-18zPg6.js +0 -135
- package/dist/packem_shared/findCycle-DF4_BRdO.js +0 -212
- package/dist/packem_shared/generateRunSummary-qn-_jKwt.js +0 -134
- package/dist/packem_shared/isNativeAvailable-BWhnZ4ES.js +0 -19
- package/dist/packem_shared/projectGraphToDot-VdTjHcVp.js +0 -202
- package/dist/packem_shared/utils-zO0ZRgtf.js +0 -390
- package/dist/remote-cache.d.ts +0 -55
- package/dist/run-summary.d.ts +0 -89
- package/dist/task-graph-utils.d.ts +0 -39
- package/dist/task-graph.d.ts +0 -22
- package/dist/task-hasher.d.ts +0 -67
- package/dist/task-orchestrator.d.ts +0 -38
- package/dist/task-scheduler.d.ts +0 -18
- package/dist/tracked-executor.d.ts +0 -46
- package/dist/types.d.ts +0 -385
- package/dist/utils.d.ts +0 -39
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
const findCycle = (taskGraph) => {
|
|
2
|
-
const visited = /* @__PURE__ */ new Set();
|
|
3
|
-
const inStack = /* @__PURE__ */ new Set();
|
|
4
|
-
const parent = /* @__PURE__ */ new Map();
|
|
5
|
-
for (const taskId of Object.keys(taskGraph.tasks)) {
|
|
6
|
-
if (visited.has(taskId)) {
|
|
7
|
-
continue;
|
|
8
|
-
}
|
|
9
|
-
const stack = [taskId];
|
|
10
|
-
while (stack.length > 0) {
|
|
11
|
-
const current = stack[stack.length - 1];
|
|
12
|
-
if (!visited.has(current)) {
|
|
13
|
-
visited.add(current);
|
|
14
|
-
inStack.add(current);
|
|
15
|
-
}
|
|
16
|
-
const deps = taskGraph.dependencies[current] ?? [];
|
|
17
|
-
let foundUnvisited = false;
|
|
18
|
-
for (const dep of deps) {
|
|
19
|
-
if (inStack.has(dep)) {
|
|
20
|
-
const cycle = [dep];
|
|
21
|
-
let node = current;
|
|
22
|
-
while (node !== dep) {
|
|
23
|
-
cycle.push(node);
|
|
24
|
-
node = parent.get(node) ?? dep;
|
|
25
|
-
}
|
|
26
|
-
cycle.push(dep);
|
|
27
|
-
cycle.reverse();
|
|
28
|
-
return cycle;
|
|
29
|
-
}
|
|
30
|
-
if (!visited.has(dep)) {
|
|
31
|
-
parent.set(dep, current);
|
|
32
|
-
stack.push(dep);
|
|
33
|
-
foundUnvisited = true;
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (!foundUnvisited) {
|
|
38
|
-
stack.pop();
|
|
39
|
-
inStack.delete(current);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return void 0;
|
|
44
|
-
};
|
|
45
|
-
const findCycles = (taskGraph) => {
|
|
46
|
-
const cycles = [];
|
|
47
|
-
const visited = /* @__PURE__ */ new Set();
|
|
48
|
-
const inStack = /* @__PURE__ */ new Set();
|
|
49
|
-
const stack = [];
|
|
50
|
-
const dfs = (taskId) => {
|
|
51
|
-
visited.add(taskId);
|
|
52
|
-
inStack.add(taskId);
|
|
53
|
-
stack.push(taskId);
|
|
54
|
-
const deps = taskGraph.dependencies[taskId] ?? [];
|
|
55
|
-
for (const dep of deps) {
|
|
56
|
-
if (inStack.has(dep)) {
|
|
57
|
-
const cycleStart = stack.indexOf(dep);
|
|
58
|
-
const cycle = [...stack.slice(cycleStart), dep];
|
|
59
|
-
cycles.push(cycle);
|
|
60
|
-
} else if (!visited.has(dep)) {
|
|
61
|
-
dfs(dep);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
stack.pop();
|
|
65
|
-
inStack.delete(taskId);
|
|
66
|
-
};
|
|
67
|
-
for (const taskId of Object.keys(taskGraph.tasks)) {
|
|
68
|
-
if (!visited.has(taskId)) {
|
|
69
|
-
dfs(taskId);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return cycles;
|
|
73
|
-
};
|
|
74
|
-
const walkTaskGraph = (taskGraph, callback) => {
|
|
75
|
-
const dependencyCount = /* @__PURE__ */ new Map();
|
|
76
|
-
for (const taskId of Object.keys(taskGraph.tasks)) {
|
|
77
|
-
dependencyCount.set(taskId, (taskGraph.dependencies[taskId] ?? []).length);
|
|
78
|
-
}
|
|
79
|
-
const dependents = /* @__PURE__ */ new Map();
|
|
80
|
-
for (const [taskId, deps] of Object.entries(taskGraph.dependencies)) {
|
|
81
|
-
for (const dep of deps) {
|
|
82
|
-
let list = dependents.get(dep);
|
|
83
|
-
if (!list) {
|
|
84
|
-
list = [];
|
|
85
|
-
dependents.set(dep, list);
|
|
86
|
-
}
|
|
87
|
-
list.push(taskId);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const queue = [];
|
|
91
|
-
for (const [taskId, count] of dependencyCount) {
|
|
92
|
-
if (count === 0) {
|
|
93
|
-
queue.push(taskId);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
while (queue.length > 0) {
|
|
97
|
-
const taskId = queue.shift();
|
|
98
|
-
callback(taskId);
|
|
99
|
-
const taskDependents = dependents.get(taskId) ?? [];
|
|
100
|
-
for (const dependent of taskDependents) {
|
|
101
|
-
const newCount = (dependencyCount.get(dependent) ?? 1) - 1;
|
|
102
|
-
dependencyCount.set(dependent, newCount);
|
|
103
|
-
if (newCount === 0) {
|
|
104
|
-
queue.push(dependent);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
const reverseTaskGraph = (taskGraph) => {
|
|
110
|
-
const reversedDependencies = {};
|
|
111
|
-
for (const taskId of Object.keys(taskGraph.tasks)) {
|
|
112
|
-
reversedDependencies[taskId] = [];
|
|
113
|
-
}
|
|
114
|
-
for (const [taskId, deps] of Object.entries(taskGraph.dependencies)) {
|
|
115
|
-
for (const dep of deps) {
|
|
116
|
-
reversedDependencies[dep]?.push(taskId);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const roots = Object.keys(taskGraph.tasks).filter((taskId) => (reversedDependencies[taskId]?.length ?? 0) === 0);
|
|
120
|
-
return {
|
|
121
|
-
dependencies: reversedDependencies,
|
|
122
|
-
roots,
|
|
123
|
-
tasks: { ...taskGraph.tasks }
|
|
124
|
-
};
|
|
125
|
-
};
|
|
126
|
-
const getLeafTasks = (taskGraph) => Object.keys(taskGraph.tasks).filter((taskId) => (taskGraph.dependencies[taskId]?.length ?? 0) === 0);
|
|
127
|
-
const makeAcyclic = (taskGraph) => {
|
|
128
|
-
const visited = /* @__PURE__ */ new Set();
|
|
129
|
-
const inStack = /* @__PURE__ */ new Set();
|
|
130
|
-
const edgesToRemove = [];
|
|
131
|
-
const dfs = (taskId) => {
|
|
132
|
-
visited.add(taskId);
|
|
133
|
-
inStack.add(taskId);
|
|
134
|
-
const deps = taskGraph.dependencies[taskId] ?? [];
|
|
135
|
-
for (const dep of deps) {
|
|
136
|
-
if (inStack.has(dep)) {
|
|
137
|
-
edgesToRemove.push({ from: taskId, to: dep });
|
|
138
|
-
} else if (!visited.has(dep)) {
|
|
139
|
-
dfs(dep);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
inStack.delete(taskId);
|
|
143
|
-
};
|
|
144
|
-
for (const taskId of Object.keys(taskGraph.tasks)) {
|
|
145
|
-
if (!visited.has(taskId)) {
|
|
146
|
-
dfs(taskId);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
const newDependencies = {};
|
|
150
|
-
for (const [taskId, deps] of Object.entries(taskGraph.dependencies)) {
|
|
151
|
-
newDependencies[taskId] = deps.filter((dep) => !edgesToRemove.some((edge) => edge.from === taskId && edge.to === dep));
|
|
152
|
-
}
|
|
153
|
-
const allDeps = /* @__PURE__ */ new Set();
|
|
154
|
-
for (const deps of Object.values(newDependencies)) {
|
|
155
|
-
for (const dep of deps) {
|
|
156
|
-
allDeps.add(dep);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
const roots = Object.keys(taskGraph.tasks).filter((taskId) => !allDeps.has(taskId));
|
|
160
|
-
return {
|
|
161
|
-
dependencies: newDependencies,
|
|
162
|
-
roots,
|
|
163
|
-
tasks: { ...taskGraph.tasks }
|
|
164
|
-
};
|
|
165
|
-
};
|
|
166
|
-
const getDependentTasks = (taskGraph, taskId) => {
|
|
167
|
-
const reversed = reverseTaskGraph(taskGraph);
|
|
168
|
-
const result = [];
|
|
169
|
-
const visited = /* @__PURE__ */ new Set();
|
|
170
|
-
const queue = [taskId];
|
|
171
|
-
while (queue.length > 0) {
|
|
172
|
-
const current = queue.shift();
|
|
173
|
-
if (visited.has(current)) {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
visited.add(current);
|
|
177
|
-
if (current !== taskId) {
|
|
178
|
-
result.push(current);
|
|
179
|
-
}
|
|
180
|
-
const deps = reversed.dependencies[current] ?? [];
|
|
181
|
-
for (const dep of deps) {
|
|
182
|
-
if (!visited.has(dep)) {
|
|
183
|
-
queue.push(dep);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return result;
|
|
188
|
-
};
|
|
189
|
-
const getTransitiveDependencies = (taskGraph, taskId) => {
|
|
190
|
-
const result = [];
|
|
191
|
-
const visited = /* @__PURE__ */ new Set();
|
|
192
|
-
const queue = [taskId];
|
|
193
|
-
while (queue.length > 0) {
|
|
194
|
-
const current = queue.shift();
|
|
195
|
-
if (visited.has(current)) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
visited.add(current);
|
|
199
|
-
if (current !== taskId) {
|
|
200
|
-
result.push(current);
|
|
201
|
-
}
|
|
202
|
-
const deps = taskGraph.dependencies[current] ?? [];
|
|
203
|
-
for (const dep of deps) {
|
|
204
|
-
if (!visited.has(dep)) {
|
|
205
|
-
queue.push(dep);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return result;
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
export { findCycle, findCycles, getDependentTasks, getLeafTasks, getTransitiveDependencies, makeAcyclic, reverseTaskGraph, walkTaskGraph };
|
|
@@ -1,134 +0,0 @@
|
|
|
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
|
-
mkdir,
|
|
22
|
-
writeFile
|
|
23
|
-
} = __cjs_getBuiltinModule("node:fs/promises");
|
|
24
|
-
import { join } from '@visulima/path';
|
|
25
|
-
import { u as uniqueId } from './utils-zO0ZRgtf.js';
|
|
26
|
-
|
|
27
|
-
const getCacheStatus = (result) => {
|
|
28
|
-
switch (result.status) {
|
|
29
|
-
case "local-cache":
|
|
30
|
-
case "local-cache-kept-existing": {
|
|
31
|
-
return "HIT";
|
|
32
|
-
}
|
|
33
|
-
case "remote-cache": {
|
|
34
|
-
return "REMOTE_HIT";
|
|
35
|
-
}
|
|
36
|
-
case "skipped": {
|
|
37
|
-
return "SKIPPED";
|
|
38
|
-
}
|
|
39
|
-
default: {
|
|
40
|
-
return "MISS";
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const generateRunSummary = (results, taskGraph, startTime) => {
|
|
45
|
-
const endTime = Date.now();
|
|
46
|
-
const id = `${new Date(startTime).toISOString().replaceAll(/[:.]/g, "-")}_${uniqueId()}`;
|
|
47
|
-
const tasks = [];
|
|
48
|
-
let succeeded = 0;
|
|
49
|
-
let failed = 0;
|
|
50
|
-
let cached = 0;
|
|
51
|
-
let skipped = 0;
|
|
52
|
-
for (const [taskId, result] of results) {
|
|
53
|
-
const taskDeps = taskGraph.dependencies[taskId] ?? [];
|
|
54
|
-
const summary = {
|
|
55
|
-
cacheable: result.task.cache !== false,
|
|
56
|
-
cacheStatus: getCacheStatus(result),
|
|
57
|
-
dependencies: taskDeps,
|
|
58
|
-
duration: result.startTime && result.endTime ? result.endTime - result.startTime : void 0,
|
|
59
|
-
endTime: result.endTime ? new Date(result.endTime).toISOString() : void 0,
|
|
60
|
-
exitCode: result.code,
|
|
61
|
-
hash: result.task.hash,
|
|
62
|
-
hashDetails: result.task.hashDetails,
|
|
63
|
-
outputs: result.task.outputs,
|
|
64
|
-
startTime: result.startTime ? new Date(result.startTime).toISOString() : void 0,
|
|
65
|
-
target: {
|
|
66
|
-
configuration: result.task.target.configuration,
|
|
67
|
-
project: result.task.target.project,
|
|
68
|
-
target: result.task.target.target
|
|
69
|
-
},
|
|
70
|
-
taskId
|
|
71
|
-
};
|
|
72
|
-
tasks.push(summary);
|
|
73
|
-
switch (result.status) {
|
|
74
|
-
case "failure": {
|
|
75
|
-
failed += 1;
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
case "local-cache":
|
|
79
|
-
// falls through
|
|
80
|
-
case "local-cache-kept-existing":
|
|
81
|
-
case "remote-cache": {
|
|
82
|
-
cached += 1;
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
case "skipped": {
|
|
86
|
-
skipped += 1;
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
case "success": {
|
|
90
|
-
succeeded += 1;
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const sortedTasks = tasks.toSorted((a, b) => {
|
|
96
|
-
if (!a.startTime || !b.startTime) {
|
|
97
|
-
return 0;
|
|
98
|
-
}
|
|
99
|
-
return a.startTime.localeCompare(b.startTime);
|
|
100
|
-
});
|
|
101
|
-
return {
|
|
102
|
-
duration: endTime - startTime,
|
|
103
|
-
endTime: new Date(endTime).toISOString(),
|
|
104
|
-
environment: {
|
|
105
|
-
arch: process.arch,
|
|
106
|
-
nodeVersion: process.version,
|
|
107
|
-
platform: process.platform
|
|
108
|
-
},
|
|
109
|
-
id,
|
|
110
|
-
startTime: new Date(startTime).toISOString(),
|
|
111
|
-
stats: {
|
|
112
|
-
cached,
|
|
113
|
-
failed,
|
|
114
|
-
skipped,
|
|
115
|
-
succeeded,
|
|
116
|
-
total: results.size
|
|
117
|
-
},
|
|
118
|
-
taskGraph: {
|
|
119
|
-
dependencies: taskGraph.dependencies,
|
|
120
|
-
roots: taskGraph.roots
|
|
121
|
-
},
|
|
122
|
-
tasks: sortedTasks
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
const writeRunSummary = async (summary, workspaceRoot) => {
|
|
126
|
-
const runsDirectory = join(workspaceRoot, ".task-runner", "runs");
|
|
127
|
-
await mkdir(runsDirectory, { recursive: true });
|
|
128
|
-
const filename = `${summary.id}.json`;
|
|
129
|
-
const filePath = join(runsDirectory, filename);
|
|
130
|
-
await writeFile(filePath, JSON.stringify(summary, void 0, 2));
|
|
131
|
-
return filePath;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
export { generateRunSummary, writeRunSummary };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import __cjs_mod__ from "node:module"; // -- packem CommonJS require shim --
|
|
2
|
-
const require = __cjs_mod__.createRequire(import.meta.url);
|
|
3
|
-
let nativeBindings;
|
|
4
|
-
let loadAttempted = false;
|
|
5
|
-
const loadNativeBindings = () => {
|
|
6
|
-
if (loadAttempted) {
|
|
7
|
-
return nativeBindings;
|
|
8
|
-
}
|
|
9
|
-
loadAttempted = true;
|
|
10
|
-
try {
|
|
11
|
-
nativeBindings = require("../binding.js");
|
|
12
|
-
} catch {
|
|
13
|
-
nativeBindings = void 0;
|
|
14
|
-
}
|
|
15
|
-
return nativeBindings;
|
|
16
|
-
};
|
|
17
|
-
const isNativeAvailable = () => loadNativeBindings() !== void 0;
|
|
18
|
-
|
|
19
|
-
export { isNativeAvailable, loadNativeBindings };
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
var __freeze = Object.freeze;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __template = (cooked, raw) => __freeze(__defProp(cooked, "raw", { value: __freeze(raw || cooked.slice()) }));
|
|
4
|
-
const getNodeColor = (taskId, focused, statuses) => {
|
|
5
|
-
if (focused && !focused.has(taskId)) {
|
|
6
|
-
return "#eeeeee";
|
|
7
|
-
}
|
|
8
|
-
const status = statuses?.get(taskId);
|
|
9
|
-
switch (status) {
|
|
10
|
-
case "failure": {
|
|
11
|
-
return "#FFB6C1";
|
|
12
|
-
}
|
|
13
|
-
case "local-cache":
|
|
14
|
-
case "local-cache-kept-existing":
|
|
15
|
-
case "remote-cache": {
|
|
16
|
-
return "#87CEEB";
|
|
17
|
-
}
|
|
18
|
-
case "running": {
|
|
19
|
-
return "#FFD700";
|
|
20
|
-
}
|
|
21
|
-
case "skipped": {
|
|
22
|
-
return "#D3D3D3";
|
|
23
|
-
}
|
|
24
|
-
case "success": {
|
|
25
|
-
return "#90EE90";
|
|
26
|
-
}
|
|
27
|
-
default: {
|
|
28
|
-
return "#FFFFFF";
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
const getStatusIcon = (status) => {
|
|
33
|
-
switch (status) {
|
|
34
|
-
case "failure": {
|
|
35
|
-
return "[FAIL] ";
|
|
36
|
-
}
|
|
37
|
-
case "local-cache":
|
|
38
|
-
case "local-cache-kept-existing":
|
|
39
|
-
case "remote-cache": {
|
|
40
|
-
return "[cache] ";
|
|
41
|
-
}
|
|
42
|
-
case "running": {
|
|
43
|
-
return "[...] ";
|
|
44
|
-
}
|
|
45
|
-
case "skipped": {
|
|
46
|
-
return "[skip] ";
|
|
47
|
-
}
|
|
48
|
-
case "success": {
|
|
49
|
-
return "[ok] ";
|
|
50
|
-
}
|
|
51
|
-
default: {
|
|
52
|
-
return "";
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
const formatTaskLine = (taskId, statuses) => {
|
|
57
|
-
const icon = getStatusIcon(statuses?.get(taskId));
|
|
58
|
-
return `${icon}${taskId}`;
|
|
59
|
-
};
|
|
60
|
-
const printTree = (taskId, prefix, isLast, taskGraph, printed, lines, statuses) => {
|
|
61
|
-
let connector;
|
|
62
|
-
if (prefix === "") {
|
|
63
|
-
connector = "";
|
|
64
|
-
} else if (isLast) {
|
|
65
|
-
connector = "└── ";
|
|
66
|
-
} else {
|
|
67
|
-
connector = "├── ";
|
|
68
|
-
}
|
|
69
|
-
const isDuplicate = printed.has(taskId);
|
|
70
|
-
const suffix = isDuplicate ? " (*)" : "";
|
|
71
|
-
const statusIcon = getStatusIcon(statuses?.get(taskId));
|
|
72
|
-
lines.push(`${prefix}${connector}${statusIcon}${taskId}${suffix}`);
|
|
73
|
-
if (isDuplicate) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
printed.add(taskId);
|
|
77
|
-
const deps = taskGraph.dependencies[taskId] ?? [];
|
|
78
|
-
let childPrefix;
|
|
79
|
-
if (prefix === "") {
|
|
80
|
-
childPrefix = "";
|
|
81
|
-
} else if (isLast) {
|
|
82
|
-
childPrefix = `${prefix} `;
|
|
83
|
-
} else {
|
|
84
|
-
childPrefix = `${prefix}│ `;
|
|
85
|
-
}
|
|
86
|
-
for (let i = 0; i < deps.length; i += 1) {
|
|
87
|
-
const isChildLast = i === deps.length - 1;
|
|
88
|
-
const dependency = deps[i];
|
|
89
|
-
if (dependency) {
|
|
90
|
-
printTree(dependency, childPrefix, isChildLast, taskGraph, printed, lines, statuses);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
const toGraphvizDot = (taskGraph, options = {}) => {
|
|
95
|
-
const { focusedTasks, groupByProject = true, taskStatuses } = options;
|
|
96
|
-
const focused = focusedTasks ? new Set(focusedTasks) : void 0;
|
|
97
|
-
const lines = ["digraph TaskGraph {", " rankdir=LR;", ' node [shape=box, style=filled, fontname="monospace"];'];
|
|
98
|
-
if (groupByProject) {
|
|
99
|
-
const projectTasks = /* @__PURE__ */ new Map();
|
|
100
|
-
for (const task of Object.values(taskGraph.tasks)) {
|
|
101
|
-
const { project } = task.target;
|
|
102
|
-
const list = projectTasks.get(project) ?? [];
|
|
103
|
-
list.push(task);
|
|
104
|
-
projectTasks.set(project, list);
|
|
105
|
-
}
|
|
106
|
-
for (const [project, tasks] of projectTasks) {
|
|
107
|
-
lines.push(` subgraph "cluster_${project}" {`, ` label="${project}";`, " style=dashed;", ' color="#888888";');
|
|
108
|
-
for (const task of tasks) {
|
|
109
|
-
const color = getNodeColor(task.id, focused, taskStatuses);
|
|
110
|
-
lines.push(` "${task.id}" [label="${task.target.target}", fillcolor="${color}"];`);
|
|
111
|
-
}
|
|
112
|
-
lines.push(" }");
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
for (const task of Object.values(taskGraph.tasks)) {
|
|
116
|
-
const color = getNodeColor(task.id, focused, taskStatuses);
|
|
117
|
-
lines.push(` "${task.id}" [fillcolor="${color}"];`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
for (const [taskId, deps] of Object.entries(taskGraph.dependencies)) {
|
|
121
|
-
for (const dep of deps) {
|
|
122
|
-
const edgeColor = focused && !focused.has(taskId) ? "#cccccc" : "#333333";
|
|
123
|
-
lines.push(` "${taskId}" -> "${dep}" [color="${edgeColor}"];`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
lines.push("}");
|
|
127
|
-
return lines.join("\n");
|
|
128
|
-
};
|
|
129
|
-
const toGraphJson = (taskGraph, taskStatuses) => {
|
|
130
|
-
const nodes = Object.values(taskGraph.tasks).map((task) => {
|
|
131
|
-
return {
|
|
132
|
-
configuration: task.target.configuration,
|
|
133
|
-
id: task.id,
|
|
134
|
-
project: task.target.project,
|
|
135
|
-
status: taskStatuses?.get(task.id),
|
|
136
|
-
target: task.target.target
|
|
137
|
-
};
|
|
138
|
-
});
|
|
139
|
-
const edges = [];
|
|
140
|
-
for (const [source, deps] of Object.entries(taskGraph.dependencies)) {
|
|
141
|
-
for (const target of deps) {
|
|
142
|
-
edges.push({ source, target });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return { edges, nodes, roots: taskGraph.roots };
|
|
146
|
-
};
|
|
147
|
-
var _a;
|
|
148
|
-
const toGraphHtml = (taskGraph, options = {}) => {
|
|
149
|
-
const graphData = toGraphJson(taskGraph, options.taskStatuses);
|
|
150
|
-
if (options.focusedTasks && options.focusedTasks.length > 0) {
|
|
151
|
-
const focused = new Set(options.focusedTasks);
|
|
152
|
-
graphData.nodes = graphData.nodes.filter((n) => focused.has(n.id));
|
|
153
|
-
graphData.edges = graphData.edges.filter((e) => focused.has(e.source) && focused.has(e.target));
|
|
154
|
-
graphData.roots = graphData.roots.filter((r) => focused.has(r));
|
|
155
|
-
}
|
|
156
|
-
return String.raw(_a || (_a = __template(['<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="UTF-8">\n<title>Task Graph</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #1a1a2e; color: #eee; }\n svg { width: 100vw; height: 100vh; }\n .node rect { rx: 6; ry: 6; stroke: #555; stroke-width: 1.5; cursor: pointer; }\n .node text { font-size: 11px; fill: #1a1a2e; font-weight: 600; pointer-events: none; }\n .node:hover rect { stroke: #fff; stroke-width: 2; }\n .edge { stroke: #444; stroke-width: 1.5; fill: none; marker-end: url(#arrow); }\n .label { font-size: 10px; fill: #888; }\n #info { position: fixed; top: 12px; right: 12px; background: #16213e; padding: 12px 16px; border-radius: 8px; font-size: 13px; }\n #info b { color: #e94560; }\n</style>\n</head>\n<body>\n<div id="info">\n <b>', "</b> tasks · <b>", "</b> dependencies · <b>", '</b> roots\n</div>\n<svg id="graph">\n <defs>\n <marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto">\n <path d="M 0 0 L 10 5 L 0 10 z" fill="#666"/>\n </marker>\n </defs>\n</svg>\n<script>\nconst data = ', ";\nconst svg = document.getElementById('graph');\nconst W = window.innerWidth, H = window.innerHeight;\nconst statusColors = {\n success: '#2ecc71', 'local-cache': '#3498db', 'remote-cache': '#9b59b6',\n failure: '#e74c3c', running: '#f39c12', skipped: '#95a5a6', pending: '#ecf0f1'\n};\nconst projectColors = {};\nconst palette = ['#e94560','#0f3460','#533483','#16c79a','#f39c12','#2ecc71','#3498db','#e67e22','#9b59b6','#1abc9c'];\nlet ci = 0;\ndata.nodes.forEach(n => {\n if (!projectColors[n.project]) projectColors[n.project] = palette[ci++ % palette.length];\n});\n\n// Simple force-directed layout\nconst nodes = data.nodes.map((n, i) => ({\n ...n, x: W/2 + (Math.random()-0.5)*400, y: H/2 + (Math.random()-0.5)*300, vx: 0, vy: 0\n}));\nconst nodeMap = new Map(nodes.map(n => [n.id, n]));\nconst edges = data.edges.map(e => ({ source: nodeMap.get(e.source), target: nodeMap.get(e.target) }));\n\nfunction simulate() {\n for (let iter = 0; iter < 300; iter++) {\n // Repulsion\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i+1; j < nodes.length; j++) {\n let dx = nodes[j].x - nodes[i].x, dy = nodes[j].y - nodes[i].y;\n let d = Math.sqrt(dx*dx + dy*dy) || 1;\n let f = 8000 / (d * d);\n nodes[i].vx -= dx/d * f; nodes[i].vy -= dy/d * f;\n nodes[j].vx += dx/d * f; nodes[j].vy += dy/d * f;\n }\n }\n // Attraction (edges)\n edges.forEach(e => {\n if (!e.source || !e.target) return;\n let dx = e.target.x - e.source.x, dy = e.target.y - e.source.y;\n let d = Math.sqrt(dx*dx + dy*dy) || 1;\n let f = (d - 150) * 0.01;\n e.source.vx += dx/d * f; e.source.vy += dy/d * f;\n e.target.vx -= dx/d * f; e.target.vy -= dy/d * f;\n });\n // Gravity\n nodes.forEach(n => {\n n.vx += (W/2 - n.x) * 0.001;\n n.vy += (H/2 - n.y) * 0.001;\n n.x += n.vx * 0.3; n.y += n.vy * 0.3;\n n.vx *= 0.8; n.vy *= 0.8;\n n.x = Math.max(60, Math.min(W-60, n.x));\n n.y = Math.max(30, Math.min(H-30, n.y));\n });\n }\n}\nsimulate();\n\n// Render\nedges.forEach(e => {\n if (!e.source || !e.target) return;\n const line = document.createElementNS('http://www.w3.org/2000/svg','line');\n line.setAttribute('x1', e.source.x); line.setAttribute('y1', e.source.y);\n line.setAttribute('x2', e.target.x); line.setAttribute('y2', e.target.y);\n line.setAttribute('class','edge');\n svg.appendChild(line);\n});\nnodes.forEach(n => {\n const g = document.createElementNS('http://www.w3.org/2000/svg','g');\n g.setAttribute('class','node');\n g.setAttribute('transform','translate('+(n.x-50)+','+(n.y-14)+')');\n const rect = document.createElementNS('http://www.w3.org/2000/svg','rect');\n rect.setAttribute('width','100'); rect.setAttribute('height','28');\n rect.setAttribute('fill', n.status ? (statusColors[n.status]||'#ecf0f1') : projectColors[n.project]);\n g.appendChild(rect);\n const text = document.createElementNS('http://www.w3.org/2000/svg','text');\n text.setAttribute('x','50'); text.setAttribute('y','18'); text.setAttribute('text-anchor','middle');\n text.textContent = n.id.length > 14 ? n.target : n.id;\n g.appendChild(text);\n g.addEventListener('click', () => {\n const deps = data.edges.filter(e => e.source === n.id).map(e => e.target);\n const rdeps = data.edges.filter(e => e.target === n.id).map(e => e.source);\n alert(n.id + '\n\nDepends on: ' + (deps.join(', ')||'none') + '\nRequired by: ' + (rdeps.join(', ')||'none'));\n });\n svg.appendChild(g);\n});\n<\/script>\n</body>\n</html>"], ['<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="UTF-8">\n<title>Task Graph</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #1a1a2e; color: #eee; }\n svg { width: 100vw; height: 100vh; }\n .node rect { rx: 6; ry: 6; stroke: #555; stroke-width: 1.5; cursor: pointer; }\n .node text { font-size: 11px; fill: #1a1a2e; font-weight: 600; pointer-events: none; }\n .node:hover rect { stroke: #fff; stroke-width: 2; }\n .edge { stroke: #444; stroke-width: 1.5; fill: none; marker-end: url(#arrow); }\n .label { font-size: 10px; fill: #888; }\n #info { position: fixed; top: 12px; right: 12px; background: #16213e; padding: 12px 16px; border-radius: 8px; font-size: 13px; }\n #info b { color: #e94560; }\n</style>\n</head>\n<body>\n<div id="info">\n <b>', "</b> tasks · <b>", "</b> dependencies · <b>", '</b> roots\n</div>\n<svg id="graph">\n <defs>\n <marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto">\n <path d="M 0 0 L 10 5 L 0 10 z" fill="#666"/>\n </marker>\n </defs>\n</svg>\n<script>\nconst data = ', ";\nconst svg = document.getElementById('graph');\nconst W = window.innerWidth, H = window.innerHeight;\nconst statusColors = {\n success: '#2ecc71', 'local-cache': '#3498db', 'remote-cache': '#9b59b6',\n failure: '#e74c3c', running: '#f39c12', skipped: '#95a5a6', pending: '#ecf0f1'\n};\nconst projectColors = {};\nconst palette = ['#e94560','#0f3460','#533483','#16c79a','#f39c12','#2ecc71','#3498db','#e67e22','#9b59b6','#1abc9c'];\nlet ci = 0;\ndata.nodes.forEach(n => {\n if (!projectColors[n.project]) projectColors[n.project] = palette[ci++ % palette.length];\n});\n\n// Simple force-directed layout\nconst nodes = data.nodes.map((n, i) => ({\n ...n, x: W/2 + (Math.random()-0.5)*400, y: H/2 + (Math.random()-0.5)*300, vx: 0, vy: 0\n}));\nconst nodeMap = new Map(nodes.map(n => [n.id, n]));\nconst edges = data.edges.map(e => ({ source: nodeMap.get(e.source), target: nodeMap.get(e.target) }));\n\nfunction simulate() {\n for (let iter = 0; iter < 300; iter++) {\n // Repulsion\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i+1; j < nodes.length; j++) {\n let dx = nodes[j].x - nodes[i].x, dy = nodes[j].y - nodes[i].y;\n let d = Math.sqrt(dx*dx + dy*dy) || 1;\n let f = 8000 / (d * d);\n nodes[i].vx -= dx/d * f; nodes[i].vy -= dy/d * f;\n nodes[j].vx += dx/d * f; nodes[j].vy += dy/d * f;\n }\n }\n // Attraction (edges)\n edges.forEach(e => {\n if (!e.source || !e.target) return;\n let dx = e.target.x - e.source.x, dy = e.target.y - e.source.y;\n let d = Math.sqrt(dx*dx + dy*dy) || 1;\n let f = (d - 150) * 0.01;\n e.source.vx += dx/d * f; e.source.vy += dy/d * f;\n e.target.vx -= dx/d * f; e.target.vy -= dy/d * f;\n });\n // Gravity\n nodes.forEach(n => {\n n.vx += (W/2 - n.x) * 0.001;\n n.vy += (H/2 - n.y) * 0.001;\n n.x += n.vx * 0.3; n.y += n.vy * 0.3;\n n.vx *= 0.8; n.vy *= 0.8;\n n.x = Math.max(60, Math.min(W-60, n.x));\n n.y = Math.max(30, Math.min(H-30, n.y));\n });\n }\n}\nsimulate();\n\n// Render\nedges.forEach(e => {\n if (!e.source || !e.target) return;\n const line = document.createElementNS('http://www.w3.org/2000/svg','line');\n line.setAttribute('x1', e.source.x); line.setAttribute('y1', e.source.y);\n line.setAttribute('x2', e.target.x); line.setAttribute('y2', e.target.y);\n line.setAttribute('class','edge');\n svg.appendChild(line);\n});\nnodes.forEach(n => {\n const g = document.createElementNS('http://www.w3.org/2000/svg','g');\n g.setAttribute('class','node');\n g.setAttribute('transform','translate('+(n.x-50)+','+(n.y-14)+')');\n const rect = document.createElementNS('http://www.w3.org/2000/svg','rect');\n rect.setAttribute('width','100'); rect.setAttribute('height','28');\n rect.setAttribute('fill', n.status ? (statusColors[n.status]||'#ecf0f1') : projectColors[n.project]);\n g.appendChild(rect);\n const text = document.createElementNS('http://www.w3.org/2000/svg','text');\n text.setAttribute('x','50'); text.setAttribute('y','18'); text.setAttribute('text-anchor','middle');\n text.textContent = n.id.length > 14 ? n.target : n.id;\n g.appendChild(text);\n g.addEventListener('click', () => {\n const deps = data.edges.filter(e => e.source === n.id).map(e => e.target);\n const rdeps = data.edges.filter(e => e.target === n.id).map(e => e.source);\n alert(n.id + '\\n\\nDepends on: ' + (deps.join(', ')||'none') + '\\nRequired by: ' + (rdeps.join(', ')||'none'));\n });\n svg.appendChild(g);\n});\n<\/script>\n</body>\n</html>"])), graphData.nodes.length, graphData.edges.length, graphData.roots.length, JSON.stringify(graphData).replaceAll("</", String.raw`<\/`));
|
|
157
|
-
};
|
|
158
|
-
const toGraphAscii = (taskGraph, options = {}) => {
|
|
159
|
-
const { taskStatuses } = options;
|
|
160
|
-
const lines = [];
|
|
161
|
-
const taskCount = Object.keys(taskGraph.tasks).length;
|
|
162
|
-
const edgeCount = Object.values(taskGraph.dependencies).reduce((s, d) => s + d.length, 0);
|
|
163
|
-
lines.push(`Task Graph (${taskCount} tasks, ${edgeCount} dependencies)`, "");
|
|
164
|
-
const allDeps = /* @__PURE__ */ new Set();
|
|
165
|
-
for (const deps of Object.values(taskGraph.dependencies)) {
|
|
166
|
-
for (const dep of deps) {
|
|
167
|
-
allDeps.add(dep);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
const roots = Object.keys(taskGraph.tasks).filter((id) => !allDeps.has(id));
|
|
171
|
-
if (roots.length === 0) {
|
|
172
|
-
for (const taskId of Object.keys(taskGraph.tasks)) {
|
|
173
|
-
lines.push(formatTaskLine(taskId, taskStatuses));
|
|
174
|
-
}
|
|
175
|
-
return lines.join("\n");
|
|
176
|
-
}
|
|
177
|
-
const printed = /* @__PURE__ */ new Set();
|
|
178
|
-
for (const root of roots) {
|
|
179
|
-
printTree(root, "", true, taskGraph, printed, lines, taskStatuses);
|
|
180
|
-
}
|
|
181
|
-
if (printed.size < taskCount) {
|
|
182
|
-
lines.push("", "(*) = already shown above");
|
|
183
|
-
}
|
|
184
|
-
return lines.join("\n");
|
|
185
|
-
};
|
|
186
|
-
const projectGraphToDot = (projectGraph) => {
|
|
187
|
-
const lines = ["digraph ProjectGraph {", " rankdir=LR;", ' node [shape=box, style=filled, fillcolor="#87CEEB", fontname="monospace"];'];
|
|
188
|
-
for (const node of Object.values(projectGraph.nodes)) {
|
|
189
|
-
const color = node.type === "application" ? "#FFD700" : "#87CEEB";
|
|
190
|
-
lines.push(` "${node.name}" [fillcolor="${color}"];`);
|
|
191
|
-
}
|
|
192
|
-
for (const [project, deps] of Object.entries(projectGraph.dependencies)) {
|
|
193
|
-
for (const dep of deps) {
|
|
194
|
-
const style = dep.type === "implicit" ? "dashed" : "solid";
|
|
195
|
-
lines.push(` "${project}" -> "${dep.target}" [style=${style}];`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
lines.push("}");
|
|
199
|
-
return lines.join("\n");
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
export { projectGraphToDot, toGraphAscii, toGraphHtml, toGraphJson, toGraphvizDot };
|