process-graph 1.0.5 → 1.1.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.
Files changed (58) hide show
  1. package/README.md +85 -17
  2. package/dist/bin.d.ts +1 -0
  3. package/dist/bin.js +92 -0
  4. package/dist/cli.d.ts +512 -0
  5. package/dist/cli.js +3 -0
  6. package/dist/control-aDk9560d.js +294 -0
  7. package/dist/detail-panel-B1ZmMuJT.js +341 -0
  8. package/dist/dist-BpCBmnMl.js +582 -0
  9. package/dist/dist-HLlW8vgT.js +1388 -0
  10. package/dist/dist-IjrgWhHQ.js +3 -0
  11. package/dist/errors-BZe5WzCn.js +19 -0
  12. package/dist/exit-codes-0ultCqdS.js +23 -0
  13. package/dist/graphql-C1j5wQFz.d.ts +631 -0
  14. package/dist/index-CCfe0csl.d.ts +353 -0
  15. package/dist/index-CmZOswkx.d.ts +512 -0
  16. package/dist/index-CoA6vXqe.d.ts +404 -0
  17. package/dist/index-CptUHq6F.d.ts +58 -0
  18. package/dist/index-CrM5qWUA.d.ts +110 -0
  19. package/dist/index-DhbvDgK4.d.ts +1582 -0
  20. package/dist/index-DricKcyl.d.ts +421 -0
  21. package/dist/index.d.ts +111 -4
  22. package/dist/index.js +929 -5
  23. package/dist/layout-CCM-KBdp.js +307 -0
  24. package/dist/layout.d.ts +8 -0
  25. package/dist/layout.js +2 -0
  26. package/dist/node-AchI1T-K.js +40 -0
  27. package/dist/open-CyRXJ4bt.js +29 -0
  28. package/dist/parse-CuipC_2K.js +41 -0
  29. package/dist/queries-CCexJAE2.js +2202 -0
  30. package/dist/react-flow/style.css +658 -0
  31. package/dist/react-flow.d.ts +173 -0
  32. package/dist/react-flow.js +450 -0
  33. package/dist/react.d.ts +2 -0
  34. package/dist/react.js +107 -0
  35. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  36. package/dist/router-D4gtTlXm.js +188 -0
  37. package/dist/schema-CVnS6HiX.js +234 -0
  38. package/dist/selection-BW_xXWOy.js +314 -0
  39. package/dist/source/github/node.d.ts +16 -0
  40. package/dist/source/github/node.js +2 -0
  41. package/dist/source/github.d.ts +49 -0
  42. package/dist/source/github.js +201 -0
  43. package/dist/source-DRDpEA8Q.js +1316 -0
  44. package/dist/status-Bm1CGu9C.js +11 -0
  45. package/dist/store/node.d.ts +24 -0
  46. package/dist/store/node.js +2 -0
  47. package/dist/store/wasm/worker.d.ts +16 -0
  48. package/dist/store/wasm/worker.js +98 -0
  49. package/dist/store/wasm.d.ts +9 -0
  50. package/dist/store/wasm.js +11 -0
  51. package/dist/store-BcR70CaO.js +1287 -0
  52. package/dist/store.d.ts +1328 -0
  53. package/dist/store.js +238 -0
  54. package/dist/ui/style.css +351 -0
  55. package/dist/ui.d.ts +235 -0
  56. package/dist/ui.js +2 -0
  57. package/dist/validate-DF3mQZww.js +125 -0
  58. package/package.json +148 -13
