lispgram 0.10.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/README.md ADDED
@@ -0,0 +1,326 @@
1
+ # lispgram
2
+
3
+ `lispgram` is a small JavaScript package that gives you:
4
+
5
+ - a user-facing lispy surface language
6
+ - a compiler from that surface language into NCF
7
+ - a lightweight SVG visualizer backed by the constraint layout engine that can render either Lispgram source or raw NCF
8
+
9
+ The public compiler now has three explicit syntaxes:
10
+
11
+ ```text
12
+ Lispgram surface human-friendly input
13
+ Semantic core official tiny fact language: node, arrow, contains
14
+ NCF visualization-oriented graph syntax
15
+ ```
16
+
17
+ It also exposes optional interpretations of the semantic core. The first is the normalized tree interpretation, which derives a single-owner containment tree using a generated root and least-common-ancestor ownership for arrows.
18
+
19
+ NCF remains the rendering representation. Author-facing source compiles through the semantic core into:
20
+
21
+ ```lisp
22
+ (cy
23
+ (nodes ...)
24
+ (edges ...))
25
+ ```
26
+
27
+ ## Public npm surface
28
+
29
+ The published package intentionally exposes only the author-facing API:
30
+
31
+ ```js
32
+ import lispgram from "lispgram";
33
+ import { parseDocument, compileLispgram, toNCF, toNCFDoc, toLayerSexp } from "lispgram/surface";
34
+ import { render, initialize, createDiagramSvg } from "lispgram/layout";
35
+ import { diagram, registerDiagram } from "lispgram/interaction";
36
+ ```
37
+
38
+ The package export map is limited to:
39
+
40
+ ```text
41
+ lispgram
42
+ lispgram/surface
43
+ lispgram/layout
44
+ lispgram/interaction
45
+ lispgram/package.json
46
+ ```
47
+
48
+ Internal layer modules are not public API and are not exported as package subpaths. The npm package still exposes normal runtime functionality through the public surface, layout, and interaction entry points, including layer translation output for devtools via `toLayerSexp()`.
49
+
50
+ JavaScript packages cannot fully prevent reverse engineering of code that runs on the client or is installed locally. The package boundary therefore focuses on minimizing the supported import surface, excluding examples/tests/devtools and maintainer docs from npm, and shipping only the grammar/layout authoring docs needed by package consumers.
51
+
52
+ ## Supported surface forms
53
+
54
+ ```lispgram
55
+ ; initialize a node
56
+ (P)
57
+
58
+ ; initialize a node with a label
59
+ (P{hi})
60
+
61
+ ; initialize a node with label plus fields
62
+ (P{Person { color blue rank 2 }})
63
+
64
+ ; fully explicit data field map
65
+ (P{{ label Person color blue rank 2 }})
66
+
67
+ ; parent/child relationships
68
+ (X Y Z)
69
+ (X Y (Z P))
70
+ (X (Y (Z P)))
71
+
72
+ ; arrows
73
+ (-> e A B)
74
+ (-> e{hi} A B)
75
+ (-> e{maps { color purple weight 2 }} A B)
76
+
77
+ ; fan-out
78
+ (-> e A [B C D])
79
+
80
+ ; fan-in
81
+ (-> e [A B C] D)
82
+ ```
83
+
84
+ ## What this starter implements
85
+
86
+ - nodes and arrows with optional `{label}` suffixes and richer `{label { key value ... }}` / `{{ key value ... }}` field maps
87
+ - parent/child trees compiled to `(@parent X)`
88
+ - arrows compiled as NCF arrow carrier nodes with:
89
+ - `(@class "arrow")`
90
+ - `(@class "arrowFrom")`
91
+ - `(@class "arrowTo")`
92
+ - fan-in / fan-out expansion into multiple arrows that keep the same visible label
93
+ - an official semantic core grammar with only `node`, `arrow`, and `contains`
94
+ - semantic core parsing/emitting for external rule or constraint systems
95
+ - a normalized tree interpretation for derived ownership/layout
96
+ - containment of arrows as well as object nodes in the semantic core
97
+ - raw NCF passthrough
98
+ - browser auto-initialization for `<pre class="lispgram">...</pre>` blocks
99
+ - heuristic SVG routing for parallel, anti-parallel, and higher-order arrows
100
+ - compound/container labels rendered only in the header band
101
+
102
+ ## Install
103
+
104
+ ```bash
105
+ npm install lispgram
106
+ ```
107
+
108
+ ## Browser usage
109
+
110
+ ```html
111
+ <pre class="lispgram">
112
+ (Y X)
113
+ (-> f A B)
114
+ (-> g B A)
115
+ (-> h X Y)
116
+ </pre>
117
+
118
+ <script type="module">
119
+ import lispgram from "lispgram";
120
+ lispgram.initialize({
121
+ startOnLoad: true,
122
+ showArrowGlyphs: true,
123
+ clickToFocus: true
124
+ });
125
+ </script>
126
+ ```
127
+
128
+ ## Library usage
129
+
130
+ ```js
131
+ import lispgram from "lispgram";
132
+
133
+ const source = `
134
+ (Y X)
135
+ (-> f A B)
136
+ (-> g B A)
137
+ (-> h X Y)
138
+ `;
139
+
140
+ const ncfString = lispgram.toNCF(source);
141
+ const ncfDoc = lispgram.toNCFDoc(source);
142
+ ```
143
+
144
+ Render into a DOM node:
145
+
146
+ ```js
147
+ import { render } from "lispgram";
148
+
149
+ render(document.querySelector("#app"), `
150
+ (P A B)
151
+ (-> left A B)
152
+ (-> right B A)
153
+ `);
154
+ ```
155
+
156
+
157
+ ## Interactive diagrams
158
+
159
+ Interactivity is attached from JavaScript, not from Lispgram syntax. Give a render a stable `diagramId`, or set `data-lispgram-diagram` on an auto-rendered `<pre>`, then select semantic elements by their normalized `data` fields.
160
+
161
+ ```js
162
+ import { render, diagram } from "lispgram";
163
+
164
+ render(document.querySelector("#app"), `
165
+ (lg-core
166
+ (node (A (@data clickable true info "Node A")))
167
+ (node B)
168
+ (arrow (f (@data clickable true info "A to B")) A B))
169
+ `, { diagramId: "P" });
170
+
171
+ diagram("P")
172
+ .select((elem) => elem.data.clickable === true)
173
+ .addonclick((elem) => alert(elem.data.info));
174
+ ```
175
+
176
+ Each selected `elem` describes the semantic cell rather than the raw SVG node:
177
+
178
+ ```js
179
+ {
180
+ id: "f",
181
+ type: "arrow", // or "node"
182
+ kind: "arrow",
183
+ data: { info: "A to B" },
184
+ source: "A",
185
+ target: "B",
186
+ parent: null,
187
+ elements: [/* generated SVG path/label/glyph elements */]
188
+ }
189
+ ```
190
+
191
+ You can also select with a small object matcher:
192
+
193
+ ```js
194
+ diagram("P")
195
+ .select({ type: "arrow", data: { clickable: true } })
196
+ .addOnClick((elem) => console.log(elem.source, elem.target));
197
+ ```
198
+
199
+ For auto-rendered diagrams:
200
+
201
+ ```html
202
+ <pre class="lispgram" data-lispgram-diagram="P">
203
+ (A{{ clickable true info "Node A" }} B)
204
+ </pre>
205
+ ```
206
+
207
+ Interaction behavior is available through `lispgram/interaction` and through the default click-to-focus SVG renderer.
208
+
209
+ ## API
210
+
211
+ The public API is intentionally small but includes the normal runtime features needed by the standalone devtool. Internal solver and layer implementation modules are not exported by the package.
212
+
213
+ ### Surface entry point
214
+
215
+ ```js
216
+ import { parseDocument, compileLispgram, toNCFDoc, toNCF, sourceToSemanticCore, toLayerSexp } from "lispgram/surface";
217
+ ```
218
+
219
+ `parseDocument(source)` parses Lispgram surface syntax. `compileLispgram(source)` returns the parsed AST, surface facts, semantic core, and normalized NCF document. `toNCFDoc(source)` accepts Lispgram surface, wrapped semantic core, or raw NCF and returns the normalized document object. `toNCF(source)` emits textual NCF. `sourceToSemanticCore(source)` returns the tiny semantic-core fact model for Lispgram or wrapped semantic-core input. `toLayerSexp(source)` returns author/devtool layer text including Surface AST, Surface Facts, Semantic Core, Normalized Tree, NCF Model, and NCF Text when those layers are available for the input form.
220
+
221
+ ### Layout entry point
222
+
223
+ ```js
224
+ import { render, renderElement, initialize, createDiagramSvg } from "lispgram/layout";
225
+ ```
226
+
227
+ `render(target, source, options?)` renders Lispgram or NCF into a DOM target. `renderElement(sourceElement, options?)` renders one source element. `initialize(options?)` auto-renders matching elements such as `<pre class="lispgram">`. `createDiagramSvg(doc, options?)` renders an already-normalized NCF document into an SVG element.
228
+
229
+ ### Interaction entry point
230
+
231
+ ```js
232
+ import { diagram, registerDiagram, unregisterDiagram, listDiagrams } from "lispgram/interaction";
233
+ ```
234
+
235
+ `diagram(id?)` returns an interactive diagram controller. Controllers support `.select(predicateOrMatcher)`, `.selectAll()`, `.get(id)`, `.on(eventName, selector, handler)`, `.addOnClick(selector, handler)`, and `.clearInteractions()`. `registerDiagram()` registers an already-rendered document/SVG pair; `render()` and `initialize()` call it automatically.
236
+
237
+ ### Root entry point
238
+
239
+ ```js
240
+ import lispgram, { render, toNCF } from "lispgram";
241
+ ```
242
+
243
+ The root entry point re-exports the public surface, layout, and interaction APIs only. It does not export internal layer emitters, solver internals, or devtool diagnostic helpers.
244
+
245
+ ## Notes
246
+
247
+ This package is intentionally small and readable. It is a good base for:
248
+
249
+ - improving the layout engine
250
+ - extending the surface language
251
+ - integrating external rule/constraint systems over the semantic core
252
+ - adding richer styling directives
253
+ - expanding support for higher-order arrows and editor UX
254
+
255
+
256
+ ## Dev visualizer
257
+
258
+ The repository includes a browser-based dev tool with Lispgram + raw NCF input, compiled/normalized NCF output, orthogonal routing, wiring overlay, arrow-node glyphs, click focus, zoom, and fit-to-view.
259
+
260
+ Run it from the repo with:
261
+
262
+ ```bash
263
+ npm run dev:visualizer
264
+ ```
265
+
266
+ Then open:
267
+
268
+ ```
269
+ http://localhost:4173/examples/devtool.html
270
+ ```
271
+
272
+ The dev tool accepts Lispgram surface syntax, wrapped semantic core `(lg-core ...)`, or raw NCF. When the input is Lispgram, it compiles it through the semantic core first and shows both the semantic core and normalized NCF in the side panel.
273
+
274
+ The repo devtool can use source-only helpers during development, while the standalone devtool uses the public `toLayerSexp()` API from the npm package.
275
+
276
+ ## Development
277
+
278
+ ```bash
279
+ npm test
280
+ ```
281
+
282
+
283
+ ## Focus behavior
284
+
285
+ When `clickToFocus` is enabled, clicking a node, compound/container, or arrow focuses that element within its own diagram. The focused element, its incident arrows, and immediate source/target nodes or arrows stay prominent while unrelated elements dim. This includes arrow-between-arrow routes, where the source and target arrows are treated as immediate endpoints. `clickToFocus` defaults to `true`; set `data-lispgram-click-focus="false"` or pass `clickToFocus: false` to disable it.
286
+
287
+ Click hit-testing uses a transparent interaction layer above the rendered diagram. Ordinary nodes are given priority over arrows, arrows over container interiors, and deeper containers over their ancestors. This keeps large ancestor containers clickable without letting them steal clicks from nested containers such as `BuildSystem`, `ExternalDependencies`, or `GuileBinding`.
288
+
289
+ ## Demo
290
+
291
+ go to repo root directory
292
+
293
+ ```bash
294
+ python -m http.server
295
+ ```
296
+
297
+ navigate to examples/basic.html in browser
298
+
299
+ ## Browser script Drop-in use
300
+
301
+ ```html
302
+
303
+ <pre class="lispgram">
304
+ (lispgram
305
+ (A)
306
+ (-> e X Y)
307
+ )
308
+ </pre>
309
+ <script type="module">
310
+ import lispgram from "https://unpkg.com/lispgram@latest/dist/index.js";
311
+ lispgram.initialize({
312
+ startOnLoad: true,
313
+ showArrowGlyphs: true,
314
+ clickToFocus: true,
315
+ arrowGlyphRadius: 5.75
316
+ });
317
+ </script>
318
+ ```
319
+
320
+ The standalone devtool at `examples/devtool-standalone.html` is static-site friendly: it dynamically imports `https://unpkg.com/lispgram@latest/dist/index.js` and uses public APIs, including `toLayerSexp()`, so you can host that single HTML file independently after publishing the package to npm.
321
+
322
+ ## Constraint layout foundation
323
+
324
+ This version uses the constraint-layout engine in `src/layers/08-constraint-layout` as the main SVG layout backend. The default small-core inference now projects arrows through containment, so arrows from leaves in one subtree to leaves in another subtree can compact their ancestor containers into readable columns instead of long vertical stacks. The small Lispgram core remains the preferred authoring surface: tree forms and ordinary arrows are inferred into containment scopes, self-loops, parallel/anti-parallel lanes, arrow-to-arrow route strata, and fallback rank constraints. The engine models nodes and containers as boxes, islands as first-class layout views, relative constraints as compiler output, and arrows as addressable routes with anchors. Boundary attachments place external source subtrees outside the selected side and then draw rounded orthogonal routes through side-ports. Template `:container` declarations are active visual shells for the template core members. This enables autodetected self loops, arrows between arrows, route dependency strata, curved cone legs, distinct route-to-node anchors, and categorical templates such as product, coproduct, equalizer, pullback, pushout, exponential, and Hasse-style ranked diagrams.
325
+
326
+ Open `examples/constraint-layout-foundation.html` from a source checkout for a browser demo. See `LAYOUT_LANGUAGE.md` for the `$layout` surface syntax. The repository also contains maintainer-oriented layout-engine notes for contributors; those internal docs are not part of the minimal npm runtime surface.