cgdl-lib 0.2.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +251 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/model/CGGraph.d.ts +59 -0
  8. package/dist/model/CGGraph.d.ts.map +1 -0
  9. package/dist/model/CGGraph.js +156 -0
  10. package/dist/model/CGGraph.js.map +1 -0
  11. package/dist/model/CGNode.d.ts +45 -0
  12. package/dist/model/CGNode.d.ts.map +1 -0
  13. package/dist/model/CGNode.js +80 -0
  14. package/dist/model/CGNode.js.map +1 -0
  15. package/dist/model/Line.d.ts +12 -0
  16. package/dist/model/Line.d.ts.map +1 -0
  17. package/dist/model/Line.js +67 -0
  18. package/dist/model/Line.js.map +1 -0
  19. package/dist/reader/Diagnostics.d.ts +16 -0
  20. package/dist/reader/Diagnostics.d.ts.map +1 -0
  21. package/dist/reader/Diagnostics.js +28 -0
  22. package/dist/reader/Diagnostics.js.map +1 -0
  23. package/dist/reader/Parsers.d.ts +39 -0
  24. package/dist/reader/Parsers.d.ts.map +1 -0
  25. package/dist/reader/Parsers.js +69 -0
  26. package/dist/reader/Parsers.js.map +1 -0
  27. package/dist/reader/Reader.d.ts +17 -0
  28. package/dist/reader/Reader.d.ts.map +1 -0
  29. package/dist/reader/Reader.js +131 -0
  30. package/dist/reader/Reader.js.map +1 -0
  31. package/dist/reader/ReaderState.d.ts +13 -0
  32. package/dist/reader/ReaderState.d.ts.map +1 -0
  33. package/dist/reader/ReaderState.js +21 -0
  34. package/dist/reader/ReaderState.js.map +1 -0
  35. package/dist/types.d.ts +28 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +3 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils/normalize.d.ts +15 -0
  40. package/dist/utils/normalize.d.ts.map +1 -0
  41. package/dist/utils/normalize.js +19 -0
  42. package/dist/utils/normalize.js.map +1 -0
  43. package/dist/utils/strings.d.ts +7 -0
  44. package/dist/utils/strings.d.ts.map +1 -0
  45. package/dist/utils/strings.js +19 -0
  46. package/dist/utils/strings.js.map +1 -0
  47. package/dist/utils/validate.d.ts +18 -0
  48. package/dist/utils/validate.d.ts.map +1 -0
  49. package/dist/utils/validate.js +39 -0
  50. package/dist/utils/validate.js.map +1 -0
  51. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2026 Linguistic Agents Ltd.
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,251 @@
1
+ # cgdl-lib
2
+
3
+ A tiny, deliberate TypeScript library that reads plain-text CGDL and builds an in-memory directed graph.
4
+
5
+ cgdl-lib implements only the graph-building core of CGDL:
6
+
7
+ - class selection
8
+ - node selection
9
+ - properties
10
+ - outgoing edges (with fully consistent incoming edges)
11
+ - preservation of non-structural lines as Line { signal, text }
12
+
13
+ Everything else is preserved but never interpreted. Higher layers (protocols, CLIs, editors) can assign meaning to preserved lines later.
14
+
15
+ Status: not published to npm yet. Use from source / GitHub until the first release.
16
+
17
+ ----------------------------------------------------------------
18
+
19
+ WHAT CGDL IS
20
+
21
+ CGDL (Context Graph Description Language) is a line-oriented, hand-editable format for describing small graphs and attached context. It is designed to be friendly to:
22
+
23
+ - hand-editing
24
+ - git diffs
25
+ - sequential reading
26
+ - structured notes that happen to form a graph
27
+
28
+ ----------------------------------------------------------------
29
+
30
+ CORE SYNTAX (IMPLEMENTED)
31
+
32
+ 1) Class directives
33
+
34
+ Open / reopen class:
35
+
36
+ [[ ClassName ]]
37
+
38
+ Effects:
39
+
40
+ - state.currentClass = "ClassName"
41
+ - clears current node selection
42
+
43
+ Close class (enter graph-level class mode):
44
+
45
+ [[ ]]
46
+
47
+ Effects:
48
+
49
+ - state.currentClass = ""
50
+ - clears current node selection
51
+
52
+ Note: Leading whitespace is ignored for directive detection.
53
+
54
+ ----------------------------------------------------------------
55
+
56
+ Node directives
57
+
58
+ Open/select node in the current class:
59
+
60
+ ## Label text
61
+
62
+ Effects:
63
+
64
+ - creates node if needed: (currentClass, "Label text")
65
+ - sets it as current node
66
+
67
+ Close current node only (class stays open):
68
+
69
+ ##
70
+
71
+ Effects:
72
+
73
+ - clears current node selection
74
+
75
+ ----------------------------------------------------------------
76
+
77
+ ## Properties
78
+
79
+ Set property:
80
+
81
+ {} key = value
82
+
83
+ Parsing:
84
+
85
+ - key is trimmed and whitespace-collapsed
86
+ - value is everything after the first = (so = is allowed inside the value)
87
+
88
+ Behavior:
89
+
90
+ - applies to the effective node (see below)
91
+ - overwrites (reassignment semantics): last value wins
92
+
93
+ ----------------------------------------------------------------
94
+
95
+ ## Outgoing edges
96
+
97
+ Outgoing edge:
98
+
99
+ OtherClass:TargetLabel
100
+
101
+ Behavior:
102
+
103
+ - adds an outgoing edge from the effective node
104
+ - always creates the target node if it doesn’t exist yet (stub node)
105
+ - maintains consistent edges:
106
+ - source stores target in _outgoingSet
107
+ - target stores source in _incomingSet
108
+ - duplicate edge adds are ignored (with a warning)
109
+
110
+ ----------------------------------------------------------------
111
+
112
+ EFFECTIVE NODE RULES (IMPORTANT)
113
+
114
+ Commands must still work even when no explicit node is currently open.
115
+
116
+ Definition:
117
+
118
+ - If an explicit node is open (state.currentNodeKey != ""):
119
+ effectiveNode = that node
120
+ - Else:
121
+ effectiveNode = graph.getOrCreateNode(state.currentClass, "")
122
+
123
+ So when no node is selected, properties and edges attach to the class default node:
124
+
125
+ (currentClass, "")
126
+
127
+ Graph-level class
128
+
129
+ After [[ ]], currentClass = "".
130
+
131
+ Nodes opened via ## Label in this state become:
132
+
133
+ ("", "Label")
134
+
135
+ These are graph-level / global feature nodes.
136
+
137
+ ----------------------------------------------------------------
138
+
139
+ UNORDERED-BY-DESIGN
140
+
141
+ Graph node sets are unordered by design. cgdl-lib intentionally does not preserve insertion order.
142
+
143
+ Do not write tests or logic that depends on iteration order of nodes or edges.
144
+
145
+ ----------------------------------------------------------------
146
+
147
+ LINE PRESERVATION AND 2-CHAR SIGNALS (FROZEN RULE)
148
+
149
+ Non-structural lines are preserved inside the current node as:
150
+
151
+ Line { signal: string, text: string }
152
+
153
+ Signal extraction:
154
+
155
+ 1. Ignore leading whitespace for detection.
156
+ 2. If the first two non-whitespace characters are BOTH punctuation,
157
+ 3. AND neither is one of: - , ' , _
158
+ 4. Then:
159
+ signal = those 2 chars
160
+ text = the rest (trimOne)
161
+ 5. Otherwise:
162
+ signal = ""
163
+ text = left-trimmed line
164
+
165
+ Notes:
166
+
167
+ - '-' and "'" are treated as “word-ish” and never count as command punctuation.
168
+ - whitespace cannot be part of a command.
169
+
170
+ Examples:
171
+
172
+ - "{} country = France" -> signal "{}"
173
+ - "!! hello" -> signal "!!"
174
+ - "-> something" -> not a signal (contains '-') -> signal ""
175
+ - "'# foo" -> not a signal (contains "'") -> signal ""
176
+ - "+-" at start -> not a signal (contains '-') -> signal ""
177
+
178
+ Text normalization:
179
+
180
+ - display normalization collapses whitespace runs and trims
181
+ - keying normalization lowercases
182
+
183
+ ----------------------------------------------------------------
184
+
185
+ API
186
+
187
+ readText(text: string)
188
+
189
+ Parses full text and returns:
190
+
191
+ - graph
192
+ - state (incremental reader state)
193
+ - diagnostics (warnings/errors)
194
+
195
+ readLine(graph, state, diagnostics, rawLine, lineNo)
196
+
197
+ Incremental parser for editor / streaming scenarios:
198
+
199
+ - updates graph and state
200
+ - appends warnings/errors to diagnostics
201
+
202
+ Diagnostics store:
203
+
204
+ - warnings: { lineNo, message }[]
205
+ - errors: { lineNo, message }[]
206
+
207
+ ----------------------------------------------------------------
208
+
209
+ INCREMENTAL PARSING EXAMPLE
210
+
211
+ import { CGGraph } from "../src/model/CGGraph";
212
+ import { ReaderState } from "../src/reader/ReaderState";
213
+ import { Diagnostics } from "../src/reader/Diagnostics";
214
+ import { readLine } from "../src/reader/Reader";
215
+
216
+ const graph = new CGGraph();
217
+ const state = new ReaderState();
218
+ const diagnostics = new Diagnostics();
219
+
220
+ const lines = [
221
+ "[[ Places ]]",
222
+ "## Paris",
223
+ "{} country = France",
224
+ "Food:Croissant",
225
+ "##",
226
+ "## Lyon",
227
+ "{} country = France",
228
+ ];
229
+
230
+ lines.forEach((rawLine, i) => {
231
+ readLine(graph, state, diagnostics, rawLine, i + 1);
232
+ });
233
+
234
+ console.log(graph);
235
+ console.log(diagnostics);
236
+
237
+ ----------------------------------------------------------------
238
+
239
+ DEVELOPMENT
240
+
241
+ Tests (vitest):
242
+ npm test
243
+
244
+ Build:
245
+ npm run build
246
+
247
+ ----------------------------------------------------------------
248
+
249
+ LICENSE
250
+
251
+ MIT (see LICENSE).
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Graph storage:
3
+ * - nodes: Map<NodeKey, CGNode>
4
+ *
5
+ * Identity is (ClassName, Label) => NodeKey = norm(class)::norm(label)
6
+ * NOTE: CGDL node sets are unordered by design, so we do NOT maintain insertion order.
7
+ */
8
+ import type { NodeKey } from "../types";
9
+ import { CGNode } from "./CGNode";
10
+ /**
11
+ * In-memory container for a CGDL graph.
12
+ * Stores nodes by canonical NodeKey.
13
+ * Nodes are created/merged on demand via getOrCreateNode.
14
+ * Unordered by design — no insertion order preserved.
15
+ */
16
+ export declare class CGGraph {
17
+ readonly nodes: Map<NodeKey, CGNode>;
18
+ makeNodeKey(className: string, label: string): NodeKey;
19
+ getNodeByKey(key: NodeKey): CGNode | undefined;
20
+ getOrCreateNode(className: string, label: string): CGNode;
21
+ /**
22
+ * Deletes a node and cleans all connected edges.
23
+ * Returns true if the node existed and was removed.
24
+ */
25
+ deleteNode(className: string, label: string): boolean;
26
+ /**
27
+ * Adds a specific outgoing edge from source to target.
28
+ * Returns true if the edge did not exist and was added.
29
+ */
30
+ addEdge(sourceClass: string, sourceLabel: string, targetClass: string, targetLabel: string): boolean;
31
+ /**
32
+ * Deletes a specific outgoing edge from source to target.
33
+ * Returns true if the edge existed and was removed.
34
+ */
35
+ deleteEdge(sourceClass: string, sourceLabel: string, targetClass: string, targetLabel: string): boolean;
36
+ /**
37
+ * Parses a NodeKey "cls::label" into its normalized parts.
38
+ * Both parts are already normalized, because NodeKey is canonical.
39
+ */
40
+ parseNodeKey(key: NodeKey): {
41
+ cls: string;
42
+ label: string;
43
+ };
44
+ /**
45
+ * Deterministic CGDL-like dump:
46
+ * - Nodes sorted by canonical key (stable for testing/debug).
47
+ * - Emits [[ Class ]] blocks and ## Label lines.
48
+ * - Properties emitted as: {} KEY = value (KEY uppercased)
49
+ * - Edges emitted as: TargetClass:TargetLabel
50
+ *
51
+ * Notes:
52
+ * - Uses display names stored on nodes (classNameDisplay/labelDisplay) so output matches
53
+ * the canonical “first-seen” casing/spaces you want to keep.
54
+ * - Edge targets are dumped using canonical node display if the target exists;
55
+ * otherwise falls back to parsed key parts.
56
+ */
57
+ toLinesCgdl(): string[];
58
+ }
59
+ //# sourceMappingURL=CGGraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CGGraph.d.ts","sourceRoot":"","sources":["../../src/model/CGGraph.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC;;;;;GAKG;AACH,qBAAa,OAAO;IAClB,SAAgB,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAa;IAEjD,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAItD,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IAI9C,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAoBhE;;;OAGG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAoC5D;;;OAGG;IAEI,OAAO,CACZ,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EACxC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GACvC,OAAO;IAcV;;;OAGG;IACI,UAAU,CACf,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EACxC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GACvC,OAAO;IAeV;;;OAGG;IACI,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAMjE;;;;;;;;;;;;OAYG;IACI,WAAW,IAAI,MAAM,EAAE;CAkD/B"}
@@ -0,0 +1,156 @@
1
+ // src/model/CGGraph.ts
2
+ import { normalizeDisplay, normalizeKeyPart } from "../utils/normalize";
3
+ import { CGNode } from "./CGNode";
4
+ /**
5
+ * In-memory container for a CGDL graph.
6
+ * Stores nodes by canonical NodeKey.
7
+ * Nodes are created/merged on demand via getOrCreateNode.
8
+ * Unordered by design — no insertion order preserved.
9
+ */
10
+ export class CGGraph {
11
+ nodes = new Map();
12
+ makeNodeKey(className, label) {
13
+ return `${normalizeKeyPart(className)}::${normalizeKeyPart(label)}`;
14
+ }
15
+ getNodeByKey(key) {
16
+ return this.nodes.get(key);
17
+ }
18
+ getOrCreateNode(className, label) {
19
+ const key = this.makeNodeKey(className, label);
20
+ const existing = this.nodes.get(key);
21
+ if (existing) {
22
+ existing.refreshDisplay(normalizeDisplay(className), normalizeDisplay(label));
23
+ return existing;
24
+ }
25
+ const node = new CGNode({
26
+ key,
27
+ classNameDisplay: normalizeDisplay(className),
28
+ labelDisplay: normalizeDisplay(label),
29
+ });
30
+ this.nodes.set(key, node);
31
+ return node;
32
+ }
33
+ /**
34
+ * Deletes a node and cleans all connected edges.
35
+ * Returns true if the node existed and was removed.
36
+ */
37
+ deleteNode(className, label) {
38
+ const key = this.makeNodeKey(className, label);
39
+ const node = this.nodes.get(key);
40
+ if (!node)
41
+ return false;
42
+ // Clean incoming edges (sources pointing TO this node)
43
+ for (const sourceKey of Array.from(node._incomingSet)) {
44
+ const source = this.nodes.get(sourceKey);
45
+ if (source) {
46
+ source.removeOutgoing(className, label);
47
+ }
48
+ }
49
+ // Clean outgoing edges (targets this node points TO)
50
+ for (const targetKey of Array.from(node._outgoingSet)) {
51
+ const target = this.nodes.get(targetKey);
52
+ if (target) {
53
+ target.removeIncoming(className, label);
54
+ }
55
+ }
56
+ // Optional: drop references from the node object itself
57
+ node._incomingSet.clear();
58
+ node._outgoingSet.clear();
59
+ this.nodes.delete(key);
60
+ return true;
61
+ }
62
+ /**
63
+ * Adds a specific outgoing edge from source to target.
64
+ * Returns true if the edge did not exist and was added.
65
+ */
66
+ addEdge(sourceClass, sourceLabel, targetClass, targetLabel) {
67
+ const source = this.getOrCreateNode(sourceClass, sourceLabel);
68
+ const target = this.getOrCreateNode(targetClass, targetLabel);
69
+ const inserted = source.addOutgoing(targetClass, targetLabel);
70
+ if (!inserted)
71
+ return false;
72
+ target.addIncoming(sourceClass, sourceLabel);
73
+ return true;
74
+ }
75
+ /**
76
+ * Deletes a specific outgoing edge from source to target.
77
+ * Returns true if the edge existed and was removed.
78
+ */
79
+ deleteEdge(sourceClass, sourceLabel, targetClass, targetLabel) {
80
+ const source = this.nodes.get(this.makeNodeKey(sourceClass, sourceLabel));
81
+ if (!source || !source.removeOutgoing(targetClass, targetLabel))
82
+ return false;
83
+ const target = this.nodes.get(this.makeNodeKey(targetClass, targetLabel));
84
+ if (target) {
85
+ target.removeIncoming(sourceClass, sourceLabel);
86
+ }
87
+ return true;
88
+ }
89
+ /**
90
+ * Parses a NodeKey "cls::label" into its normalized parts.
91
+ * Both parts are already normalized, because NodeKey is canonical.
92
+ */
93
+ parseNodeKey(key) {
94
+ const i = key.indexOf("::");
95
+ if (i < 0)
96
+ return { cls: "", label: key };
97
+ return { cls: key.slice(0, i), label: key.slice(i + 2) };
98
+ }
99
+ /**
100
+ * Deterministic CGDL-like dump:
101
+ * - Nodes sorted by canonical key (stable for testing/debug).
102
+ * - Emits [[ Class ]] blocks and ## Label lines.
103
+ * - Properties emitted as: {} KEY = value (KEY uppercased)
104
+ * - Edges emitted as: TargetClass:TargetLabel
105
+ *
106
+ * Notes:
107
+ * - Uses display names stored on nodes (classNameDisplay/labelDisplay) so output matches
108
+ * the canonical “first-seen” casing/spaces you want to keep.
109
+ * - Edge targets are dumped using canonical node display if the target exists;
110
+ * otherwise falls back to parsed key parts.
111
+ */
112
+ toLinesCgdl() {
113
+ const out = [];
114
+ const nodeKeys = Array.from(this.nodes.keys()).sort();
115
+ let currentClassDisplay = null;
116
+ for (const key of nodeKeys) {
117
+ const node = this.nodes.get(key);
118
+ const clsDisp = node.classNameDisplay;
119
+ const labelDisp = node.labelDisplay;
120
+ // Emit class header when class changes (including graph-level class "")
121
+ if (currentClassDisplay === null || currentClassDisplay !== clsDisp) {
122
+ currentClassDisplay = clsDisp;
123
+ out.push(`[[ ${clsDisp} ]]`.trim()); // if clsDisp == "" -> "[[]]" after trim
124
+ }
125
+ // Emit node header
126
+ out.push(`## ${labelDisp}`.trim()); // if labelDisp == "" -> "##" after trim
127
+ // Properties: stable, key uppercased in output
128
+ const props = Array.from(node.properties.entries()).sort(([a], [b]) => a.localeCompare(b));
129
+ for (const [k, v] of props) {
130
+ out.push(`{} ${k.toUpperCase()} = ${v}`);
131
+ }
132
+ // Outgoing edges: stable by target key, but display using target node's canonical display if present
133
+ const outs = Array.from(node._outgoingSet.values()).sort();
134
+ for (const targetKey of outs) {
135
+ const target = this.nodes.get(targetKey);
136
+ if (target) {
137
+ out.push(`${target.classNameDisplay}:${target.labelDisplay}`);
138
+ }
139
+ else {
140
+ // Fallback: derive from key if node missing (should be rare in your design)
141
+ const parsed = this.parseNodeKey(targetKey);
142
+ out.push(`${parsed.cls}:${parsed.label}`);
143
+ }
144
+ }
145
+ // Preserved lines (optional): keep in stored order, reconstruct as close as possible
146
+ for (const l of node.lines) {
147
+ if (l.signal)
148
+ out.push(`${l.signal} ${l.text}`.trimEnd());
149
+ else
150
+ out.push(`${l.text}`.trimEnd());
151
+ }
152
+ }
153
+ return out;
154
+ }
155
+ }
156
+ //# sourceMappingURL=CGGraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CGGraph.js","sourceRoot":"","sources":["../../src/model/CGGraph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Node data:
3
+ * - properties overwrite (reassignment)
4
+ * - edges de-dup (duplicate adds warn; stored once)
5
+ * - lines preserved as Line{signal,text}
6
+ */
7
+ import type { NodeKey } from "../types";
8
+ import { Line } from "./Line";
9
+ export declare class CGNode {
10
+ readonly key: NodeKey;
11
+ classNameDisplay: string;
12
+ labelDisplay: string;
13
+ readonly properties: Map<string, string>;
14
+ readonly _outgoingSet: Set<string>;
15
+ readonly _incomingSet: Set<string>;
16
+ readonly lines: Line[];
17
+ constructor(args: {
18
+ key: NodeKey;
19
+ classNameDisplay: string;
20
+ labelDisplay: string;
21
+ });
22
+ refreshDisplay(className: string, label: string): void;
23
+ setProperty(key: string, value: string): void;
24
+ /**
25
+ * Returns true if inserted; false if duplicate.
26
+ */
27
+ addOutgoing(targetClass: string, targetLabel: string): boolean;
28
+ /**
29
+ * Returns true if inserted; false if duplicate.
30
+ */
31
+ addIncoming(sourceClass: string, sourceLabel: string): boolean;
32
+ addLine(line: Line): void;
33
+ /**
34
+ * Removes a specific outgoing edge.
35
+ * Returns true if the edge existed and was removed.
36
+ */
37
+ removeOutgoing(targetClass: string, targetLabel: string): boolean;
38
+ /**
39
+ * Removes a specific incoming edge.
40
+ * Returns true if the edge existed and was removed.
41
+ */
42
+ removeIncoming(sourceClass: string, sourceLabel: string): boolean;
43
+ private edgeKey;
44
+ }
45
+ //# sourceMappingURL=CGNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CGNode.d.ts","sourceRoot":"","sources":["../../src/model/CGNode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,qBAAa,MAAM;IAEjB,SAAgB,GAAG,EAAE,OAAO,CAAC;IAGtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IAG5B,SAAgB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAE5D,SAAgB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IACtD,SAAgB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAGtD,SAAgB,KAAK,EAAE,IAAI,EAAE,CAAM;gBAEhB,IAAI,EAAE;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE;IAMlF,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKtD,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpD;;OAEG;IACI,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAWrE;;OAEG;IACI,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAY9D,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAKhC;;;OAGG;IACI,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAWxE;;;OAGG;IACI,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IASxE,OAAO,CAAC,OAAO;CAGhB"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Node data:
3
+ * - properties overwrite (reassignment)
4
+ * - edges de-dup (duplicate adds warn; stored once)
5
+ * - lines preserved as Line{signal,text}
6
+ */
7
+ import { normalizeDisplay, normalizeKeyPart } from "../utils/normalize";
8
+ export class CGNode {
9
+ key;
10
+ // Display (preserve case, whitespace collapsed)
11
+ classNameDisplay;
12
+ labelDisplay;
13
+ // Properties: overwrite semantics.
14
+ properties = new Map();
15
+ _outgoingSet = new Set(); // stores TARGET node keys (to)
16
+ _incomingSet = new Set(); // stores SOURCE node keys (from)
17
+ // Non-structural lines inside the node.
18
+ lines = [];
19
+ constructor(args) {
20
+ this.key = args.key;
21
+ this.classNameDisplay = args.classNameDisplay;
22
+ this.labelDisplay = args.labelDisplay;
23
+ }
24
+ refreshDisplay(className, label) {
25
+ this.classNameDisplay = normalizeDisplay(className);
26
+ this.labelDisplay = normalizeDisplay(label);
27
+ }
28
+ setProperty(key, value) {
29
+ this.properties.set(key, value);
30
+ }
31
+ /**
32
+ * Returns true if inserted; false if duplicate.
33
+ */
34
+ addOutgoing(targetClass, targetLabel) {
35
+ const k = this.edgeKey(targetClass, targetLabel);
36
+ if (this._outgoingSet.has(k))
37
+ return false;
38
+ this._outgoingSet.add(k);
39
+ return true;
40
+ }
41
+ /**
42
+ * Returns true if inserted; false if duplicate.
43
+ */
44
+ addIncoming(sourceClass, sourceLabel) {
45
+ const k = this.edgeKey(sourceClass, sourceLabel);
46
+ if (this._incomingSet.has(k))
47
+ return false;
48
+ this._incomingSet.add(k);
49
+ return true;
50
+ }
51
+ addLine(line) {
52
+ this.lines.push(line);
53
+ }
54
+ /**
55
+ * Removes a specific outgoing edge.
56
+ * Returns true if the edge existed and was removed.
57
+ */
58
+ removeOutgoing(targetClass, targetLabel) {
59
+ const k = this.edgeKey(targetClass, targetLabel);
60
+ if (!this._outgoingSet.has(k))
61
+ return false;
62
+ this._outgoingSet.delete(k);
63
+ return true;
64
+ }
65
+ /**
66
+ * Removes a specific incoming edge.
67
+ * Returns true if the edge existed and was removed.
68
+ */
69
+ removeIncoming(sourceClass, sourceLabel) {
70
+ const k = this.edgeKey(sourceClass, sourceLabel);
71
+ if (!this._incomingSet.has(k))
72
+ return false;
73
+ this._incomingSet.delete(k);
74
+ return true;
75
+ }
76
+ edgeKey(cls, label) {
77
+ return `${normalizeKeyPart(cls)}::${normalizeKeyPart(label)}`;
78
+ }
79
+ }
80
+ //# sourceMappingURL=CGNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CGNode.js","sourceRoot":"","sources":["../../src/model/CGNode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare class Line {
2
+ readonly signal: string;
3
+ readonly text: string;
4
+ constructor(signal: string, text: string);
5
+ static parse(rawLine: string): Line;
6
+ static splitSignal(rawLine: string): {
7
+ signal: string;
8
+ text: string;
9
+ };
10
+ private static isCommandPunct;
11
+ }
12
+ //# sourceMappingURL=Line.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Line.d.ts","sourceRoot":"","sources":["../../src/model/Line.ts"],"names":[],"mappings":"AAeA,qBAAa,IAAI;IACf,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;WAUjC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;WAQ5B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAuB5E,OAAO,CAAC,MAAM,CAAC,cAAc;CAc9B"}