@@ -0,0 +1,307 @@
1
+ import ELK from "elkjs/lib/elk.bundled.js";
2
+ //#region ../../core/graph/layout/dist/elk-engine.js
3
+ /**
4
+ * Fixes ELK's randomised tie-breaking, so the same graph always yields the same boxes. ELK's own default is the same value; it is set explicitly so a change of default cannot make output depend on the library version.
5
+ */
6
+ const RANDOM_SEED = "1";
7
+ const elkDirection = {
8
+ right: "RIGHT",
9
+ down: "DOWN",
10
+ left: "LEFT",
11
+ up: "UP"
12
+ };
13
+ const toElkNode = (node, groupPadding) => {
14
+ if (node.children === void 0) return {
15
+ id: node.id,
16
+ width: node.width,
17
+ height: node.height
18
+ };
19
+ const layoutOptions = {
20
+ "elk.padding": `[top=${groupPadding},left=${groupPadding},bottom=${groupPadding},right=${groupPadding}]`,
21
+ "elk.nodeSize.constraints": "MINIMUM_SIZE",
22
+ "elk.nodeSize.minimum": `(${node.width},${node.height})`
23
+ };
24
+ return {
25
+ id: node.id,
26
+ layoutOptions,
27
+ children: node.children.map((child) => toElkNode(child, groupPadding))
28
+ };
29
+ };
30
+ /** Flattens ELK's parent-relative coordinates into absolute boxes, outermost nodes first. */
31
+ const flatten = (root) => {
32
+ const boxes = [];
33
+ const stack = [];
34
+ for (const child of root.children ?? []) stack.push({
35
+ node: child,
36
+ x: 0,
37
+ y: 0
38
+ });
39
+ for (let next = stack.pop(); next !== void 0; next = stack.pop()) {
40
+ const { node, x: originX, y: originY } = next;
41
+ const x = originX + (node.x ?? 0);
42
+ const y = originY + (node.y ?? 0);
43
+ boxes.push({
44
+ id: node.id,
45
+ x,
46
+ y,
47
+ width: node.width ?? 0,
48
+ height: node.height ?? 0
49
+ });
50
+ for (const child of node.children ?? []) stack.push({
51
+ node: child,
52
+ x,
53
+ y
54
+ });
55
+ }
56
+ return boxes;
57
+ };
58
+ /**
59
+ * The default engine: elkjs's layered algorithm, run in the calling context from the bundled build so it needs neither a Worker nor Node-only modules. Groups are laid out together with their children (`INCLUDE_CHILDREN`), so an edge between lanes takes part in layer assignment.
60
+ */
61
+ const createElkEngine = () => {
62
+ const elk = new ELK();
63
+ return { async arrange(graph) {
64
+ const edges = graph.edges.map((edge) => ({
65
+ id: edge.id,
66
+ sources: [edge.source],
67
+ targets: [edge.target]
68
+ }));
69
+ const root = {
70
+ id: "root",
71
+ layoutOptions: {
72
+ "elk.algorithm": "layered",
73
+ "elk.direction": elkDirection[graph.direction],
74
+ "elk.spacing.nodeNode": String(graph.nodeGap),
75
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(graph.layerGap),
76
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
77
+ "elk.randomSeed": RANDOM_SEED
78
+ },
79
+ children: graph.nodes.map((node) => toElkNode(node, graph.groupPadding)),
80
+ edges
81
+ };
82
+ return flatten(await elk.layout(root));
83
+ } };
84
+ };
85
+ //#endregion
86
+ //#region ../../core/graph/layout/dist/metrics.js
87
+ /**
88
+ * The unit every dimension below is a multiple of, so nodes of different shapes and lanes align on one grid and a renderer that snaps to a grid snaps to the same points.
89
+ */
90
+ const GRID = 8;
91
+ /** A process step or state: wide enough for a short label on one line. */
92
+ const PROCESS_UNITS = {
93
+ width: 20,
94
+ height: 8
95
+ };
96
+ /** A start or end terminator: a rounded box smaller than a step, so it reads as a boundary. */
97
+ const TERMINATOR_UNITS = {
98
+ width: 12,
99
+ height: 6
100
+ };
101
+ /** A decision diamond: taller than a step, because a diamond has less usable width than the box that encloses it. */
102
+ const DECISION_UNITS = {
103
+ width: 16,
104
+ height: 12
105
+ };
106
+ /** The initial and final pseudo-states of a state machine: a dot, as in the notation. */
107
+ const PSEUDO_STATE_UNITS = {
108
+ width: 4,
109
+ height: 4
110
+ };
111
+ /** The least a lane may measure, so a lane with no nodes is still visible. */
112
+ const LANE_MINIMUM_UNITS = {
113
+ width: 24,
114
+ height: 12
115
+ };
116
+ const sized = (units) => ({
117
+ width: units.width * GRID,
118
+ height: units.height * GRID
119
+ });
120
+ const PROCESS_SIZE = sized(PROCESS_UNITS);
121
+ const TERMINATOR_SIZE = sized(TERMINATOR_UNITS);
122
+ const DECISION_SIZE = sized(DECISION_UNITS);
123
+ const PSEUDO_STATE_SIZE = sized(PSEUDO_STATE_UNITS);
124
+ const LANE_MINIMUM_SIZE = sized(LANE_MINIMUM_UNITS);
125
+ /**
126
+ * The bar across the flow: a fork or join is drawn perpendicular to the edges it gathers or splits, so it is tall when edges run sideways and wide when they run vertically.
127
+ */
128
+ const barSize = (direction) => {
129
+ const thickness = 8;
130
+ const length = 96;
131
+ return direction === "right" || direction === "left" ? {
132
+ width: thickness,
133
+ height: length
134
+ } : {
135
+ width: length,
136
+ height: thickness
137
+ };
138
+ };
139
+ //#endregion
140
+ //#region ../../core/graph/layout/dist/layout.js
141
+ const flowNodeSizes = {
142
+ process: PROCESS_SIZE,
143
+ terminator: TERMINATOR_SIZE,
144
+ decision: DECISION_SIZE
145
+ };
146
+ const flowNodeSize = (shape, direction) => shape === "bar" ? barSize(direction) : flowNodeSizes[shape];
147
+ const stateSize = (role) => role === "state" ? PROCESS_SIZE : PSEUDO_STATE_SIZE;
148
+ const prepare = (view, direction) => {
149
+ if ("states" in view) return {
150
+ notation: "stateMachine",
151
+ elements: view.states.map((state) => ({
152
+ id: state.id,
153
+ size: stateSize(state.role)
154
+ })),
155
+ edges: view.transitions.map((transition) => ({
156
+ from: transition.source,
157
+ to: transition.target
158
+ })),
159
+ lanes: []
160
+ };
161
+ const elements = view.nodes.map((node) => ({
162
+ id: node.id,
163
+ size: flowNodeSize(node.shape, direction)
164
+ }));
165
+ if ("lanes" in view) return {
166
+ notation: "swimlane",
167
+ elements,
168
+ edges: view.edges,
169
+ lanes: view.lanes
170
+ };
171
+ return {
172
+ notation: "flowchart",
173
+ elements,
174
+ edges: view.edges,
175
+ lanes: []
176
+ };
177
+ };
178
+ /**
179
+ * Settles by throwing the signal's own reason once it aborts, and never settles if `stop` aborts first, which also removes the listener.
180
+ */
181
+ const whenAborted = async (signal, stop) => {
182
+ await new Promise((resolve) => {
183
+ signal.addEventListener("abort", () => {
184
+ resolve();
185
+ }, {
186
+ once: true,
187
+ signal: stop
188
+ });
189
+ });
190
+ signal.throwIfAborted();
191
+ throw new Error("The signal aborted without a reason");
192
+ };
193
+ /**
194
+ * Places a projected view with a layered layout and returns where each element goes, as the model's `views` shape.
195
+ *
196
+ * Pure with respect to the model: it reads only the view, never mutates it, and the model stores the result apart from its semantics, so no projection reads a coordinate. The same view and options give the same positions with the default engine. Swimlane lanes are groups, and every node lies inside its lane's bounds.
197
+ * @param view - A flowchart, swimlane or state machine from the projection package.
198
+ * @param options - Direction, spacing, abort signal and engine.
199
+ * @returns Positions keyed by notation and element id, element sizes and lane bounds.
200
+ * @throws The signal's reason when `options.signal` aborts before the layout completes.
201
+ */
202
+ const layout = async (view, options = {}) => {
203
+ const { direction = "right", spacing, signal, engine = createElkEngine() } = options;
204
+ signal?.throwIfAborted();
205
+ const prepared = prepare(view, direction);
206
+ const elementIds = /* @__PURE__ */ new Map();
207
+ const leaves = /* @__PURE__ */ new Map();
208
+ prepared.elements.forEach((element, index) => {
209
+ const id = `n${index}`;
210
+ elementIds.set(element.id, id);
211
+ leaves.set(id, element);
212
+ });
213
+ const leafNode = (id, size) => ({
214
+ id,
215
+ ...size
216
+ });
217
+ const nodeFor = (element) => {
218
+ const id = elementIds.get(element);
219
+ const leaf = id === void 0 ? void 0 : leaves.get(id);
220
+ return id === void 0 || leaf === void 0 ? void 0 : leafNode(id, leaf.size);
221
+ };
222
+ const placedInLane = /* @__PURE__ */ new Set();
223
+ const laneIds = [];
224
+ const nodes = [];
225
+ prepared.lanes.forEach((lane, index) => {
226
+ const id = `l${index}`;
227
+ laneIds.push(id);
228
+ const children = [];
229
+ for (const element of lane.nodes) {
230
+ const child = nodeFor(element);
231
+ if (child !== void 0) {
232
+ placedInLane.add(element);
233
+ children.push(child);
234
+ }
235
+ }
236
+ nodes.push({
237
+ id,
238
+ ...LANE_MINIMUM_SIZE,
239
+ children
240
+ });
241
+ });
242
+ for (const element of prepared.elements) if (!placedInLane.has(element.id)) {
243
+ const node = nodeFor(element.id);
244
+ if (node !== void 0) nodes.push(node);
245
+ }
246
+ const edges = [];
247
+ prepared.edges.forEach((edge, index) => {
248
+ const source = elementIds.get(edge.from);
249
+ const target = elementIds.get(edge.to);
250
+ if (source !== void 0 && target !== void 0) edges.push({
251
+ id: `e${index}`,
252
+ source,
253
+ target
254
+ });
255
+ });
256
+ const request = engine.arrange({
257
+ direction,
258
+ nodeGap: spacing?.node ?? 32,
259
+ layerGap: spacing?.layer ?? 64,
260
+ groupPadding: 32,
261
+ nodes,
262
+ edges
263
+ }, signal);
264
+ let boxes;
265
+ if (signal === void 0) boxes = await request;
266
+ else {
267
+ const stop = new AbortController();
268
+ try {
269
+ boxes = await Promise.race([request, whenAborted(signal, stop.signal)]);
270
+ } finally {
271
+ stop.abort();
272
+ }
273
+ }
274
+ const byId = new Map(boxes.map((box) => [box.id, box]));
275
+ const positions = {};
276
+ const sizes = {};
277
+ for (const [id, element] of leaves) {
278
+ const box = byId.get(id);
279
+ if (box === void 0) throw new Error(`The layout engine returned no box for element "${element.id}"`);
280
+ positions[element.id] = {
281
+ x: box.x,
282
+ y: box.y
283
+ };
284
+ sizes[element.id] = {
285
+ width: box.width,
286
+ height: box.height
287
+ };
288
+ }
289
+ const lanes = prepared.lanes.map((lane, index) => {
290
+ const box = byId.get(laneIds[index] ?? "");
291
+ if (box === void 0) throw new Error(`The layout engine returned no box for lane "${lane.participant}"`);
292
+ return {
293
+ participant: lane.participant,
294
+ x: box.x,
295
+ y: box.y,
296
+ width: box.width,
297
+ height: box.height
298
+ };
299
+ });
300
+ return {
301
+ views: { [prepared.notation]: positions },
302
+ sizes,
303
+ lanes
304
+ };
305
+ };
306
+ //#endregion
307
+ export { createElkEngine as n, layout as t };
@@ -0,0 +1,8 @@
1
+ import { a as layout, c as EngineBox, d as EngineGroup, f as EngineLeaf, i as LayoutView, l as EngineEdge, m as LayoutEngine, n as LayoutOptions, o as Size, p as EngineNode, r as LayoutResult, s as Direction, t as LaneBounds, u as EngineGraph } from "./index-CrM5qWUA.js";
2
+ //#region ../../core/graph/layout/dist/elk-engine.d.ts
3
+ /**
4
+ * The default engine: elkjs's layered algorithm, run in the calling context from the bundled build so it needs neither a Worker nor Node-only modules. Groups are laid out together with their children (`INCLUDE_CHILDREN`), so an edge between lanes takes part in layer assignment.
5
+ */
6
+ export declare const createElkEngine: () => LayoutEngine;
7
+ //#endregion
8
+ export { type Direction, type EngineBox, type EngineEdge, type EngineGraph, type EngineGroup, type EngineLeaf, type EngineNode, type LaneBounds, type LayoutEngine, type LayoutOptions, type LayoutResult, type LayoutView, type Size, layout };
package/dist/layout.js ADDED
@@ -0,0 +1,2 @@
1
+ import { n as createElkEngine, t as layout } from "./layout-CCM-KBdp.js";
2
+ export { createElkEngine, layout };
@@ -0,0 +1,40 @@
1
+ import { t as GraphSourceError } from "./errors-BZe5WzCn.js";
2
+ import { execFile } from "node:child_process";
3
+ //#region ../../adapters/graph/source-github-issues/dist/node.js
4
+ /** Runs `gh auth token` and resolves with its standard output. */
5
+ const ghAuthToken = async () => new Promise((resolve, reject) => {
6
+ execFile("gh", ["auth", "token"], (error, stdout) => {
7
+ if (error === null) resolve(stdout);
8
+ else reject(new Error("gh auth token failed", { cause: error }));
9
+ });
10
+ });
11
+ /**
12
+ * A token port for Node that uses `GITHUB_TOKEN` when it is set and not empty, and otherwise the token the GitHub CLI holds (`gh auth token`), asked for once and reused. The same token serves every owner. The token is never logged, and an error from the CLI is reported without its output.
13
+ * @param options - The environment and the CLI runner, for tests.
14
+ * @returns The token port.
15
+ */
16
+ const githubTokenFromEnvironment = (options = {}) => {
17
+ const env = options.env ?? process.env;
18
+ const runGh = options.runGh ?? ghAuthToken;
19
+ const fromEnvironment = env.GITHUB_TOKEN;
20
+ let fromCli;
21
+ return async () => {
22
+ if (fromEnvironment !== void 0 && fromEnvironment !== "") return fromEnvironment;
23
+ fromCli ??= runGh().then((output) => {
24
+ const token = output.trim();
25
+ if (token === "") throw new GraphSourceError({
26
+ kind: "unauthorised",
27
+ message: "gh auth token printed no token; run gh auth login"
28
+ });
29
+ return token;
30
+ }, (error) => {
31
+ throw new GraphSourceError({
32
+ kind: "unauthorised",
33
+ message: "no GitHub token: GITHUB_TOKEN is not set and gh auth token failed; set GITHUB_TOKEN or run gh auth login"
34
+ }, { cause: error });
35
+ });
36
+ return fromCli;
37
+ };
38
+ };
39
+ //#endregion
40
+ export { githubTokenFromEnvironment as t };
@@ -0,0 +1,29 @@
1
+ import { t as createSqliteGraphStore } from "./store-BcR70CaO.js";
2
+ import { sql } from "drizzle-orm";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { drizzle } from "drizzle-orm/node-sqlite";
5
+ //#region ../../adapters/graph/sqlite-node/dist/open.js
6
+ /** The path `node:sqlite` reads as a private database in memory rather than a file. */
7
+ const inMemory = ":memory:";
8
+ /**
9
+ * Opens a graph store on a SQLite database file, creating the file when it does not exist. The schema is migrated on the store's first operation.
10
+ *
11
+ * A file database is switched to write-ahead logging, so readers in other processes (a command line beside a server) are not blocked by a writer. Each process's change feed sees only its own writes.
12
+ * @param path - The database file, or `":memory:"` for a private database that lives as long as the store.
13
+ * @param options - `node:sqlite` options passed through unchanged, such as `timeout` for how long a write waits for another process's lock.
14
+ * @returns The store, its database and a way to close it.
15
+ */
16
+ const openNodeGraphStore = (path, options = {}) => {
17
+ const client = new DatabaseSync(path, options);
18
+ const db = drizzle({ client });
19
+ if (path !== inMemory) db.run(sql`PRAGMA journal_mode = WAL`);
20
+ return {
21
+ store: createSqliteGraphStore({ db }),
22
+ db,
23
+ close: () => {
24
+ client.close();
25
+ }
26
+ };
27
+ };
28
+ //#endregion
29
+ export { openNodeGraphStore as t };
@@ -0,0 +1,41 @@
1
+ import { o as toPointer, t as modelSchema } from "./schema-CVnS6HiX.js";
2
+ import { t as validate } from "./validate-DF3mQZww.js";
3
+ //#region ../../core/graph/schema/dist/parse.js
4
+ /** Thrown by `parseModel` when the input is not a valid model. */
5
+ var ModelParseError = class extends Error {
6
+ /** Every problem found, in the order the schema and then `validate` reported them. Never empty. */
7
+ issues;
8
+ /**
9
+ * @param issues - The problems found. Must not be empty.
10
+ */
11
+ constructor(issues) {
12
+ super(`Invalid model: ${issues.map((issue) => issue.source === "schema" ? `${issue.pointer === "" ? "/" : issue.pointer}: ${issue.message}` : issue.message).join("; ")}`);
13
+ this.name = "ModelParseError";
14
+ this.issues = issues;
15
+ }
16
+ };
17
+ /**
18
+ * Loads a model from untrusted input, such as parsed JSON.
19
+ *
20
+ * The input is checked against the open schema first, so every shape problem is reported with the JSON pointer of the offending value. Only a well-shaped model is then passed to `validate`, whose issues are surfaced the same way.
21
+ * @param input - The value to load.
22
+ * @returns The validated model, with identifiers as plain strings.
23
+ * @throws ModelParseError when the input is not a well-shaped model or fails `validate`.
24
+ */
25
+ const parseModel = (input) => {
26
+ const parsed = modelSchema.safeParse(input);
27
+ if (!parsed.success) throw new ModelParseError(parsed.error.issues.map((issue) => ({
28
+ source: "schema",
29
+ pointer: toPointer(issue.path),
30
+ message: issue.message
31
+ })));
32
+ const issues = validate(parsed.data);
33
+ if (issues.length > 0) throw new ModelParseError(issues.map((issue) => ({
34
+ source: "validate",
35
+ code: issue.code,
36
+ message: issue.message
37
+ })));
38
+ return parsed.data;
39
+ };
40
+ //#endregion
41
+ export { parseModel as n, ModelParseError as t };