@alpacakit/plan-graph 0.1.0-beta.19

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +2 -0
  6. package/dist/plan-graph/ids.d.ts +9 -0
  7. package/dist/plan-graph/ids.d.ts.map +1 -0
  8. package/dist/plan-graph/ids.js +22 -0
  9. package/dist/plan-graph/index.d.ts +10 -0
  10. package/dist/plan-graph/index.d.ts.map +1 -0
  11. package/dist/plan-graph/index.js +9 -0
  12. package/dist/plan-graph/model.d.ts +59 -0
  13. package/dist/plan-graph/model.d.ts.map +1 -0
  14. package/dist/plan-graph/model.js +1 -0
  15. package/dist/plan-graph/ordering.d.ts +11 -0
  16. package/dist/plan-graph/ordering.d.ts.map +1 -0
  17. package/dist/plan-graph/ordering.js +63 -0
  18. package/dist/plan-graph/patch.d.ts +73 -0
  19. package/dist/plan-graph/patch.d.ts.map +1 -0
  20. package/dist/plan-graph/patch.js +138 -0
  21. package/dist/plan-graph/projection.d.ts +9 -0
  22. package/dist/plan-graph/projection.d.ts.map +1 -0
  23. package/dist/plan-graph/projection.js +1 -0
  24. package/dist/plan-graph/readiness.d.ts +12 -0
  25. package/dist/plan-graph/readiness.d.ts.map +1 -0
  26. package/dist/plan-graph/readiness.js +26 -0
  27. package/dist/plan-graph/schema.d.ts +29 -0
  28. package/dist/plan-graph/schema.d.ts.map +1 -0
  29. package/dist/plan-graph/schema.js +25 -0
  30. package/dist/plan-graph/validator.d.ts +27 -0
  31. package/dist/plan-graph/validator.d.ts.map +1 -0
  32. package/dist/plan-graph/validator.js +168 -0
  33. package/dist/plan-graph/values.d.ts +44 -0
  34. package/dist/plan-graph/values.d.ts.map +1 -0
  35. package/dist/plan-graph/values.js +36 -0
  36. package/dist/render/index.d.ts +2 -0
  37. package/dist/render/index.d.ts.map +1 -0
  38. package/dist/render/index.js +1 -0
  39. package/dist/render/mermaid-flowchart.d.ts +43 -0
  40. package/dist/render/mermaid-flowchart.d.ts.map +1 -0
  41. package/dist/render/mermaid-flowchart.js +75 -0
  42. package/package.json +37 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Masahiro Tonomura (codemafia0000)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # @alpacakit/plan-graph
