@geml/geml 1.1.1 → 1.4.2
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 -21
- package/README.md +155 -79
- package/codemap/adapters/crg.mjs +120 -109
- package/codemap/adapters/joern.mjs +131 -131
- package/codemap/adapters/scip.mjs +658 -229
- package/codemap/browser-stub.mjs +29 -24
- package/codemap/build.mjs +609 -354
- package/codemap/cross-stack.mjs +303 -0
- package/codemap/detect.mjs +399 -185
- package/codemap/emit.mjs +480 -361
- package/codemap/entries.mjs +129 -0
- package/codemap/exclude.mjs +52 -52
- package/codemap/find.mjs +63 -0
- package/codemap/foldings.mjs +110 -0
- package/codemap/joern-export.sc +83 -83
- package/codemap/mcp-server.mjs +172 -143
- package/codemap/normalize.mjs +0 -0
- package/codemap/recipe-trust.mjs +103 -0
- package/codemap/refresh.mjs +310 -160
- package/codemap/render-all.mjs +64 -64
- package/codemap/serve.mjs +578 -378
- package/codemap/sfc-virtualize.mjs +367 -0
- package/codemap/verify.mjs +148 -126
- package/dist/block-edit.d.ts +1 -0
- package/dist/block-edit.js +112 -0
- package/dist/from-md.js +66 -7
- package/dist/geml.d.ts +2 -1
- package/dist/geml.js +1103 -233
- package/dist/history.js +102 -62
- package/dist/inline.d.ts +2 -1
- package/dist/inline.js +61 -8
- package/dist/render-html.d.ts +3 -0
- package/dist/render-html.js +95 -0
- package/dist/render.d.ts +33 -3
- package/dist/render.js +558 -283
- package/dist/serialize.js +22 -2
- package/dist/table.js +40 -5
- package/dist/to-md.js +4 -0
- package/package.json +62 -58
package/dist/serialize.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// parse(serialize(parse(src))) ≅ parse(src)
|
|
10
10
|
//
|
|
11
11
|
// verified over the conformance corpus by test/roundtrip.test.mjs.
|
|
12
|
-
import { parseInline } from "./inline.js";
|
|
12
|
+
import { META_REF_SRC, parseInline } from "./inline.js";
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
14
|
// Values & attributes (§4)
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
@@ -61,6 +61,26 @@ function serDataValue(v) {
|
|
|
61
61
|
function escText(s) {
|
|
62
62
|
return s.replace(/[\\`*~$\[\]]/g, (c) => "\\" + c);
|
|
63
63
|
}
|
|
64
|
+
// A literal `{{name}}` in a text run would be re-read as a §4 metadata
|
|
65
|
+
// reference by the next document-level parse — a layer serInlines's
|
|
66
|
+
// parseInline check cannot see — so it is escaped unconditionally, in both the
|
|
67
|
+
// lazy and the escalated pass. Applied after escText, which would otherwise
|
|
68
|
+
// escape the inserted backslash itself.
|
|
69
|
+
//
|
|
70
|
+
// The inserted escape must survive interpolate()'s left-to-right `\x`
|
|
71
|
+
// pairing: when the emitted text directly before the reference ends in an ODD
|
|
72
|
+
// run of backslashes, a single inserted `\` would itself be consumed as that
|
|
73
|
+
// run's escapee, re-exposing `{{` — so double it (`\\{`), which pairs as
|
|
74
|
+
// escaped-backslash + escaped-brace and parses back to the same model text.
|
|
75
|
+
const META_REF_G = new RegExp(META_REF_SRC, "g");
|
|
76
|
+
function escMetaRef(s) {
|
|
77
|
+
return s.replace(META_REF_G, (m, _key, offset) => {
|
|
78
|
+
let bs = 0;
|
|
79
|
+
for (let k = offset - 1; k >= 0 && s[k] === "\\"; k--)
|
|
80
|
+
bs++;
|
|
81
|
+
return (bs % 2 === 1 ? "\\\\{" : "\\{") + m.slice(1);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
64
84
|
function longestRun(s, ch) {
|
|
65
85
|
let max = 0;
|
|
66
86
|
let run = 0;
|
|
@@ -91,7 +111,7 @@ function linkDest(n) {
|
|
|
91
111
|
// when the verbatim form does not round-trip.
|
|
92
112
|
function serInline(n, esc) {
|
|
93
113
|
switch (n.type) {
|
|
94
|
-
case "text": return esc ? escText(n.value) : n.value;
|
|
114
|
+
case "text": return escMetaRef(esc ? escText(n.value) : n.value);
|
|
95
115
|
case "emph": return `*${serSeq(n.children, esc)}*`;
|
|
96
116
|
case "strong": return `**${serSeq(n.children, esc)}**`;
|
|
97
117
|
case "strike": return `~~${serSeq(n.children, esc)}~~`;
|
package/dist/table.js
CHANGED
|
@@ -312,10 +312,7 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
312
312
|
const ci = colIndex(name);
|
|
313
313
|
return ci < 0 ? null : cellNum(ci, row);
|
|
314
314
|
};
|
|
315
|
-
const
|
|
316
|
-
const ci = colIndex(name);
|
|
317
|
-
if (ci < 0)
|
|
318
|
-
return null;
|
|
315
|
+
const computeAgg = (fn, ci) => {
|
|
319
316
|
const vals = [];
|
|
320
317
|
for (let r = 0; r < model.rows.length; r++) {
|
|
321
318
|
const v = cellNum(ci, r);
|
|
@@ -336,6 +333,30 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
336
333
|
return Math.max(...vals);
|
|
337
334
|
return null;
|
|
338
335
|
};
|
|
336
|
+
// A given aggregate over a given column is constant across rows, yet the
|
|
337
|
+
// per-row `evalExpr` below used to recompute it with a full-table scan every
|
|
338
|
+
// time — O(R²·M) for a table with R rows and M aggregate uses, so a 5000-row
|
|
339
|
+
// ×100-`sum()` sheet took ~a minute. Memoize each `(fn, column)` result once
|
|
340
|
+
// per formula (`aggReset` clears it). The ONE column whose values genuinely
|
|
341
|
+
// change mid-loop is the column the current formula is writing (`aggBypassCi`)
|
|
342
|
+
// — an aggregate over it is row-dependent, so that one is never cached, which
|
|
343
|
+
// preserves the exact behaviour of in-place / self-referential formulas.
|
|
344
|
+
let aggCache = new Map();
|
|
345
|
+
let aggBypassCi = -1;
|
|
346
|
+
const aggReset = (bypassCi) => { aggCache = new Map(); aggBypassCi = bypassCi; };
|
|
347
|
+
const aggResolve = (fn, name) => {
|
|
348
|
+
const ci = colIndex(name);
|
|
349
|
+
if (ci < 0)
|
|
350
|
+
return null;
|
|
351
|
+
if (ci === aggBypassCi)
|
|
352
|
+
return computeAgg(fn, ci);
|
|
353
|
+
const key = `${fn}:${ci}`;
|
|
354
|
+
if (aggCache.has(key))
|
|
355
|
+
return aggCache.get(key);
|
|
356
|
+
const val = computeAgg(fn, ci);
|
|
357
|
+
aggCache.set(key, val);
|
|
358
|
+
return val;
|
|
359
|
+
};
|
|
339
360
|
// `compute="Name = expr; Name2 = expr2"` — `;`-separated; may also appear as
|
|
340
361
|
// compute, compute2, … Each formula adds/overwrites a per-row column.
|
|
341
362
|
const formulas = Object.entries(attrs)
|
|
@@ -367,6 +388,9 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
367
388
|
columns.push(name);
|
|
368
389
|
ci = columns.length - 1;
|
|
369
390
|
}
|
|
391
|
+
// Fresh aggregate cache per formula; the target column is being written
|
|
392
|
+
// row-by-row so aggregates over it stay uncached.
|
|
393
|
+
aggReset(ci);
|
|
370
394
|
let failed = false;
|
|
371
395
|
for (let r = 0; r < model.rows.length && !failed; r++) {
|
|
372
396
|
try {
|
|
@@ -399,6 +423,9 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
399
423
|
const summary = columns.map(() => ({ text: "", inlines: [] }));
|
|
400
424
|
// In the summary row a bare column has no value: only aggregates resolve.
|
|
401
425
|
const noRow = () => null;
|
|
426
|
+
// No column is mutated while building the summary row, so every aggregate is
|
|
427
|
+
// cacheable against the final table state (no bypass column).
|
|
428
|
+
aggReset(-1);
|
|
402
429
|
for (const s of summaryDecls) {
|
|
403
430
|
const eq = s.indexOf("=");
|
|
404
431
|
if (eq <= 0) {
|
|
@@ -458,7 +485,15 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
458
485
|
diagnostics.push({ severity: "warning", message: `span \`${sd}\` targets a cell outside the table` });
|
|
459
486
|
continue;
|
|
460
487
|
}
|
|
461
|
-
|
|
488
|
+
// A span can never extend past the grid: clamp its extent to the rows/cols
|
|
489
|
+
// actually available from the target cell. Without this, `span="r1c1:9e6x9e6"`
|
|
490
|
+
// makes the renderer's O(rows×cols) coverage sweep hang (DoS). Every row has
|
|
491
|
+
// exactly `columns.length` cells (built above), so the column bound is exact.
|
|
492
|
+
const maxRows = model.rows.length - (sp.row - 1);
|
|
493
|
+
const maxCols = columns.length - (sp.col - 1);
|
|
494
|
+
const rows = Math.max(1, Math.min(sp.rows, maxRows));
|
|
495
|
+
const cols = Math.max(1, Math.min(sp.cols, maxCols));
|
|
496
|
+
cell.span = { rows, cols };
|
|
462
497
|
}
|
|
463
498
|
return { model, diagnostics };
|
|
464
499
|
}
|
package/dist/to-md.js
CHANGED
|
@@ -127,6 +127,10 @@ function typedToMd(b, notes) {
|
|
|
127
127
|
return `[^${b.id}]: ${text}`;
|
|
128
128
|
}
|
|
129
129
|
const inner = (b.children ?? []).map((c) => block(c, notes)).filter(Boolean).join("\n\n");
|
|
130
|
+
// `text` is an addressable prose container, not a callout: its children
|
|
131
|
+
// project as plain paragraphs. Only `note` carries blockquote semantics.
|
|
132
|
+
if (b.type === "text")
|
|
133
|
+
return inner;
|
|
130
134
|
return inner.split("\n").map((l) => (l ? `> ${l}` : ">")).join("\n");
|
|
131
135
|
}
|
|
132
136
|
// raw modes
|
package/package.json
CHANGED
|
@@ -1,58 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@geml/geml",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"publishConfig": {
|
|
5
|
-
"access": "public"
|
|
6
|
-
},
|
|
7
|
-
"description": "
|
|
8
|
-
"type": "module",
|
|
9
|
-
"bin": {
|
|
10
|
-
"geml": "dist/geml.js"
|
|
11
|
-
},
|
|
12
|
-
"main": "dist/geml.js",
|
|
13
|
-
"types": "dist/geml.d.ts",
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"codemap",
|
|
17
|
-
"README.md",
|
|
18
|
-
"LICENSE"
|
|
19
|
-
],
|
|
20
|
-
"engines": {
|
|
21
|
-
"node": ">=
|
|
22
|
-
},
|
|
23
|
-
"keywords": [
|
|
24
|
-
"geml",
|
|
25
|
-
"markup",
|
|
26
|
-
"markdown",
|
|
27
|
-
"parser",
|
|
28
|
-
"cli",
|
|
29
|
-
"document",
|
|
30
|
-
"typed-block",
|
|
31
|
-
"ai",
|
|
32
|
-
"agent"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
"url": "https://github.com/geml-spec/geml
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@geml/geml",
|
|
3
|
+
"version": "1.4.2",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "GEML(General Expressive Markup Language) — one format, two readers. People and AI agents co-write the same document: plain text that stays legible for people, and addressable, verifiable, and versioned for machines. Reference parser, validator, renderer & CLI for GEML.",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"geml": "dist/geml.js"
|
|
11
|
+
},
|
|
12
|
+
"main": "dist/geml.js",
|
|
13
|
+
"types": "dist/geml.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"codemap",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"geml",
|
|
25
|
+
"markup",
|
|
26
|
+
"markdown",
|
|
27
|
+
"parser",
|
|
28
|
+
"cli",
|
|
29
|
+
"document",
|
|
30
|
+
"typed-block",
|
|
31
|
+
"ai",
|
|
32
|
+
"agent",
|
|
33
|
+
"llm",
|
|
34
|
+
"addressable",
|
|
35
|
+
"versioning",
|
|
36
|
+
"docs",
|
|
37
|
+
"code-graph"
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/geml-spec/geml.git",
|
|
42
|
+
"directory": "geml-parser"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/geml-spec/geml#readme",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/geml-spec/geml/issues"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc",
|
|
50
|
+
"test": "tsc && node test/all.mjs",
|
|
51
|
+
"parse": "node dist/geml.js",
|
|
52
|
+
"coverage": "tsc && c8 --all --include=dist/**/*.js --include=codemap/**/*.mjs --reporter=text --reporter=text-summary node test/all.mjs",
|
|
53
|
+
"coverage:check": "tsc && c8 --all --include=dist/**/*.js --include=codemap/**/*.mjs --check-coverage --lines 95 --statements 95 --functions 95 --branches 95 node test/all.mjs",
|
|
54
|
+
"prepublishOnly": "npm run build"
|
|
55
|
+
},
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/node": "^22.19.21",
|
|
59
|
+
"c8": "^10.1.3",
|
|
60
|
+
"typescript": "^5.9.3"
|
|
61
|
+
}
|
|
62
|
+
}
|