@procedures/lib 0.2.3 → 0.4.0
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 +89 -0
- package/README.md +19 -40
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +22 -51
- package/dist/module.js.map +1 -1
- package/dist/procedures/lib/graph.d.ts +21 -0
- package/dist/procedures/lib/graph.d.ts.map +1 -0
- package/dist/procedures/lib/graph.js +118 -0
- package/dist/procedures/lib/graph.js.map +1 -0
- package/dist/procedures/lib/index.d.ts +1 -0
- package/dist/procedures/lib/index.d.ts.map +1 -1
- package/dist/procedures/lib/index.js +1 -0
- package/dist/procedures/lib/index.js.map +1 -1
- package/dist/types.d.ts +42 -58
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +27 -89
- package/dist/types.js.map +1 -1
- package/package.json +9 -9
- package/src/index.ts +2 -0
- package/src/module.ts +22 -60
- package/src/procedures/lib/graph.ts +134 -0
- package/src/procedures/lib/index.ts +1 -0
- package/src/types.ts +77 -144
- package/dist/procedures/core/catch.d.ts +0 -33
- package/dist/procedures/core/catch.d.ts.map +0 -1
- package/dist/procedures/core/catch.js +0 -118
- package/dist/procedures/core/catch.js.map +0 -1
- package/dist/procedures/core/index.d.ts +0 -9
- package/dist/procedures/core/index.d.ts.map +0 -1
- package/dist/procedures/core/index.js +0 -8
- package/dist/procedures/core/index.js.map +0 -1
- package/dist/procedures/dag/index.d.ts +0 -5
- package/dist/procedures/dag/index.d.ts.map +0 -1
- package/dist/procedures/dag/index.js +0 -5
- package/dist/procedures/dag/index.js.map +0 -1
- package/dist/procedures/dag/traverse.d.ts +0 -54
- package/dist/procedures/dag/traverse.d.ts.map +0 -1
- package/dist/procedures/dag/traverse.js +0 -252
- package/dist/procedures/dag/traverse.js.map +0 -1
- package/src/procedures/core/catch.ts +0 -142
- package/src/procedures/core/index.ts +0 -9
- package/src/procedures/dag/index.ts +0 -5
- package/src/procedures/dag/traverse.ts +0 -281
package/dist/types.js
CHANGED
|
@@ -44,76 +44,7 @@ export const LibAuditInputSchema = z.object({
|
|
|
44
44
|
/** Attempt to fix issues (create missing files/dirs) */
|
|
45
45
|
fix: z.boolean().default(false).describe("Attempt to fix issues (create missing files/dirs)"),
|
|
46
46
|
});
|
|
47
|
-
//
|
|
48
|
-
// dag.traverse Types
|
|
49
|
-
// =============================================================================
|
|
50
|
-
/**
|
|
51
|
-
* Schema for $proc references with $when control.
|
|
52
|
-
*/
|
|
53
|
-
const ProcRefSchema = z.object({
|
|
54
|
-
$proc: z.array(z.string()),
|
|
55
|
-
input: z.unknown().optional(),
|
|
56
|
-
$when: z.string().optional(),
|
|
57
|
-
$name: z.string().optional(),
|
|
58
|
-
});
|
|
59
|
-
export const DagTraverseInputSchema = z.object({
|
|
60
|
-
/**
|
|
61
|
-
* Procedure to execute for each node.
|
|
62
|
-
* - Array: procedure path, e.g., ["git", "add"]
|
|
63
|
-
* - $proc with $when: "$never" or "$parent": deferred, executed per-node
|
|
64
|
-
*
|
|
65
|
-
* Example:
|
|
66
|
-
* ```json
|
|
67
|
-
* { "$proc": ["git", "add"], "input": { "all": true }, "$when": "$parent" }
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
visit: z.union([
|
|
71
|
-
z.array(z.string()),
|
|
72
|
-
ProcRefSchema,
|
|
73
|
-
]).describe("Procedure to execute for each node. - Array: procedure path, e.g., [\"git\", \"add\"] - $proc with $when: \"$never\" or \"$parent\": deferred, executed per-node Example: ```json { \"$proc\": [\"git\", \"add\"], \"input\": { \"all\": true }, \"$when\": \"$parent\" } ```"),
|
|
74
|
-
/** Filter to specific package names */
|
|
75
|
-
filter: z.array(z.string()).optional().describe("Filter to specific package names"),
|
|
76
|
-
/** Start from specific root package */
|
|
77
|
-
root: z.string().optional().describe("Start from specific root package"),
|
|
78
|
-
/** Workspace root (defaults to the pnpm workspace that contains client-lib) */
|
|
79
|
-
rootPath: z.string().optional().describe("Workspace root (defaults to the pnpm workspace that contains client-lib)"),
|
|
80
|
-
/** Max parallel operations (default: 4) */
|
|
81
|
-
concurrency: z.number().default(4).describe("Max parallel operations (default: 4)"),
|
|
82
|
-
/**
|
|
83
|
-
* When the visits of nodes in one git repository run one at a time (default: "auto").
|
|
84
|
-
* - "auto": when the visit calls a `git` procedure (git locks the index of the repository)
|
|
85
|
-
* - "repository": always
|
|
86
|
-
* - "none": never
|
|
87
|
-
*/
|
|
88
|
-
serialize: z.enum(["auto", "repository", "none"]).default("auto").describe("When the visits of nodes in one git repository run one at a time (default: \"auto\"). - \"auto\": when the visit calls a `git` procedure (git locks the index of the repository) - \"repository\": always - \"none\": never"),
|
|
89
|
-
/** Continue on error (default: false) */
|
|
90
|
-
continueOnError: z.boolean().default(false).describe("Continue on error (default: false)"),
|
|
91
|
-
/** Preview without executing (default: false) */
|
|
92
|
-
dryRun: z.boolean().default(false).describe("Preview without executing (default: false)"),
|
|
93
|
-
});
|
|
94
|
-
// =============================================================================
|
|
95
|
-
// core.catch Types
|
|
96
|
-
// =============================================================================
|
|
97
|
-
export const CoreCatchInputSchema = z.object({
|
|
98
|
-
/**
|
|
99
|
-
* Procedure ref to try executing.
|
|
100
|
-
* Should use $when: "catch" so it's not auto-executed during hydration.
|
|
101
|
-
*
|
|
102
|
-
* Example:
|
|
103
|
-
* ```json
|
|
104
|
-
* { "$proc": ["git", "commit"], "input": { "message": "auto" }, "$when": "catch" }
|
|
105
|
-
* ```
|
|
106
|
-
*/
|
|
107
|
-
try: z.unknown().describe("Procedure ref to try executing. Should use $when: \"catch\" so it's not auto-executed during hydration. Example: ```json { \"$proc\": [\"git\", \"commit\"], \"input\": { \"message\": \"auto\" }, \"$when\": \"catch\" } ```"),
|
|
108
|
-
/**
|
|
109
|
-
* Handler procedure ref called on error.
|
|
110
|
-
* Receives StepResultInfo (success, error, proc) merged with its input.
|
|
111
|
-
* Should return ContinueDecision { continue: boolean }.
|
|
112
|
-
*/
|
|
113
|
-
handler: z.unknown().optional().describe("Handler procedure ref called on error. Receives StepResultInfo (success, error, proc) merged with its input. Should return ContinueDecision { continue: boolean }."),
|
|
114
|
-
/** Working directory for procedure execution */
|
|
115
|
-
cwd: z.string().optional().describe("Working directory for procedure execution"),
|
|
116
|
-
});
|
|
47
|
+
// The types of dag.traverse are in @procedures/dag. core.catch is removed: use client.tryCatch.
|
|
117
48
|
// =============================================================================
|
|
118
49
|
// Output schemas (roadmap 2.1)
|
|
119
50
|
// =============================================================================
|
|
@@ -206,26 +137,33 @@ export const LibAuditOutputSchema = z.looseObject({
|
|
|
206
137
|
})
|
|
207
138
|
.describe("The counts"),
|
|
208
139
|
});
|
|
209
|
-
export const
|
|
210
|
-
|
|
211
|
-
|
|
140
|
+
export const LibGraphInputSchema = z.object({
|
|
141
|
+
rootPath: z.string().optional().describe("The workspace root (default: the pnpm workspace that contains client-lib)"),
|
|
142
|
+
});
|
|
143
|
+
const DEPENDENCY_KINDS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
144
|
+
export const LibGraphOutputSchema = z.looseObject({
|
|
145
|
+
root: z.string().describe("The workspace root"),
|
|
146
|
+
nodes: z
|
|
212
147
|
.array(z.looseObject({
|
|
213
|
-
name: z.string().describe("The
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
error: z.string().optional().describe("The error of a failed visit"),
|
|
218
|
-
output: z.unknown().optional().describe("The result of the visit"),
|
|
148
|
+
name: z.string().describe("The name in package.json"),
|
|
149
|
+
folder: z.string().describe("The folder in packages/"),
|
|
150
|
+
version: z.string().optional().describe("The version in package.json"),
|
|
151
|
+
private: z.boolean().optional().describe("True for a private package"),
|
|
219
152
|
}))
|
|
220
|
-
.describe("The
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
153
|
+
.describe("The workspace packages, in name order"),
|
|
154
|
+
edges: z
|
|
155
|
+
.array(z.looseObject({
|
|
156
|
+
from: z.string().describe("The package that depends"),
|
|
157
|
+
to: z.string().describe("The package that it depends on"),
|
|
158
|
+
kind: z.enum(DEPENDENCY_KINDS).describe("The field of package.json"),
|
|
159
|
+
spec: z.string().describe("The specifier, for example workspace:*"),
|
|
160
|
+
}))
|
|
161
|
+
.describe("The workspace: dependencies between the packages"),
|
|
162
|
+
acyclic: z.boolean().describe("True when the graph has no cycle"),
|
|
163
|
+
cycles: z.array(z.array(z.string())).describe("Each cycle: the packages of a strongly connected component, in name order"),
|
|
164
|
+
levels: z.array(z.array(z.string())).optional().describe("Without a cycle: the packages in levels. Level 0 depends on no workspace package."),
|
|
165
|
+
warnings: z
|
|
166
|
+
.array(z.looseObject({ path: z.string().describe("The folder"), issue: z.string().describe("The problem") }))
|
|
167
|
+
.describe("The folders that the procedure could not read"),
|
|
230
168
|
});
|
|
231
169
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,kBAAkB,GAE1B,CAAC,CAAC,MAAM,CAAC;IACZ,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;CACrH,CAAC,CAAC;AA8EH,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,oBAAoB,GAK5B,CAAC,CAAC,MAAM,CAAC;IACZ,0CAA0C;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACnE,oCAAoC;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IAC7D,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;IACpH,wDAAwD;IACxD,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,mDAAmD,CAAC;CACjG,CAAC,CAAC;AAmCH,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,iBAAiB,GAKzB,CAAC,CAAC,MAAM,CAAC;IACZ,oDAAoD;IACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,EAAE,kDAAkD,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;IACzJ,4BAA4B;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,EAAE,oDAAoD,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;IACpJ,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;IACpH,uCAAuC;IACvC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;CAChF,CAAC,CAAC;AAmBH,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,mBAAmB,GAG3B,CAAC,CAAC,MAAM,CAAC;IACZ,+EAA+E;IAC/E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;IACpH,wDAAwD;IACxD,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,mDAAmD,CAAC;CAC9F,CAAC,CAAC;AAiEH,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/lib",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "Workspace procedures for pnpm monorepos: scan the packages, scaffold a new package, audit packages against a template, rename across the workspace
|
|
4
|
+
"version": "0.4.0",
|
|
5
|
+
"description": "Workspace procedures for pnpm monorepos: scan the packages, graph their dependencies, scaffold a new package, audit packages against a template, and rename across the workspace.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"monorepo",
|
|
8
8
|
"pnpm",
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
"vitest": "^5.0.3"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@procedures/client": "0.
|
|
72
|
-
"@procedures/dag": "0.
|
|
73
|
-
"@procedures/fs": "0.
|
|
74
|
-
"@procedures/git": "0.
|
|
75
|
-
"@procedures/pnpm": "0.
|
|
76
|
-
"@procedures/shell": "0.
|
|
71
|
+
"@procedures/client": "0.4.0",
|
|
72
|
+
"@procedures/dag": "0.4.0",
|
|
73
|
+
"@procedures/fs": "0.4.0",
|
|
74
|
+
"@procedures/git": "0.4.0",
|
|
75
|
+
"@procedures/pnpm": "0.4.0",
|
|
76
|
+
"@procedures/shell": "0.4.0",
|
|
77
77
|
"ts-morph": "^24.0.0",
|
|
78
78
|
"zod": "^4.6.5"
|
|
79
79
|
},
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"build": "tsc -b",
|
|
85
85
|
"typecheck": "tsc --noEmit",
|
|
86
86
|
"clean": "rm -rf dist .tsbuildinfo",
|
|
87
|
-
"test": "vitest run
|
|
87
|
+
"test": "vitest run",
|
|
88
88
|
"test:watch": "vitest"
|
|
89
89
|
}
|
|
90
90
|
}
|
package/src/index.ts
CHANGED
package/src/module.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* client-cli no longer registers these to avoid duplicates.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { createProcedure, zodAdapter,
|
|
10
|
+
import { createProcedure, zodAdapter, defineModule, type ProcedureModule, PROCEDURE_REGISTRY, registerModules, type ProcedureRegistry } from "@procedures/client";
|
|
11
11
|
import gitModule from "@procedures/git/module";
|
|
12
12
|
import fsModule from "@procedures/fs/module";
|
|
13
13
|
import {
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
libRename,
|
|
16
16
|
libNew,
|
|
17
17
|
libAudit,
|
|
18
|
+
libGraph,
|
|
18
19
|
} from "./procedures/lib/index.js";
|
|
19
20
|
import {
|
|
20
21
|
ecosystemProcedures,
|
|
@@ -23,15 +24,11 @@ import {
|
|
|
23
24
|
type EcosystemProceduresInput,
|
|
24
25
|
type EcosystemProceduresOutput,
|
|
25
26
|
} from "./procedures/ecosystem/index.js";
|
|
26
|
-
import { dagTraverse } from "./procedures/dag/index.js";
|
|
27
|
-
import { coreCatch } from "./procedures/core/index.js";
|
|
28
27
|
import {
|
|
29
28
|
LibScanInputSchema,
|
|
30
29
|
LibRenameInputSchema,
|
|
31
30
|
LibNewInputSchema,
|
|
32
31
|
LibAuditInputSchema,
|
|
33
|
-
DagTraverseInputSchema,
|
|
34
|
-
CoreCatchInputSchema,
|
|
35
32
|
type LibScanInput,
|
|
36
33
|
type LibScanOutput,
|
|
37
34
|
type LibRenameInput,
|
|
@@ -40,17 +37,12 @@ import {
|
|
|
40
37
|
type LibNewOutput,
|
|
41
38
|
type LibAuditInput,
|
|
42
39
|
type LibAuditOutput,
|
|
43
|
-
type DagTraverseInput,
|
|
44
|
-
type DagTraverseOutput,
|
|
45
|
-
type CoreCatchInput,
|
|
46
|
-
type CoreCatchOutput,
|
|
47
40
|
LibScanOutputSchema,
|
|
48
41
|
LibRenameOutputSchema,
|
|
49
42
|
LibNewOutputSchema,
|
|
50
43
|
LibAuditOutputSchema,
|
|
51
|
-
DagTraverseOutputSchema,
|
|
52
|
-
CoreCatchOutputSchema,
|
|
53
44
|
} from "./types.js";
|
|
45
|
+
import { LibGraphInputSchema, LibGraphOutputSchema, type LibGraphInput, type LibGraphOutput } from "./types.js";
|
|
54
46
|
import type { ProcedureContext } from "@procedures/client";
|
|
55
47
|
|
|
56
48
|
// =============================================================================
|
|
@@ -131,6 +123,22 @@ const libAuditProcedure = createProcedure()
|
|
|
131
123
|
})
|
|
132
124
|
.build();
|
|
133
125
|
|
|
126
|
+
// lib.graph (roadmap R44)
|
|
127
|
+
const libGraphProcedure = createProcedure()
|
|
128
|
+
.path(["lib", "graph"])
|
|
129
|
+
.input(zodAdapter<LibGraphInput>(LibGraphInputSchema))
|
|
130
|
+
.output(zodAdapter<LibGraphOutput>(LibGraphOutputSchema))
|
|
131
|
+
.meta({
|
|
132
|
+
description: "The dependency graph of the workspace packages: nodes, workspace: edges, cycles and build levels",
|
|
133
|
+
calls: ["fs.readdir", "fs.read.json"],
|
|
134
|
+
effects: { reads: ["fs"], writes: [] },
|
|
135
|
+
args: [],
|
|
136
|
+
shorts: {},
|
|
137
|
+
output: "json",
|
|
138
|
+
})
|
|
139
|
+
.handler(async (input: LibGraphInput, ctx: ProcedureContext): Promise<LibGraphOutput> => libGraph(input, ctx))
|
|
140
|
+
.build();
|
|
141
|
+
|
|
134
142
|
// =============================================================================
|
|
135
143
|
// ecosystem.* Procedures
|
|
136
144
|
// =============================================================================
|
|
@@ -152,51 +160,8 @@ const ecosystemProceduresProcedure = createProcedure()
|
|
|
152
160
|
})
|
|
153
161
|
.build();
|
|
154
162
|
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
// =============================================================================
|
|
158
|
-
|
|
159
|
-
const dagTraverseProcedure = createProcedure()
|
|
160
|
-
.path(["dag", "traverse"])
|
|
161
|
-
.input(zodAdapter<DagTraverseInput>(DagTraverseInputSchema))
|
|
162
|
-
.output(zodAdapter<DagTraverseOutput>(DagTraverseOutputSchema))
|
|
163
|
-
.meta({
|
|
164
|
-
description: "Traverse ecosystem packages in dependency order, executing visit procedure for each",
|
|
165
|
-
// It runs the procedure refs of its input: a server with an expose rule limits what they call
|
|
166
|
-
tags: [RUNS_REFS_TAG],
|
|
167
|
-
// Its own effect is the scan of the workspace. The admission examines each visit call.
|
|
168
|
-
effects: { reads: ["fs"], writes: [] },
|
|
169
|
-
args: [],
|
|
170
|
-
shorts: { root: "r", concurrency: "j", continueOnError: "c", dryRun: "d" },
|
|
171
|
-
output: "streaming",
|
|
172
|
-
})
|
|
173
|
-
.handler(async (input: DagTraverseInput, ctx: ProcedureContext): Promise<DagTraverseOutput> => {
|
|
174
|
-
return dagTraverse(input, ctx);
|
|
175
|
-
})
|
|
176
|
-
.build();
|
|
177
|
-
|
|
178
|
-
// =============================================================================
|
|
179
|
-
// core.* Procedures
|
|
180
|
-
// =============================================================================
|
|
181
|
-
|
|
182
|
-
const coreCatchProcedure = createProcedure()
|
|
183
|
-
.path(["core", "catch"])
|
|
184
|
-
.input(zodAdapter<CoreCatchInput>(CoreCatchInputSchema))
|
|
185
|
-
.output(zodAdapter<CoreCatchOutput>(CoreCatchOutputSchema))
|
|
186
|
-
.meta({
|
|
187
|
-
description: "Execute a procedure with error handling",
|
|
188
|
-
// It runs the procedure refs of its input: a server with an expose rule limits what they call
|
|
189
|
-
tags: [RUNS_REFS_TAG],
|
|
190
|
-
// Control flow: no effects of its own. The admission examines each nested call.
|
|
191
|
-
effects: { reads: [], writes: [] },
|
|
192
|
-
args: [],
|
|
193
|
-
shorts: {},
|
|
194
|
-
output: "json",
|
|
195
|
-
})
|
|
196
|
-
.handler(async (input: CoreCatchInput, ctx: ProcedureContext): Promise<CoreCatchOutput> => {
|
|
197
|
-
return coreCatch(input, ctx);
|
|
198
|
-
})
|
|
199
|
-
.build();
|
|
163
|
+
// dag.traverse is in the module of @procedures/dag. It calls lib.scan of this module.
|
|
164
|
+
// core.catch is removed: client.tryCatch of @procedures/client does the same.
|
|
200
165
|
|
|
201
166
|
// =============================================================================
|
|
202
167
|
// Registration
|
|
@@ -212,12 +177,9 @@ export const libModule: ProcedureModule = defineModule("@procedures/lib", [
|
|
|
212
177
|
libRenameProcedure,
|
|
213
178
|
libNewProcedure,
|
|
214
179
|
libAuditProcedure,
|
|
180
|
+
libGraphProcedure,
|
|
215
181
|
// ecosystem.* procedures
|
|
216
182
|
ecosystemProceduresProcedure,
|
|
217
|
-
// dag.* procedures (canonical home)
|
|
218
|
-
dagTraverseProcedure,
|
|
219
|
-
// core.* procedures
|
|
220
|
-
coreCatchProcedure,
|
|
221
183
|
], [fsModule, gitModule]);
|
|
222
184
|
|
|
223
185
|
export default libModule;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib.graph procedure (roadmap R44)
|
|
3
|
+
*
|
|
4
|
+
* The dependency graph of the workspace packages (`<root>/packages/*`): one node for each
|
|
5
|
+
* package, and one edge for each dependency with a `workspace:` specifier. The procedure finds
|
|
6
|
+
* the cycles (the strongly connected components, and a package that depends on itself). Without
|
|
7
|
+
* a cycle, it also gives the levels of a build order. It only reads, through `fs.readdir` and
|
|
8
|
+
* `fs.read.json`, so a root of the host confines it as it confines `lib.scan`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { buildLeveledDAG, type DAGNode } from "@procedures/dag";
|
|
13
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
14
|
+
import type { DependencyKind, LibGraphEdge, LibGraphInput, LibGraphNode, LibGraphOutput } from "../../types.js";
|
|
15
|
+
import { packagesDir, resolveWorkspaceRoot } from "../../workspace.js";
|
|
16
|
+
|
|
17
|
+
const KINDS: readonly DependencyKind[] = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
18
|
+
|
|
19
|
+
interface PackageJson {
|
|
20
|
+
name?: unknown;
|
|
21
|
+
version?: unknown;
|
|
22
|
+
private?: unknown;
|
|
23
|
+
dependencies?: Record<string, string>;
|
|
24
|
+
devDependencies?: Record<string, string>;
|
|
25
|
+
peerDependencies?: Record<string, string>;
|
|
26
|
+
optionalDependencies?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface FsReaddirOutput {
|
|
30
|
+
entries: Array<{ name: string; type: string }>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The cycles of a graph: each strongly connected component with more than one node, and each
|
|
35
|
+
* node with an edge to itself (Tarjan's algorithm). Each cycle and the list are in name order.
|
|
36
|
+
*/
|
|
37
|
+
export function findCycles(names: readonly string[], edges: ReadonlyMap<string, readonly string[]>): string[][] {
|
|
38
|
+
let counter = 0;
|
|
39
|
+
const index = new Map<string, number>();
|
|
40
|
+
const low = new Map<string, number>();
|
|
41
|
+
const stack: string[] = [];
|
|
42
|
+
const onStack = new Set<string>();
|
|
43
|
+
const cycles: string[][] = [];
|
|
44
|
+
|
|
45
|
+
const visit = (name: string): void => {
|
|
46
|
+
index.set(name, counter);
|
|
47
|
+
low.set(name, counter);
|
|
48
|
+
counter++;
|
|
49
|
+
stack.push(name);
|
|
50
|
+
onStack.add(name);
|
|
51
|
+
for (const next of edges.get(name) ?? []) {
|
|
52
|
+
if (!index.has(next)) {
|
|
53
|
+
visit(next);
|
|
54
|
+
low.set(name, Math.min(low.get(name)!, low.get(next)!));
|
|
55
|
+
} else if (onStack.has(next)) {
|
|
56
|
+
low.set(name, Math.min(low.get(name)!, index.get(next)!));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (low.get(name) === index.get(name)) {
|
|
60
|
+
const component: string[] = [];
|
|
61
|
+
let member: string;
|
|
62
|
+
do {
|
|
63
|
+
member = stack.pop()!;
|
|
64
|
+
onStack.delete(member);
|
|
65
|
+
component.push(member);
|
|
66
|
+
} while (member !== name);
|
|
67
|
+
const selfEdge = component.length === 1 && (edges.get(name) ?? []).includes(name);
|
|
68
|
+
if (component.length > 1 || selfEdge) cycles.push(component.sort());
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
for (const name of names) if (!index.has(name)) visit(name);
|
|
73
|
+
return cycles.sort((a, b) => a[0]!.localeCompare(b[0]!));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The dependency graph of the workspace packages
|
|
78
|
+
*/
|
|
79
|
+
export async function libGraph(input: LibGraphInput, ctx: ProcedureContext): Promise<LibGraphOutput> {
|
|
80
|
+
const root = resolveWorkspaceRoot(input.rootPath);
|
|
81
|
+
const dir = packagesDir(root);
|
|
82
|
+
const warnings: LibGraphOutput["warnings"] = [];
|
|
83
|
+
const listing = await ctx.client.call<{ path: string }, FsReaddirOutput>(["fs", "readdir"], { path: dir });
|
|
84
|
+
|
|
85
|
+
const packages: Array<{ folder: string; manifest: PackageJson }> = [];
|
|
86
|
+
for (const entry of listing.entries.filter((item) => item.type === "directory").sort((a, b) => a.name.localeCompare(b.name))) {
|
|
87
|
+
const path = join(dir, entry.name, "package.json");
|
|
88
|
+
try {
|
|
89
|
+
const { data } = await ctx.client.call<{ path: string }, { data: unknown }>(["fs", "read.json"], { path });
|
|
90
|
+
const manifest = data as PackageJson;
|
|
91
|
+
if (typeof manifest.name !== "string" || manifest.name.length === 0) {
|
|
92
|
+
warnings.push({ path, issue: "package.json has no name" });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
packages.push({ folder: entry.name, manifest });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
warnings.push({ path, issue: `Failed to read package.json: ${error instanceof Error ? error.message : String(error)}` });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const names = new Set(packages.map((pkg) => pkg.manifest.name as string));
|
|
102
|
+
const nodes: LibGraphNode[] = [];
|
|
103
|
+
const edges: LibGraphEdge[] = [];
|
|
104
|
+
const adjacency = new Map<string, string[]>();
|
|
105
|
+
for (const { folder, manifest } of packages) {
|
|
106
|
+
const name = manifest.name as string;
|
|
107
|
+
const node: LibGraphNode = { name, folder };
|
|
108
|
+
if (typeof manifest.version === "string") node.version = manifest.version;
|
|
109
|
+
if (typeof manifest.private === "boolean") node.private = manifest.private;
|
|
110
|
+
nodes.push(node);
|
|
111
|
+
const targets = new Set<string>();
|
|
112
|
+
for (const kind of KINDS) {
|
|
113
|
+
for (const [dependency, spec] of Object.entries(manifest[kind] ?? {})) {
|
|
114
|
+
if (typeof spec !== "string" || !spec.startsWith("workspace:")) continue;
|
|
115
|
+
if (!names.has(dependency)) {
|
|
116
|
+
warnings.push({ path: join(dir, folder, "package.json"), issue: `${dependency} (${spec}) is not a package of the workspace` });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
edges.push({ from: name, to: dependency, kind, spec });
|
|
120
|
+
targets.add(dependency);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
adjacency.set(name, [...targets].sort());
|
|
124
|
+
}
|
|
125
|
+
nodes.sort((a, b) => a.name.localeCompare(b.name));
|
|
126
|
+
|
|
127
|
+
const cycles = findCycles(nodes.map((node) => node.name), adjacency);
|
|
128
|
+
const output: LibGraphOutput = { root, nodes, edges, acyclic: cycles.length === 0, cycles, warnings };
|
|
129
|
+
if (cycles.length === 0) {
|
|
130
|
+
const dagNodes = new Map<string, DAGNode>(nodes.map((node) => [node.name, { id: node.name, dependencies: adjacency.get(node.name) ?? [] }]));
|
|
131
|
+
output.levels = buildLeveledDAG(dagNodes).levels.map((level) => level.map((node) => node.id).sort());
|
|
132
|
+
}
|
|
133
|
+
return output;
|
|
134
|
+
}
|