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.
- package/LICENSE +21 -0
- package/README.md +251 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/model/CGGraph.d.ts +59 -0
- package/dist/model/CGGraph.d.ts.map +1 -0
- package/dist/model/CGGraph.js +156 -0
- package/dist/model/CGGraph.js.map +1 -0
- package/dist/model/CGNode.d.ts +45 -0
- package/dist/model/CGNode.d.ts.map +1 -0
- package/dist/model/CGNode.js +80 -0
- package/dist/model/CGNode.js.map +1 -0
- package/dist/model/Line.d.ts +12 -0
- package/dist/model/Line.d.ts.map +1 -0
- package/dist/model/Line.js +67 -0
- package/dist/model/Line.js.map +1 -0
- package/dist/reader/Diagnostics.d.ts +16 -0
- package/dist/reader/Diagnostics.d.ts.map +1 -0
- package/dist/reader/Diagnostics.js +28 -0
- package/dist/reader/Diagnostics.js.map +1 -0
- package/dist/reader/Parsers.d.ts +39 -0
- package/dist/reader/Parsers.d.ts.map +1 -0
- package/dist/reader/Parsers.js +69 -0
- package/dist/reader/Parsers.js.map +1 -0
- package/dist/reader/Reader.d.ts +17 -0
- package/dist/reader/Reader.d.ts.map +1 -0
- package/dist/reader/Reader.js +131 -0
- package/dist/reader/Reader.js.map +1 -0
- package/dist/reader/ReaderState.d.ts +13 -0
- package/dist/reader/ReaderState.d.ts.map +1 -0
- package/dist/reader/ReaderState.js +21 -0
- package/dist/reader/ReaderState.js.map +1 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/normalize.d.ts +15 -0
- package/dist/utils/normalize.d.ts.map +1 -0
- package/dist/utils/normalize.js +19 -0
- package/dist/utils/normalize.js.map +1 -0
- package/dist/utils/strings.d.ts +7 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +19 -0
- package/dist/utils/strings.js.map +1 -0
- package/dist/utils/validate.d.ts +18 -0
- package/dist/utils/validate.d.ts.map +1 -0
- package/dist/utils/validate.js +39 -0
- package/dist/utils/validate.js.map +1 -0
- 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).
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|