2
+
3
+ Typed DAG kernel for plan-shaped graphs, part of the AlpacaLoop workspace.
4
+ It owns the plan-graph model (nodes, edges, revisions), validation rules
5
+ (unique ids, known endpoints, no self-edges, acyclicity), patch commands
6
+ with an immutable reducer, deterministic topological ordering, readiness
7
+ computation, and zod schemas for the whole vocabulary.
8
+
9
+ The `alpacaloop` control plane consumes this package as thin projections
10
+ over its own workflow state; the package itself is provider- and
11
+ runtime-neutral. It depends on `@alpacakit/core` for the shared primitive
12
+ vocabulary and is published together with it and the root package.
13
+
14
+ Main exports: `PlanGraphDefinition` and the node/edge model types,
15
+ `validatePlanGraph` / `createPlanGraphValidator`, the `PlanGraphPatch`
16
+ union with its reducer, `topologicallyOrderPlanGraphNodes`,
17
+ `selectReadyPlanGraphNodes`, and the `PLAN_GRAPH_*` value maps.
@@ -0,0 +1,3 @@
1
+ export * from "./plan-graph/index.js";
2
+ export * from "./render/index.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./plan-graph/index.js";
2
+ export * from "./render/index.js";
@@ -0,0 +1,9 @@
1
+ import type { PlanGraphEdgeId, PlanGraphId, PlanGraphNodeId, PlanGraphPatchId, PlanGraphRevision } from "./model.js";
2
+ export declare function makePlanGraphId(value: string): PlanGraphId;
3
+ export declare function makePlanGraphNodeId(value: string): PlanGraphNodeId;
4
+ export declare function makePlanGraphEdgeId(value: string): PlanGraphEdgeId;
5
+ export declare function makePlanGraphPatchId(value: string): PlanGraphPatchId;
6
+ export declare function makePlanGraphRevision(value: string): PlanGraphRevision;
7
+ export declare function makeJoinedPlanGraphNodeId(...parts: readonly string[]): PlanGraphNodeId;
8
+ export declare function makeJoinedPlanGraphEdgeId(...parts: readonly string[]): PlanGraphEdgeId;
9
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/plan-graph/ids.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAE1D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAElE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAElE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAEpE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAEtE;AAED,wBAAgB,yBAAyB,CACvC,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAC1B,eAAe,CAEjB;AAED,wBAAgB,yBAAyB,CACvC,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAC1B,eAAe,CAEjB"}
@@ -0,0 +1,22 @@
1
+ import { makeBrandedId, makeJoinedBrandedId } from "@alpacakit/core";
2
+ export function makePlanGraphId(value) {
3
+ return makeBrandedId(value);
4
+ }
5
+ export function makePlanGraphNodeId(value) {
6
+ return makeBrandedId(value);
7
+ }
8
+ export function makePlanGraphEdgeId(value) {
9
+ return makeBrandedId(value);
10
+ }
11
+ export function makePlanGraphPatchId(value) {
12
+ return makeBrandedId(value);
13
+ }
14
+ export function makePlanGraphRevision(value) {
15
+ return makeBrandedId(value);
16
+ }
17
+ export function makeJoinedPlanGraphNodeId(...parts) {
18
+ return makeJoinedBrandedId(...parts);
19
+ }
20
+ export function makeJoinedPlanGraphEdgeId(...parts) {
21
+ return makeJoinedBrandedId(...parts);
22
+ }
@@ -0,0 +1,10 @@
1
+ export * from "./ids.js";
2
+ export * from "./model.js";
3
+ export * from "./ordering.js";
4
+ export * from "./patch.js";
5
+ export * from "./projection.js";
6
+ export * from "./readiness.js";
7
+ export * from "./schema.js";
8
+ export * from "./validator.js";
9
+ export * from "./values.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plan-graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,9 @@
1
+ export * from "./ids.js";
2
+ export * from "./model.js";
3
+ export * from "./ordering.js";
4
+ export * from "./patch.js";
5
+ export * from "./projection.js";
6
+ export * from "./readiness.js";
7
+ export * from "./schema.js";
8
+ export * from "./validator.js";
9
+ export * from "./values.js";
@@ -0,0 +1,59 @@
1
+ import type { Brand, DefinitionBase, Metadata } from "@alpacakit/core";
2
+ import type { PLAN_GRAPH_VALIDATION_RESULT_KIND, PlanGraphNodeOriginKind } from "./values.js";
3
+ export type { DefinitionBase, Metadata };
4
+ export type PlanGraphRevision = Brand<string, "PlanGraphRevision">;
5
+ export interface PlanGraphDefinition<Id, Kind extends string, TMetadata, Node, Edge> extends DefinitionBase<Id, Kind, TMetadata> {
6
+ readonly revision: PlanGraphRevision;
7
+ readonly nodes: readonly Node[];
8
+ readonly edges: readonly Edge[];
9
+ }
10
+ export type PlanGraphId = Brand<string, "PlanGraphId">;
11
+ export type PlanGraphNodeId = Brand<string, "PlanGraphNodeId">;
12
+ export type PlanGraphEdgeId = Brand<string, "PlanGraphEdgeId">;
13
+ export type PlanGraphPatchId = Brand<string, "PlanGraphPatchId">;
14
+ export type PlanGraphValidationIssueId = Brand<string, "PlanGraphValidationIssueId">;
15
+ export type PlanGraphNodeOrigin = {
16
+ readonly kind: PlanGraphNodeOriginKind;
17
+ readonly sourceId: string | null;
18
+ };
19
+ export type PlanNodeBase<Id, Kind extends string, Payload, State> = {
20
+ readonly id: Id;
21
+ readonly kind: Kind;
22
+ readonly payload: Payload;
23
+ readonly state: State;
24
+ readonly origin: PlanGraphNodeOrigin;
25
+ };
26
+ export type PlanEdgeBase<Id, NodeId, Kind extends string, Condition> = {
27
+ readonly id: Id;
28
+ readonly fromNodeId: NodeId;
29
+ readonly toNodeId: NodeId;
30
+ readonly kind: Kind;
31
+ readonly condition: Condition;
32
+ };
33
+ export type PlanGraphNodeRef<NodeId> = {
34
+ readonly id: NodeId;
35
+ };
36
+ export type PlanGraphEdgeRef<EdgeId, NodeId> = {
37
+ readonly id: EdgeId;
38
+ readonly fromNodeId: NodeId;
39
+ readonly toNodeId: NodeId;
40
+ };
41
+ export type PlanGraphValidationIssueLocation<NodeId, EdgeId> = {
42
+ readonly nodeId: NodeId | null;
43
+ readonly edgeId: EdgeId | null;
44
+ readonly nodeIds: readonly NodeId[];
45
+ readonly edgeIds: readonly EdgeId[];
46
+ };
47
+ export type PlanGraphValidationIssue<NodeId, EdgeId, Kind extends string = string, Details extends Metadata = Metadata> = {
48
+ readonly kind: Kind;
49
+ readonly message: string;
50
+ readonly location: PlanGraphValidationIssueLocation<NodeId, EdgeId>;
51
+ readonly details: Details;
52
+ };
53
+ export type PlanGraphValidationResult<NodeId, EdgeId, Issue extends PlanGraphValidationIssue<NodeId, EdgeId> = PlanGraphValidationIssue<NodeId, EdgeId>> = {
54
+ readonly kind: typeof PLAN_GRAPH_VALIDATION_RESULT_KIND.valid;
55
+ } | {
56
+ readonly kind: typeof PLAN_GRAPH_VALIDATION_RESULT_KIND.invalid;
57
+ readonly issues: readonly Issue[];
58
+ };
59
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/plan-graph/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { PlanGraphDefinition, PlanGraphEdgeRef, PlanGraphNodeRef } from "./model.js";
2
+ import { PLAN_GRAPH_ORDERING_RESULT_KIND } from "./values.js";
3
+ export type PlanGraphOrderingResult<NodeId, Node> = {
4
+ readonly kind: typeof PLAN_GRAPH_ORDERING_RESULT_KIND.ordered;
5
+ readonly nodes: readonly Node[];
6
+ } | {
7
+ readonly kind: typeof PLAN_GRAPH_ORDERING_RESULT_KIND.cycle;
8
+ readonly nodeIds: readonly NodeId[];
9
+ };
10
+ export declare function topologicallyOrderPlanGraphNodes<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>>(graph: PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>): PlanGraphOrderingResult<NodeId, Node>;
11
+ //# sourceMappingURL=ordering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ordering.d.ts","sourceRoot":"","sources":["../../src/plan-graph/ordering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAE9D,MAAM,MAAM,uBAAuB,CAAC,MAAM,EAAE,IAAI,IAC5C;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,+BAA+B,CAAC,OAAO,CAAC;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACjC,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,+BAA+B,CAAC,KAAK,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC,CAAC;AAEN,wBAAgB,gCAAgC,CAC9C,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACrC,IAAI,SAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAE7C,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,GAC/D,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,CA2CvC"}
@@ -0,0 +1,63 @@
1
+ import { PLAN_GRAPH_ORDERING_RESULT_KIND } from "./values.js";
2
+ export function topologicallyOrderPlanGraphNodes(graph) {
3
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
4
+ const pendingDependencyIdsById = buildPendingDependencyMap(graph);
5
+ const dependentIdsById = buildDependentMap(graph);
6
+ const originalIndexById = new Map(graph.nodes.map((node, index) => [node.id, index]));
7
+ const readyIds = graph.nodes
8
+ .map((node) => node.id)
9
+ .filter((nodeId) => (pendingDependencyIdsById.get(nodeId)?.size ?? 0) === 0);
10
+ const orderedNodes = [];
11
+ const orderedIds = new Set();
12
+ while (readyIds.length > 0) {
13
+ sortNodeIdsByOriginalIndex(readyIds, originalIndexById);
14
+ const nodeId = readyIds.shift();
15
+ const node = nodeId === undefined ? undefined : nodeById.get(nodeId);
16
+ if (nodeId === undefined || node === undefined || orderedIds.has(nodeId)) {
17
+ continue;
18
+ }
19
+ orderedNodes.push(node);
20
+ orderedIds.add(nodeId);
21
+ for (const dependentId of dependentIdsById.get(nodeId) ?? []) {
22
+ const pendingDependencyIds = pendingDependencyIdsById.get(dependentId);
23
+ pendingDependencyIds?.delete(nodeId);
24
+ if (pendingDependencyIds?.size === 0) {
25
+ readyIds.push(dependentId);
26
+ }
27
+ }
28
+ }
29
+ if (orderedNodes.length !== graph.nodes.length) {
30
+ return {
31
+ kind: PLAN_GRAPH_ORDERING_RESULT_KIND.cycle,
32
+ nodeIds: graph.nodes
33
+ .map((node) => node.id)
34
+ .filter((nodeId) => !orderedIds.has(nodeId)),
35
+ };
36
+ }
37
+ return { kind: PLAN_GRAPH_ORDERING_RESULT_KIND.ordered, nodes: orderedNodes };
38
+ }
39
+ function buildPendingDependencyMap(graph) {
40
+ const nodeIds = new Set(graph.nodes.map((node) => node.id));
41
+ const pendingDependencyIdsById = new Map();
42
+ for (const node of graph.nodes) {
43
+ pendingDependencyIdsById.set(node.id, new Set());
44
+ }
45
+ for (const edge of graph.edges) {
46
+ if (nodeIds.has(edge.fromNodeId) && nodeIds.has(edge.toNodeId)) {
47
+ pendingDependencyIdsById.get(edge.toNodeId)?.add(edge.fromNodeId);
48
+ }
49
+ }
50
+ return pendingDependencyIdsById;
51
+ }
52
+ function buildDependentMap(graph) {
53
+ const dependentIdsById = new Map();
54
+ for (const edge of graph.edges) {
55
+ const dependentIds = dependentIdsById.get(edge.fromNodeId) ?? [];
56
+ dependentIds.push(edge.toNodeId);
57
+ dependentIdsById.set(edge.fromNodeId, dependentIds);
58
+ }
59
+ return dependentIdsById;
60
+ }
61
+ function sortNodeIdsByOriginalIndex(nodeIds, originalIndexById) {
62
+ nodeIds.sort((left, right) => (originalIndexById.get(left) ?? 0) - (originalIndexById.get(right) ?? 0));
63
+ }
@@ -0,0 +1,73 @@
1
+ import type { PlanGraphDefinition, PlanGraphRevision, PlanGraphValidationIssue, PlanGraphValidationResult } from "./model.js";
2
+ import { PLAN_GRAPH_PATCH_KIND } from "./values.js";
3
+ export declare const EMPTY_GRAPH_PATCH_LIST: readonly never[];
4
+ type NodeWithId<NodeId> = {
5
+ readonly id: NodeId;
6
+ };
7
+ type EdgeWithId<EdgeId, NodeId> = {
8
+ readonly id: EdgeId;
9
+ readonly fromNodeId: NodeId;
10
+ readonly toNodeId: NodeId;
11
+ };
12
+ export type PlanGraphPatch<NodeId, EdgeId, Node, Edge, Reason> = AddPlanGraphNodesPatch<Node, Reason> | UpdatePlanGraphNodesPatch<Node, Reason> | RemovePlanGraphNodesPatch<NodeId, Reason> | ConnectPlanGraphEdgesPatch<Edge, Reason> | UpdatePlanGraphEdgesPatch<Edge, Reason> | DisconnectPlanGraphEdgesPatch<EdgeId, Reason>;
13
+ export type PlanGraphPatchCommand<GraphId, NodeId, EdgeId, Node, Edge, Reason> = {
14
+ readonly graphId: GraphId;
15
+ readonly baseRevision: PlanGraphRevision;
16
+ readonly nextRevision: PlanGraphRevision;
17
+ readonly patch: PlanGraphPatch<NodeId, EdgeId, Node, Edge, Reason>;
18
+ };
19
+ export type PlanGraphPatchSet<GraphId, NodeId, EdgeId, Node, Edge, Reason> = {
20
+ readonly graphId: GraphId;
21
+ readonly baseRevision: PlanGraphRevision;
22
+ readonly nextRevision: PlanGraphRevision;
23
+ readonly patches: readonly PlanGraphPatch<NodeId, EdgeId, Node, Edge, Reason>[];
24
+ };
25
+ export type AddPlanGraphNodesPatch<Node, Reason> = {
26
+ readonly kind: typeof PLAN_GRAPH_PATCH_KIND.addNodes;
27
+ readonly nodes: readonly Node[];
28
+ readonly reason: Reason;
29
+ };
30
+ export type UpdatePlanGraphNodesPatch<Node, Reason> = {
31
+ readonly kind: typeof PLAN_GRAPH_PATCH_KIND.updateNodes;
32
+ readonly nodes: readonly Node[];
33
+ readonly reason: Reason;
34
+ };
35
+ export type RemovePlanGraphNodesPatch<NodeId, Reason> = {
36
+ readonly kind: typeof PLAN_GRAPH_PATCH_KIND.removeNodes;
37
+ readonly nodeIds: readonly NodeId[];
38
+ readonly reason: Reason;
39
+ };
40
+ export type ConnectPlanGraphEdgesPatch<Edge, Reason> = {
41
+ readonly kind: typeof PLAN_GRAPH_PATCH_KIND.connectEdges;
42
+ readonly edges: readonly Edge[];
43
+ readonly reason: Reason;
44
+ };
45
+ export type UpdatePlanGraphEdgesPatch<Edge, Reason> = {
46
+ readonly kind: typeof PLAN_GRAPH_PATCH_KIND.updateEdges;
47
+ readonly edges: readonly Edge[];
48
+ readonly reason: Reason;
49
+ };
50
+ export type DisconnectPlanGraphEdgesPatch<EdgeId, Reason> = {
51
+ readonly kind: typeof PLAN_GRAPH_PATCH_KIND.disconnectEdges;
52
+ readonly edgeIds: readonly EdgeId[];
53
+ readonly reason: Reason;
54
+ };
55
+ export type PatchablePlanGraph<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends NodeWithId<NodeId>, Edge extends EdgeWithId<EdgeId, NodeId>> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>;
56
+ export declare class PlanGraphPatchError extends Error {
57
+ readonly issues: readonly unknown[];
58
+ constructor(message: string, issues?: readonly unknown[], options?: ErrorOptions);
59
+ }
60
+ export type PlanGraphPatchResultValidator<Graph, NodeId, EdgeId, Issue extends PlanGraphValidationIssue<NodeId, EdgeId>> = (graph: Graph) => PlanGraphValidationResult<NodeId, EdgeId, Issue>;
61
+ export declare function assertValidPlanGraphPatchResult<Graph, NodeId, EdgeId, Issue extends PlanGraphValidationIssue<NodeId, EdgeId>>(graph: Graph, validate: PlanGraphPatchResultValidator<Graph, NodeId, EdgeId, Issue>, subject?: string): Graph;
62
+ export interface PlanGraphPatchReducer<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends NodeWithId<NodeId>, Edge extends EdgeWithId<EdgeId, NodeId>, Reason, Graph extends PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge> = PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge>> {
63
+ readonly id: string;
64
+ reduce(input: {
65
+ readonly graph: Graph;
66
+ readonly patch: PlanGraphPatch<NodeId, EdgeId, Node, Edge, Reason>;
67
+ }): Graph | null;
68
+ }
69
+ export declare function applyPlanGraphPatch<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends NodeWithId<NodeId>, Edge extends EdgeWithId<EdgeId, NodeId>, Reason, Graph extends PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge> = PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge>>(graph: Graph, command: PlanGraphPatchCommand<GraphId, NodeId, EdgeId, Node, Edge, Reason>, reducers?: readonly PlanGraphPatchReducer<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Reason, Graph>[]): Graph;
70
+ export declare function applyPlanGraphPatches<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends NodeWithId<NodeId>, Edge extends EdgeWithId<EdgeId, NodeId>, Reason, Graph extends PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge> = PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge>>(graph: Graph, patchSet: PlanGraphPatchSet<GraphId, NodeId, EdgeId, Node, Edge, Reason>, reducers?: readonly PlanGraphPatchReducer<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Reason, Graph>[]): Graph;
71
+ export declare function createCorePlanGraphPatchReducers<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends NodeWithId<NodeId>, Edge extends EdgeWithId<EdgeId, NodeId>, Reason, Graph extends PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge> = PatchablePlanGraph<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge>>(): readonly PlanGraphPatchReducer<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Reason, Graph>[];
72
+ export {};
73
+ //# sourceMappingURL=patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../../src/plan-graph/patch.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,qBAAqB,EAEtB,MAAM,aAAa,CAAC;AAIrB,eAAO,MAAM,sBAAsB,kBAEP,CAAC;AAE7B,KAAK,UAAU,CAAC,MAAM,IAAI;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,KAAK,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,IACzD,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,GACpC,yBAAyB,CAAC,IAAI,EAAE,MAAM,CAAC,GACvC,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,0BAA0B,CAAC,IAAI,EAAE,MAAM,CAAC,GACxC,yBAAyB,CAAC,IAAI,EAAE,MAAM,CAAC,GACvC,6BAA6B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD,MAAM,MAAM,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,IAC3E;IACE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;CACpE,CAAC;AAEJ,MAAM,MAAM,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI;IAC3E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,CACvC,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,MAAM,CACP,EAAE,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,IAAI,EAAE,MAAM,IAAI;IACjD,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,QAAQ,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,CAAC,IAAI,EAAE,MAAM,IAAI;IACpD,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,WAAW,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,CAAC,MAAM,EAAE,MAAM,IAAI;IACtD,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,WAAW,CAAC;IACxD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,IAAI,EAAE,MAAM,IAAI;IACrD,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,YAAY,CAAC;IACzD,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,CAAC,IAAI,EAAE,MAAM,IAAI;IACpD,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,WAAW,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,6BAA6B,CAAC,MAAM,EAAE,MAAM,IAAI;IAC1D,QAAQ,CAAC,IAAI,EAAE,OAAO,qBAAqB,CAAC,eAAe,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAC5B,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,UAAU,CAAC,MAAM,CAAC,EAC/B,IAAI,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,IACrC,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAE9D,qBAAa,mBAAoB,SAAQ,KAAK;IAG1C,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE;gBADnC,OAAO,EAAE,MAAM,EACN,MAAM,GAAE,SAAS,OAAO,EAAO,EACxC,OAAO,CAAC,EAAE,YAAY;CAKzB;AAED,MAAM,MAAM,6BAA6B,CACvC,KAAK,EACL,MAAM,EACN,MAAM,EACN,KAAK,SAAS,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,IACpD,CAAC,KAAK,EAAE,KAAK,KAAK,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAEvE,wBAAgB,+BAA+B,CAC7C,KAAK,EACL,MAAM,EACN,MAAM,EACN,KAAK,SAAS,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,EAEtD,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,6BAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EACrE,OAAO,SAAqB,GAC3B,KAAK,CASP;AAED,MAAM,WAAW,qBAAqB,CACpC,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,UAAU,CAAC,MAAM,CAAC,EAC/B,IAAI,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,MAAM,EACN,KAAK,SAAS,kBAAkB,CAC9B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,CACL,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;IAE5E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,KAAK,EAAE;QACZ,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;KACpE,GAAG,KAAK,GAAG,IAAI,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,UAAU,CAAC,MAAM,CAAC,EAC/B,IAAI,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,MAAM,EACN,KAAK,SAAS,kBAAkB,CAC9B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,CACL,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,EAE5E,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAC3E,QAAQ,CAAC,EAAE,SAAS,qBAAqB,CACvC,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,KAAK,CACN,EAAE,GACF,KAAK,CAWP;AA0LD,wBAAgB,qBAAqB,CACnC,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,UAAU,CAAC,MAAM,CAAC,EAC/B,IAAI,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,MAAM,EACN,KAAK,SAAS,kBAAkB,CAC9B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,CACL,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,EAE5E,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EACxE,QAAQ,GAAE,SAAS,qBAAqB,CACtC,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,KAAK,CACN,EAUE,GACF,KAAK,CAaP;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,UAAU,CAAC,MAAM,CAAC,EAC/B,IAAI,SAAS,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,MAAM,EACN,KAAK,SAAS,kBAAkB,CAC9B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,CACL,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KACzE,SAAS,qBAAqB,CACjC,OAAO,EACP,IAAI,EACJ,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,KAAK,CACN,EAAE,CAOF"}
@@ -0,0 +1,138 @@
1
+ import { appendDraftItems, produceImmutable, removeDraftItemsByKey, removeDraftItemsWhere, replaceExistingDraftItemsByKey, } from "@alpacakit/core";
2
+ import { validatePlanGraph } from "./validator.js";
3
+ import { PLAN_GRAPH_PATCH_KIND, PLAN_GRAPH_VALIDATION_RESULT_KIND, } from "./values.js";
4
+ const CORE_PLAN_GRAPH_PATCH_REDUCER_ID = "core_plan_graph_patch";
5
+ export const EMPTY_GRAPH_PATCH_LIST = Object.freeze([]);
6
+ export class PlanGraphPatchError extends Error {
7
+ issues;
8
+ constructor(message, issues = [], options) {
9
+ super(message, options);
10
+ this.issues = issues;
11
+ this.name = "PlanGraphPatchError";
12
+ }
13
+ }
14
+ export function assertValidPlanGraphPatchResult(graph, validate, subject = "Plan graph patch") {
15
+ const result = validate(graph);
16
+ if (result.kind === PLAN_GRAPH_VALIDATION_RESULT_KIND.valid) {
17
+ return graph;
18
+ }
19
+ throw new PlanGraphPatchError(buildInvalidPatchMessage(subject, result.issues), result.issues);
20
+ }
21
+ export function applyPlanGraphPatch(graph, command, reducers) {
22
+ return applyPlanGraphPatches(graph, {
23
+ graphId: command.graphId,
24
+ baseRevision: command.baseRevision,
25
+ nextRevision: command.nextRevision,
26
+ patches: [command.patch],
27
+ }, reducers);
28
+ }
29
+ function applyPlanGraphStructuralPatch(graph, patch, reducers) {
30
+ assertPatchTargetsExistingElements(graph, patch);
31
+ for (const reducer of reducers) {
32
+ const nextGraph = reducer.reduce({ graph, patch });
33
+ if (nextGraph !== null) {
34
+ assertValidPatchedGraph(nextGraph);
35
+ return nextGraph;
36
+ }
37
+ }
38
+ throw new PlanGraphPatchError(`No plan graph patch reducer handled ${patch.kind}.`);
39
+ }
40
+ function assertPatchTargetsExistingElements(graph, patch) {
41
+ switch (patch.kind) {
42
+ case PLAN_GRAPH_PATCH_KIND.updateNodes:
43
+ assertKnownIds("node", graph.nodes, patch.nodes.map((node) => node.id));
44
+ return;
45
+ case PLAN_GRAPH_PATCH_KIND.removeNodes:
46
+ assertKnownIds("node", graph.nodes, patch.nodeIds);
47
+ return;
48
+ case PLAN_GRAPH_PATCH_KIND.updateEdges:
49
+ assertKnownIds("edge", graph.edges, patch.edges.map((edge) => edge.id));
50
+ return;
51
+ case PLAN_GRAPH_PATCH_KIND.disconnectEdges:
52
+ assertKnownIds("edge", graph.edges, patch.edgeIds);
53
+ return;
54
+ case PLAN_GRAPH_PATCH_KIND.addNodes:
55
+ case PLAN_GRAPH_PATCH_KIND.connectEdges:
56
+ return;
57
+ default:
58
+ throw new PlanGraphPatchError(`Unsupported plan graph patch kind ${String(patch.kind)}.`);
59
+ }
60
+ }
61
+ function assertKnownIds(targetName, currentItems, targetIds) {
62
+ const currentIds = new Set(currentItems.map((item) => item.id));
63
+ for (const targetId of targetIds) {
64
+ if (!currentIds.has(targetId)) {
65
+ throw new PlanGraphPatchError(`Plan graph patch references missing ${targetName} id ${String(targetId)}.`);
66
+ }
67
+ }
68
+ }
69
+ function assertValidPatchedGraph(graph) {
70
+ const result = validatePlanGraph(graph);
71
+ if (result.kind === PLAN_GRAPH_VALIDATION_RESULT_KIND.valid) {
72
+ return;
73
+ }
74
+ throw new PlanGraphPatchError(buildInvalidPatchMessage("Plan graph patch", result.issues), result.issues);
75
+ }
76
+ function buildInvalidPatchMessage(subject, issues) {
77
+ const issueKinds = issues.map((issue) => issue.kind).join(", ");
78
+ return `${subject} produced an invalid graph (${issues.length} issue${issues.length === 1 ? "" : "s"}: ${issueKinds}).`;
79
+ }
80
+ function assertPatchTargetsGraph(graphId, patchGraphId) {
81
+ if (graphId === patchGraphId) {
82
+ return;
83
+ }
84
+ throw new PlanGraphPatchError(`Plan graph patch targets ${String(patchGraphId)}, but current graph is ${String(graphId)}.`);
85
+ }
86
+ function assertPatchTargetsRevision(graphRevision, patchBaseRevision) {
87
+ if (Object.is(graphRevision, patchBaseRevision)) {
88
+ return;
89
+ }
90
+ throw new PlanGraphPatchError(`Plan graph patch base revision ${String(patchBaseRevision)} does not match current revision ${String(graphRevision)}.`);
91
+ }
92
+ export function applyPlanGraphPatches(graph, patchSet, reducers = createCorePlanGraphPatchReducers()) {
93
+ assertPatchTargetsGraph(graph.id, patchSet.graphId);
94
+ assertPatchTargetsRevision(graph.revision, patchSet.baseRevision);
95
+ const patchedGraph = patchSet.patches.reduce((currentGraph, patch) => applyPlanGraphStructuralPatch(currentGraph, patch, reducers), graph);
96
+ const nextGraph = produceImmutable(patchedGraph, (draft) => {
97
+ draft.revision = patchSet.nextRevision;
98
+ });
99
+ assertValidPatchedGraph(nextGraph);
100
+ return nextGraph;
101
+ }
102
+ export function createCorePlanGraphPatchReducers() {
103
+ return [
104
+ {
105
+ id: CORE_PLAN_GRAPH_PATCH_REDUCER_ID,
106
+ reduce: ({ graph, patch }) => reduceCorePlanGraphPatch(graph, patch),
107
+ },
108
+ ];
109
+ }
110
+ function reduceCorePlanGraphPatch(graph, patch) {
111
+ return produceImmutable(graph, (draft) => {
112
+ switch (patch.kind) {
113
+ case PLAN_GRAPH_PATCH_KIND.addNodes:
114
+ appendDraftItems(draft.nodes, patch.nodes);
115
+ return;
116
+ case PLAN_GRAPH_PATCH_KIND.updateNodes:
117
+ replaceExistingDraftItemsByKey(draft.nodes, patch.nodes, (node) => node.id);
118
+ return;
119
+ case PLAN_GRAPH_PATCH_KIND.removeNodes: {
120
+ removeDraftItemsWhere(draft.edges, (edge) => patch.nodeIds.some((nodeId) => Object.is(edge.fromNodeId, nodeId) ||
121
+ Object.is(edge.toNodeId, nodeId)));
122
+ removeDraftItemsByKey(draft.nodes, patch.nodeIds, (node) => node.id);
123
+ return;
124
+ }
125
+ case PLAN_GRAPH_PATCH_KIND.connectEdges:
126
+ appendDraftItems(draft.edges, patch.edges);
127
+ return;
128
+ case PLAN_GRAPH_PATCH_KIND.updateEdges:
129
+ replaceExistingDraftItemsByKey(draft.edges, patch.edges, (edge) => edge.id);
130
+ return;
131
+ case PLAN_GRAPH_PATCH_KIND.disconnectEdges:
132
+ removeDraftItemsByKey(draft.edges, patch.edgeIds, (edge) => edge.id);
133
+ return;
134
+ default:
135
+ throw new PlanGraphPatchError(`Unsupported plan graph patch kind ${String(patch.kind)}.`);
136
+ }
137
+ });
138
+ }
@@ -0,0 +1,9 @@
1
+ import type { Projector } from "@alpacakit/core";
2
+ export interface PlanGraphProjection<InputGraph, OutputGraph> extends Projector<InputGraph, OutputGraph> {
3
+ readonly id: string;
4
+ }
5
+ export interface PlanGraphPatchProjection<InputGraph, Patch> {
6
+ readonly id: string;
7
+ project(input: InputGraph): readonly Patch[];
8
+ }
9
+ //# sourceMappingURL=projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../src/plan-graph/projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,mBAAmB,CAAC,UAAU,EAAE,WAAW,CAC1D,SAAQ,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB,CAAC,UAAU,EAAE,KAAK;IACzD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,KAAK,EAAE,CAAC;CAC9C"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { PlanGraphDefinition, PlanGraphEdgeRef, PlanGraphNodeRef } from "./model.js";
2
+ export type ReadyPlanGraphNodesInput<NodeId, Edge> = {
3
+ readonly completedNodeIds: ReadonlySet<NodeId>;
4
+ readonly blockedNodeIds: ReadonlySet<NodeId>;
5
+ readonly isEdgeReady: (edge: Edge) => boolean;
6
+ };
7
+ export declare function selectReadyPlanGraphNodes<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>>(graph: PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>, input: ReadyPlanGraphNodesInput<NodeId, Edge>): readonly Node[];
8
+ export declare function selectDependencyReadyPlanGraphNodes<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>>(graph: PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>, input: {
9
+ readonly completedNodeIds: ReadonlySet<NodeId>;
10
+ readonly blockedNodeIds?: ReadonlySet<NodeId>;
11
+ }): readonly Node[];
12
+ //# sourceMappingURL=readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../../src/plan-graph/readiness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,wBAAwB,CAAC,MAAM,EAAE,IAAI,IAAI;IACnD,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CAC/C,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACrC,IAAI,SAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAE7C,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,EAChE,KAAK,EAAE,wBAAwB,CAAC,MAAM,EAAE,IAAI,CAAC,GAC5C,SAAS,IAAI,EAAE,CAcjB;AAED,wBAAgB,mCAAmC,CACjD,OAAO,EACP,IAAI,SAAS,MAAM,EACnB,SAAS,EACT,MAAM,EACN,MAAM,EACN,IAAI,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACrC,IAAI,SAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAE7C,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,EAChE,KAAK,EAAE;IACL,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/C,GACA,SAAS,IAAI,EAAE,CAMjB"}
@@ -0,0 +1,26 @@
1
+ export function selectReadyPlanGraphNodes(graph, input) {
2
+ const incomingEdgesByNodeId = groupIncomingEdgesByNodeId(graph.edges);
3
+ return graph.nodes.filter((node) => {
4
+ if (input.completedNodeIds.has(node.id) ||
5
+ input.blockedNodeIds.has(node.id)) {
6
+ return false;
7
+ }
8
+ return (incomingEdgesByNodeId.get(node.id) ?? []).every((edge) => input.completedNodeIds.has(edge.fromNodeId) && input.isEdgeReady(edge));
9
+ });
10
+ }
11
+ export function selectDependencyReadyPlanGraphNodes(graph, input) {
12
+ return selectReadyPlanGraphNodes(graph, {
13
+ completedNodeIds: input.completedNodeIds,
14
+ blockedNodeIds: input.blockedNodeIds ?? new Set(),
15
+ isEdgeReady: () => true,
16
+ });
17
+ }
18
+ function groupIncomingEdgesByNodeId(edges) {
19
+ const incomingEdgesByNodeId = new Map();
20
+ for (const edge of edges) {
21
+ const incomingEdges = incomingEdgesByNodeId.get(edge.toNodeId) ?? [];
22
+ incomingEdges.push(edge);
23
+ incomingEdgesByNodeId.set(edge.toNodeId, incomingEdges);
24
+ }
25
+ return incomingEdgesByNodeId;
26
+ }
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ export declare const planGraphIdSchema: z.ZodType<import("@alpacakit/core").Brand<string, "PlanGraphId">, unknown, z.core.$ZodTypeInternals<import("@alpacakit/core").Brand<string, "PlanGraphId">, unknown>>;
3
+ export declare const planGraphNodeIdSchema: z.ZodType<import("@alpacakit/core").Brand<string, "PlanGraphNodeId">, unknown, z.core.$ZodTypeInternals<import("@alpacakit/core").Brand<string, "PlanGraphNodeId">, unknown>>;
4
+ export declare const planGraphEdgeIdSchema: z.ZodType<import("@alpacakit/core").Brand<string, "PlanGraphEdgeId">, unknown, z.core.$ZodTypeInternals<import("@alpacakit/core").Brand<string, "PlanGraphEdgeId">, unknown>>;
5
+ export declare const planGraphPatchIdSchema: z.ZodType<import("@alpacakit/core").Brand<string, "PlanGraphPatchId">, unknown, z.core.$ZodTypeInternals<import("@alpacakit/core").Brand<string, "PlanGraphPatchId">, unknown>>;
6
+ export declare const planGraphPatchKindSchema: z.ZodEnum<{
7
+ add_nodes: "add_nodes";
8
+ update_nodes: "update_nodes";
9
+ remove_nodes: "remove_nodes";
10
+ connect_edges: "connect_edges";
11
+ update_edges: "update_edges";
12
+ disconnect_edges: "disconnect_edges";
13
+ }>;
14
+ export declare const planGraphNodeOriginKindSchema: z.ZodEnum<{
15
+ seed: "seed";
16
+ patch: "patch";
17
+ projection: "projection";
18
+ imported: "imported";
19
+ }>;
20
+ export declare const planGraphNodeOriginSchema: z.ZodReadonly<z.ZodObject<{
21
+ kind: z.ZodEnum<{
22
+ seed: "seed";
23
+ patch: "patch";
24
+ projection: "projection";
25
+ imported: "imported";
26
+ }>;
27
+ sourceId: z.ZodNullable<z.ZodString>;
28
+ }, z.core.$strip>>;
29
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/plan-graph/schema.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,iBAAiB,uKAAgD,CAAC;AAC/E,eAAO,MAAM,qBAAqB,+KACiB,CAAC;AACpD,eAAO,MAAM,qBAAqB,+KACiB,CAAC;AACpD,eAAO,MAAM,sBAAsB,iLACiB,CAAC;AAErD,eAAO,MAAM,wBAAwB;;;;;;;EAOnC,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;EAKxC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;kBAGpC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { brandedStringSchema, strictReadonlyObject, stringIdSchema, } from "@alpacakit/core";
2
+ import { z } from "zod";
3
+ import { PLAN_GRAPH_NODE_ORIGIN_KIND, PLAN_GRAPH_PATCH_KIND, } from "./values.js";
4
+ export const planGraphIdSchema = brandedStringSchema();
5
+ export const planGraphNodeIdSchema = brandedStringSchema();
6
+ export const planGraphEdgeIdSchema = brandedStringSchema();
7
+ export const planGraphPatchIdSchema = brandedStringSchema();
8
+ export const planGraphPatchKindSchema = z.enum([
9
+ PLAN_GRAPH_PATCH_KIND.addNodes,
10
+ PLAN_GRAPH_PATCH_KIND.updateNodes,
11
+ PLAN_GRAPH_PATCH_KIND.removeNodes,
12
+ PLAN_GRAPH_PATCH_KIND.connectEdges,
13
+ PLAN_GRAPH_PATCH_KIND.updateEdges,
14
+ PLAN_GRAPH_PATCH_KIND.disconnectEdges,
15
+ ]);
16
+ export const planGraphNodeOriginKindSchema = z.enum([
17
+ PLAN_GRAPH_NODE_ORIGIN_KIND.seed,
18
+ PLAN_GRAPH_NODE_ORIGIN_KIND.patch,
19
+ PLAN_GRAPH_NODE_ORIGIN_KIND.projection,
20
+ PLAN_GRAPH_NODE_ORIGIN_KIND.imported,
21
+ ]);
22
+ export const planGraphNodeOriginSchema = strictReadonlyObject({
23
+ kind: planGraphNodeOriginKindSchema,
24
+ sourceId: stringIdSchema.nullable(),
25
+ });
@@ -0,0 +1,27 @@
1
+ import type { PlanGraphDefinition, PlanGraphEdgeRef, PlanGraphNodeRef, PlanGraphValidationIssue, PlanGraphValidationResult } from "./model.js";
2
+ export declare class PlanGraphValidationError extends Error {
3
+ readonly issues: readonly unknown[];
4
+ constructor(message: string, issues?: readonly unknown[], options?: ErrorOptions);
5
+ }
6
+ export interface PlanGraphValidationRule<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>> {
7
+ readonly id: string;
8
+ validate(graph: Graph): Iterable<PlanGraphValidationIssue<NodeId, EdgeId>>;
9
+ }
10
+ type PlanGraphValidationRuleHandler<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>> = (graph: Graph) => Iterable<PlanGraphValidationIssue<NodeId, EdgeId>>;
11
+ export interface PlanGraphValidator<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>> {
12
+ validate(graph: Graph): PlanGraphValidationResult<NodeId, EdgeId>;
13
+ }
14
+ export declare class RuleBasedPlanGraphValidator<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>> implements PlanGraphValidator<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph> {
15
+ private readonly rules;
16
+ constructor(rules: readonly PlanGraphValidationRule<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>[]);
17
+ validate(graph: Graph): PlanGraphValidationResult<NodeId, EdgeId>;
18
+ }
19
+ export declare function definePlanGraphValidationRule<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>>(id: string, validate: PlanGraphValidationRuleHandler<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>): PlanGraphValidationRule<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>;
20
+ export declare function validatePlanGraph<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>>(graph: Graph): PlanGraphValidationResult<NodeId, EdgeId>;
21
+ export declare function validatePlanGraphWithRules<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>>(graph: Graph, rules: readonly PlanGraphValidationRule<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>[]): PlanGraphValidationResult<NodeId, EdgeId>;
22
+ export declare function createPlanGraphValidator<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>>(rules: readonly PlanGraphValidationRule<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>[]): PlanGraphValidator<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>;
23
+ export declare function createCorePlanGraphValidator<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>>(): PlanGraphValidator<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>;
24
+ export declare function createCorePlanGraphValidationRules<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>, Graph extends PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge> = PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>>(): readonly PlanGraphValidationRule<GraphId, Kind, TMetadata, NodeId, EdgeId, Node, Edge, Graph>[];
25
+ export declare function assertValidPlanGraph<GraphId, Kind extends string, TMetadata, NodeId, EdgeId, Node extends PlanGraphNodeRef<NodeId>, Edge extends PlanGraphEdgeRef<EdgeId, NodeId>>(graph: PlanGraphDefinition<GraphId, Kind, TMetadata, Node, Edge>): void;
26
+ export {};
27
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/plan-graph/validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ import { topologicallyOrderPlanGraphNodes } from "./ordering.js";
2
+ import { PLAN_GRAPH_ORDERING_RESULT_KIND, PLAN_GRAPH_VALIDATION_ISSUE_KIND, PLAN_GRAPH_VALIDATION_RESULT_KIND, PLAN_GRAPH_VALIDATION_RULE_ID, } from "./values.js";
3
+ export class PlanGraphValidationError extends Error {
4
+ issues;
5
+ constructor(message, issues = [], options) {
6
+ super(message, options);
7
+ this.issues = issues;
8
+ this.name = "PlanGraphValidationError";
9
+ }
10
+ }
11
+ export class RuleBasedPlanGraphValidator {
12
+ rules;
13
+ constructor(rules) {
14
+ this.rules = rules;
15
+ }
16
+ validate(graph) {
17
+ const issues = [
18
+ ...iteratePlanGraphValidationIssues(graph, this.rules),
19
+ ];
20
+ return issues.length === 0
21
+ ? { kind: PLAN_GRAPH_VALIDATION_RESULT_KIND.valid }
22
+ : { kind: PLAN_GRAPH_VALIDATION_RESULT_KIND.invalid, issues };
23
+ }
24
+ }
25
+ export function definePlanGraphValidationRule(id, validate) {
26
+ return { id, validate };
27
+ }
28
+ export function validatePlanGraph(graph) {
29
+ return createCorePlanGraphValidator().validate(graph);
30
+ }
31
+ export function validatePlanGraphWithRules(graph, rules) {
32
+ return createPlanGraphValidator(rules).validate(graph);
33
+ }
34
+ export function createPlanGraphValidator(rules) {
35
+ return new RuleBasedPlanGraphValidator(rules);
36
+ }
37
+ function* iteratePlanGraphValidationIssues(graph, rules) {
38
+ for (const rule of rules) {
39
+ try {
40
+ yield* rule.validate(graph);
41
+ }
42
+ catch (error) {
43
+ throw new PlanGraphValidationError(`Plan graph validation rule ${rule.id} failed.`, [], { cause: error });
44
+ }
45
+ }
46
+ }
47
+ export function createCorePlanGraphValidator() {
48
+ return createPlanGraphValidator(createCorePlanGraphValidationRules());
49
+ }
50
+ export function createCorePlanGraphValidationRules() {
51
+ return [
52
+ definePlanGraphValidationRule(PLAN_GRAPH_VALIDATION_RULE_ID.uniqueNodeIds, (graph) => findDuplicateNodeIssues(graph.nodes)),
53
+ definePlanGraphValidationRule(PLAN_GRAPH_VALIDATION_RULE_ID.uniqueEdgeIds, (graph) => findDuplicateEdgeIssues(graph.edges)),
54
+ definePlanGraphValidationRule(PLAN_GRAPH_VALIDATION_RULE_ID.noSelfEdges, (graph) => findSelfEdgeIssues(graph.edges)),
55
+ definePlanGraphValidationRule(PLAN_GRAPH_VALIDATION_RULE_ID.knownEdgeEndpoints, (graph) => findMissingEndpointIssues(graph)),
56
+ definePlanGraphValidationRule(PLAN_GRAPH_VALIDATION_RULE_ID.acyclicGraph, (graph) => findCycleIssues(graph)),
57
+ ];
58
+ }
59
+ export function assertValidPlanGraph(graph) {
60
+ const result = validatePlanGraph(graph);
61
+ if (result.kind === PLAN_GRAPH_VALIDATION_RESULT_KIND.valid) {
62
+ return;
63
+ }
64
+ throw new PlanGraphValidationError(buildInvalidGraphMessage(result.issues), result.issues);
65
+ }
66
+ function buildInvalidGraphMessage(issues) {
67
+ const issueKinds = issues.map((issue) => issue.kind).join(", ");
68
+ return `Invalid plan graph (${issues.length} issue${issues.length === 1 ? "" : "s"}: ${issueKinds}).`;
69
+ }
70
+ function* findDuplicateNodeIssues(nodes) {
71
+ yield* findDuplicateIdIssues(nodes, (node) => node.id, (nodeId) => createPlanGraphValidationIssue(PLAN_GRAPH_VALIDATION_ISSUE_KIND.duplicateNodeId, `Plan graph contains duplicate node id ${String(nodeId)}.`, {
72
+ nodeId,
73
+ nodeIds: [nodeId],
74
+ }));
75
+ }
76
+ function* findDuplicateEdgeIssues(edges) {
77
+ yield* findDuplicateIdIssues(edges, (edge) => edge.id, (edgeId) => createPlanGraphValidationIssue(PLAN_GRAPH_VALIDATION_ISSUE_KIND.duplicateEdgeId, `Plan graph contains duplicate edge id ${String(edgeId)}.`, {
78
+ edgeId,
79
+ edgeIds: [edgeId],
80
+ }));
81
+ }
82
+ function* findDuplicateIdIssues(items, idOf, issueOf) {
83
+ const seenIds = new Set();
84
+ const duplicateIds = new Set();
85
+ for (const item of items) {
86
+ const id = idOf(item);
87
+ if (seenIds.has(id)) {
88
+ duplicateIds.add(id);
89
+ }
90
+ seenIds.add(id);
91
+ }
92
+ for (const duplicateId of duplicateIds) {
93
+ yield issueOf(duplicateId);
94
+ }
95
+ }
96
+ function* findSelfEdgeIssues(edges) {
97
+ for (const edge of edges) {
98
+ if (edge.fromNodeId === edge.toNodeId) {
99
+ yield createPlanGraphValidationIssue(PLAN_GRAPH_VALIDATION_ISSUE_KIND.selfEdge, `Plan graph edge ${String(edge.id)} points to itself.`, {
100
+ edgeId: edge.id,
101
+ nodeId: edge.fromNodeId,
102
+ edgeIds: [edge.id],
103
+ nodeIds: [edge.fromNodeId],
104
+ });
105
+ }
106
+ }
107
+ }
108
+ function* findMissingEndpointIssues(graph) {
109
+ const nodeIds = new Set(graph.nodes.map((node) => node.id));
110
+ for (const edge of graph.edges) {
111
+ if (!nodeIds.has(edge.fromNodeId)) {
112
+ yield missingEndpointIssue(edge.id, edge.fromNodeId);
113
+ }
114
+ if (!nodeIds.has(edge.toNodeId)) {
115
+ yield missingEndpointIssue(edge.id, edge.toNodeId);
116
+ }
117
+ }
118
+ }
119
+ function* findCycleIssues(graph) {
120
+ if (!canEvaluateCycles(graph)) {
121
+ return;
122
+ }
123
+ const ordered = topologicallyOrderPlanGraphNodes(graph);
124
+ if (ordered.kind === PLAN_GRAPH_ORDERING_RESULT_KIND.ordered) {
125
+ return;
126
+ }
127
+ yield createPlanGraphValidationIssue(PLAN_GRAPH_VALIDATION_ISSUE_KIND.cycle, `Plan graph contains a cycle involving ${ordered.nodeIds
128
+ .map(String)
129
+ .join(", ")}.`, {
130
+ nodeIds: ordered.nodeIds,
131
+ });
132
+ }
133
+ function canEvaluateCycles(graph) {
134
+ const nodeIds = new Set();
135
+ for (const node of graph.nodes) {
136
+ if (nodeIds.has(node.id)) {
137
+ return false;
138
+ }
139
+ nodeIds.add(node.id);
140
+ }
141
+ for (const edge of graph.edges) {
142
+ if (!nodeIds.has(edge.fromNodeId) || !nodeIds.has(edge.toNodeId)) {
143
+ return false;
144
+ }
145
+ }
146
+ return true;
147
+ }
148
+ function missingEndpointIssue(edgeId, nodeId) {
149
+ return createPlanGraphValidationIssue(PLAN_GRAPH_VALIDATION_ISSUE_KIND.missingEdgeEndpoint, `Plan graph edge ${String(edgeId)} references missing node ${String(nodeId)}.`, {
150
+ edgeId,
151
+ nodeId,
152
+ edgeIds: [edgeId],
153
+ nodeIds: [nodeId],
154
+ });
155
+ }
156
+ function createPlanGraphValidationIssue(kind, message, location) {
157
+ return {
158
+ kind,
159
+ message,
160
+ location: {
161
+ nodeId: location.nodeId ?? null,
162
+ edgeId: location.edgeId ?? null,
163
+ nodeIds: location.nodeIds ?? [],
164
+ edgeIds: location.edgeIds ?? [],
165
+ },
166
+ details: {},
167
+ };
168
+ }
@@ -0,0 +1,44 @@
1
+ import type { ValueOf } from "@alpacakit/core";
2
+ export declare const PLAN_GRAPH_PATCH_KIND: {
3
+ readonly addNodes: "add_nodes";
4
+ readonly updateNodes: "update_nodes";
5
+ readonly removeNodes: "remove_nodes";
6
+ readonly connectEdges: "connect_edges";
7
+ readonly updateEdges: "update_edges";
8
+ readonly disconnectEdges: "disconnect_edges";
9
+ };
10
+ export type PlanGraphPatchKind = ValueOf<typeof PLAN_GRAPH_PATCH_KIND>;
11
+ export declare const PLAN_GRAPH_NODE_ORIGIN_KIND: {
12
+ readonly seed: "seed";
13
+ readonly patch: "patch";
14
+ readonly projection: "projection";
15
+ readonly imported: "imported";
16
+ };
17
+ export type PlanGraphNodeOriginKind = ValueOf<typeof PLAN_GRAPH_NODE_ORIGIN_KIND>;
18
+ export declare const PLAN_GRAPH_ORDERING_RESULT_KIND: {
19
+ readonly ordered: "ordered";
20
+ readonly cycle: "cycle";
21
+ };
22
+ export type PlanGraphOrderingResultKind = ValueOf<typeof PLAN_GRAPH_ORDERING_RESULT_KIND>;
23
+ export declare const PLAN_GRAPH_VALIDATION_RULE_ID: {
24
+ readonly uniqueNodeIds: "unique_node_ids";
25
+ readonly uniqueEdgeIds: "unique_edge_ids";
26
+ readonly noSelfEdges: "no_self_edges";
27
+ readonly knownEdgeEndpoints: "known_edge_endpoints";
28
+ readonly acyclicGraph: "acyclic_graph";
29
+ };
30
+ export type PlanGraphValidationRuleId = ValueOf<typeof PLAN_GRAPH_VALIDATION_RULE_ID>;
31
+ export declare const PLAN_GRAPH_VALIDATION_RESULT_KIND: {
32
+ readonly valid: "valid";
33
+ readonly invalid: "invalid";
34
+ };
35
+ export type PlanGraphValidationResultKind = ValueOf<typeof PLAN_GRAPH_VALIDATION_RESULT_KIND>;
36
+ export declare const PLAN_GRAPH_VALIDATION_ISSUE_KIND: {
37
+ readonly duplicateNodeId: "duplicate_node_id";
38
+ readonly duplicateEdgeId: "duplicate_edge_id";
39
+ readonly missingEdgeEndpoint: "missing_edge_endpoint";
40
+ readonly selfEdge: "self_edge";
41
+ readonly cycle: "cycle";
42
+ };
43
+ export type PlanGraphValidationIssueKind = ValueOf<typeof PLAN_GRAPH_VALIDATION_ISSUE_KIND>;
44
+ //# sourceMappingURL=values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/plan-graph/values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,eAAO,MAAM,qBAAqB;;;;;;;CAOxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEvE,eAAO,MAAM,2BAA2B;;;;;CAK9B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAC3C,OAAO,2BAA2B,CACnC,CAAC;AAEF,eAAO,MAAM,+BAA+B;;;CAGlC,CAAC;AAEX,MAAM,MAAM,2BAA2B,GAAG,OAAO,CAC/C,OAAO,+BAA+B,CACvC,CAAC;AAEF,eAAO,MAAM,6BAA6B;;;;;;CAMhC,CAAC;AAEX,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAC7C,OAAO,6BAA6B,CACrC,CAAC;AAEF,eAAO,MAAM,iCAAiC;;;CAGpC,CAAC;AAEX,MAAM,MAAM,6BAA6B,GAAG,OAAO,CACjD,OAAO,iCAAiC,CACzC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;CAMnC,CAAC;AAEX,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAChD,OAAO,gCAAgC,CACxC,CAAC"}
@@ -0,0 +1,36 @@
1
+ export const PLAN_GRAPH_PATCH_KIND = {
2
+ addNodes: "add_nodes",
3
+ updateNodes: "update_nodes",
4
+ removeNodes: "remove_nodes",
5
+ connectEdges: "connect_edges",
6
+ updateEdges: "update_edges",
7
+ disconnectEdges: "disconnect_edges",
8
+ };
9
+ export const PLAN_GRAPH_NODE_ORIGIN_KIND = {
10
+ seed: "seed",
11
+ patch: "patch",
12
+ projection: "projection",
13
+ imported: "imported",
14
+ };
15
+ export const PLAN_GRAPH_ORDERING_RESULT_KIND = {
16
+ ordered: "ordered",
17
+ cycle: "cycle",
18
+ };
19
+ export const PLAN_GRAPH_VALIDATION_RULE_ID = {
20
+ uniqueNodeIds: "unique_node_ids",
21
+ uniqueEdgeIds: "unique_edge_ids",
22
+ noSelfEdges: "no_self_edges",
23
+ knownEdgeEndpoints: "known_edge_endpoints",
24
+ acyclicGraph: "acyclic_graph",
25
+ };
26
+ export const PLAN_GRAPH_VALIDATION_RESULT_KIND = {
27
+ valid: "valid",
28
+ invalid: "invalid",
29
+ };
30
+ export const PLAN_GRAPH_VALIDATION_ISSUE_KIND = {
31
+ duplicateNodeId: "duplicate_node_id",
32
+ duplicateEdgeId: "duplicate_edge_id",
33
+ missingEdgeEndpoint: "missing_edge_endpoint",
34
+ selfEdge: "self_edge",
35
+ cycle: "cycle",
36
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./mermaid-flowchart.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./mermaid-flowchart.js";
@@ -0,0 +1,43 @@
1
+ export declare const MERMAID_FLOWCHART_EDGE_STYLE: {
2
+ readonly solid: "solid";
3
+ readonly dotted: "dotted";
4
+ };
5
+ export type MermaidFlowchartEdgeStyle = (typeof MERMAID_FLOWCHART_EDGE_STYLE)[keyof typeof MERMAID_FLOWCHART_EDGE_STYLE];
6
+ export type MermaidFlowchartNode<NodeId extends string> = {
7
+ readonly id: NodeId;
8
+ readonly label: string;
9
+ };
10
+ export type MermaidFlowchartEdge<NodeId extends string> = {
11
+ readonly fromNodeId: NodeId;
12
+ readonly toNodeId: NodeId;
13
+ readonly label: string | null;
14
+ readonly style: MermaidFlowchartEdgeStyle;
15
+ };
16
+ export type MermaidFlowchartClassDefinition = {
17
+ readonly name: string;
18
+ readonly style: string;
19
+ };
20
+ export type MermaidFlowchartClassAssignment<NodeId extends string> = {
21
+ readonly nodeId: NodeId;
22
+ readonly className: string;
23
+ };
24
+ export interface MermaidFlowchartRenderContext<NodeId extends string> {
25
+ nodeName(nodeId: NodeId): string;
26
+ escapeText(value: string): string;
27
+ bodyLine(value: string): string;
28
+ }
29
+ export type MermaidFlowchartBodySection<NodeId extends string> = (context: MermaidFlowchartRenderContext<NodeId>) => readonly string[];
30
+ export type MermaidFlowchartBodySections<NodeId extends string> = {
31
+ readonly beforeEdges: readonly MermaidFlowchartBodySection<NodeId>[];
32
+ readonly afterEdges: readonly MermaidFlowchartBodySection<NodeId>[];
33
+ };
34
+ export type MermaidFlowchartInput<NodeId extends string> = {
35
+ readonly preambleCommentLines: readonly string[];
36
+ readonly nodes: readonly MermaidFlowchartNode<NodeId>[];
37
+ readonly edges: readonly MermaidFlowchartEdge<NodeId>[];
38
+ readonly classDefinitions: readonly MermaidFlowchartClassDefinition[];
39
+ readonly classAssignments: readonly MermaidFlowchartClassAssignment<NodeId>[];
40
+ readonly bodySections: MermaidFlowchartBodySections<NodeId>;
41
+ };
42
+ export declare function renderMermaidFlowchart<NodeId extends string>(input: MermaidFlowchartInput<NodeId>): string;
43
+ //# sourceMappingURL=mermaid-flowchart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid-flowchart.d.ts","sourceRoot":"","sources":["../../src/render/mermaid-flowchart.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B;;;CAG/B,CAAC;AAEX,MAAM,MAAM,yBAAyB,GACnC,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,OAAO,4BAA4B,CAAC,CAAC;AAEnF,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI;IACxD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAAC,MAAM,SAAS,MAAM,IAAI;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,+BAA+B,CAAC,MAAM,SAAS,MAAM,IAAI;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,6BAA6B,CAAC,MAAM,SAAS,MAAM;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,2BAA2B,CAAC,MAAM,SAAS,MAAM,IAAI,CAC/D,OAAO,EAAE,6BAA6B,CAAC,MAAM,CAAC,KAC3C,SAAS,MAAM,EAAE,CAAC;AAEvB,MAAM,MAAM,4BAA4B,CAAC,MAAM,SAAS,MAAM,IAAI;IAChE,QAAQ,CAAC,WAAW,EAAE,SAAS,2BAA2B,CAAC,MAAM,CAAC,EAAE,CAAC;IACrE,QAAQ,CAAC,UAAU,EAAE,SAAS,2BAA2B,CAAC,MAAM,CAAC,EAAE,CAAC;CACrE,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,MAAM,SAAS,MAAM,IAAI;IACzD,QAAQ,CAAC,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;IACxD,QAAQ,CAAC,gBAAgB,EAAE,SAAS,+BAA+B,EAAE,CAAC;IACtE,QAAQ,CAAC,gBAAgB,EAAE,SAAS,+BAA+B,CAAC,MAAM,CAAC,EAAE,CAAC;IAC9E,QAAQ,CAAC,YAAY,EAAE,4BAA4B,CAAC,MAAM,CAAC,CAAC;CAC7D,CAAC;AAcF,wBAAgB,sBAAsB,CAAC,MAAM,SAAS,MAAM,EAC1D,KAAK,EAAE,qBAAqB,CAAC,MAAM,CAAC,GACnC,MAAM,CAKR"}
@@ -0,0 +1,75 @@
1
+ export const MERMAID_FLOWCHART_EDGE_STYLE = {
2
+ solid: "solid",
3
+ dotted: "dotted",
4
+ };
5
+ const MERMAID_FLOWCHART_TEXT = {
6
+ lineBreak: "\n",
7
+ indentation: " ",
8
+ commentPrefix: "%% ",
9
+ graphDeclaration: "flowchart LR",
10
+ nodeNamePrefix: "node",
11
+ classDefinitionKeyword: "classDef",
12
+ classAssignmentKeyword: "class",
13
+ missingNodeBinding: (nodeId) => `Missing Mermaid node render binding: ${String(nodeId)}.`,
14
+ };
15
+ export function renderMermaidFlowchart(input) {
16
+ const context = createRenderContext(input.nodes);
17
+ return [...renderMermaidFlowchartLines(input, context)].join(MERMAID_FLOWCHART_TEXT.lineBreak);
18
+ }
19
+ function* renderMermaidFlowchartLines(input, context) {
20
+ for (const line of input.preambleCommentLines) {
21
+ yield `${MERMAID_FLOWCHART_TEXT.commentPrefix}${context.escapeText(line)}`;
22
+ }
23
+ yield MERMAID_FLOWCHART_TEXT.graphDeclaration;
24
+ for (const node of input.nodes) {
25
+ yield context.bodyLine(`${context.nodeName(node.id)}["${context.escapeText(node.label)}"]`);
26
+ }
27
+ yield* renderBodySections(input.bodySections.beforeEdges, context);
28
+ for (const edge of input.edges) {
29
+ yield context.bodyLine(renderEdge(edge, context));
30
+ }
31
+ yield* renderBodySections(input.bodySections.afterEdges, context);
32
+ for (const definition of input.classDefinitions) {
33
+ yield context.bodyLine(`${MERMAID_FLOWCHART_TEXT.classDefinitionKeyword} ${definition.name} ${definition.style}`);
34
+ }
35
+ for (const assignment of input.classAssignments) {
36
+ yield context.bodyLine(`${MERMAID_FLOWCHART_TEXT.classAssignmentKeyword} ${context.nodeName(assignment.nodeId)} ${assignment.className}`);
37
+ }
38
+ }
39
+ function createRenderContext(nodes) {
40
+ const nodeNames = new Map(nodes.map((node, index) => [
41
+ node.id,
42
+ `${MERMAID_FLOWCHART_TEXT.nodeNamePrefix}${index}`,
43
+ ]));
44
+ return {
45
+ nodeName: (nodeId) => {
46
+ const name = nodeNames.get(nodeId);
47
+ if (name === undefined) {
48
+ throw new Error(MERMAID_FLOWCHART_TEXT.missingNodeBinding(nodeId));
49
+ }
50
+ return name;
51
+ },
52
+ escapeText: (value) => value
53
+ .replaceAll("&", "&amp;")
54
+ .replaceAll('"', "&quot;")
55
+ .replaceAll("|", "&#124;"),
56
+ bodyLine: (value) => `${MERMAID_FLOWCHART_TEXT.indentation}${value}`,
57
+ };
58
+ }
59
+ function* renderBodySections(sections, context) {
60
+ for (const section of sections) {
61
+ yield* section(context);
62
+ }
63
+ }
64
+ function renderEdge(edge, context) {
65
+ const from = context.nodeName(edge.fromNodeId);
66
+ const to = context.nodeName(edge.toNodeId);
67
+ if (edge.style === MERMAID_FLOWCHART_EDGE_STYLE.solid) {
68
+ return edge.label === null
69
+ ? `${from} --> ${to}`
70
+ : `${from} -->|"${context.escapeText(edge.label)}"| ${to}`;
71
+ }
72
+ return edge.label === null
73
+ ? `${from} -.-> ${to}`
74
+ : `${from} -. "${context.escapeText(edge.label)}" .-> ${to}`;
75
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@alpacakit/plan-graph",
3
+ "version": "0.1.0-beta.19",
4
+ "description": "Typed DAG kernel for plan-shaped graphs.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "types": "./dist/index.d.ts",
14
+ "files": [
15
+ "dist",
16
+ "README*.md",
17
+ "LICENSE"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public",
21
+ "registry": "https://registry.npmjs.org/"
22
+ },
23
+ "dependencies": {
24
+ "immer": "^11.1.8",
25
+ "zod": "^4.3.6",
26
+ "@alpacakit/core": "0.1.0-beta.19"
27
+ },
28
+ "devDependencies": {
29
+ "typescript": "^5.9.3",
30
+ "vitest": "^4.0.18"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc -p tsconfig.build.json",
34
+ "typecheck": "tsc -p tsconfig.json --noEmit",
35
+ "test": "vitest run"
36
+ }
37
+ }