@geml/geml 1.4.6 → 1.5.1
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 +217 -217
- package/codemap/adapters/crg.mjs +120 -120
- package/codemap/adapters/joern.mjs +131 -131
- package/codemap/adapters/scip.mjs +658 -658
- package/codemap/browser-stub.mjs +29 -29
- package/codemap/build.mjs +609 -609
- package/codemap/cross-stack.mjs +303 -303
- package/codemap/detect.mjs +399 -399
- package/codemap/emit.mjs +480 -480
- package/codemap/entries.mjs +129 -129
- package/codemap/exclude.mjs +52 -52
- package/codemap/find.mjs +49 -49
- package/codemap/foldings.mjs +110 -110
- package/codemap/joern-export.sc +83 -83
- package/codemap/mcp-server.mjs +431 -431
- package/codemap/normalize.mjs +275 -275
- package/codemap/recipe-trust.mjs +103 -103
- package/codemap/refresh.mjs +310 -310
- package/codemap/render-all.mjs +77 -64
- package/codemap/serve.mjs +585 -578
- package/codemap/sfc-virtualize.mjs +367 -367
- package/codemap/verify.mjs +148 -148
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +12 -2
- package/dist/geml.d.ts +4 -0
- package/dist/geml.js +653 -156
- package/dist/inline.d.ts +20 -0
- package/dist/inline.js +36 -4
- package/dist/mcp.js +32 -24
- package/dist/render-html.js +35 -35
- package/dist/render.d.ts +19 -0
- package/dist/render.js +486 -182
- package/dist/serialize.js +9 -1
- package/dist/table.d.ts +0 -4
- package/dist/table.js +62 -53
- package/dist/to-md.js +17 -3
- package/package.json +66 -66
package/dist/serialize.js
CHANGED
|
@@ -124,6 +124,7 @@ function serInline(n, esc) {
|
|
|
124
124
|
case "image": return `${serAttrs({ attrs: n.attrs })}`;
|
|
125
125
|
case "link": return `[${serSeq(n.children, esc)}](${linkDest(n)})${serAttrs({ attrs: n.attrs })}`;
|
|
126
126
|
case "autoref": return `[[${n.doc !== undefined ? `${n.doc}#${n.anchor}` : `#${n.anchor}`}]]`;
|
|
127
|
+
case "project": return `![[${n.doc !== undefined ? `${n.doc}#${n.anchor}` : `#${n.anchor}`}]]`;
|
|
127
128
|
case "footnote": return `[^${n.ref}]`;
|
|
128
129
|
}
|
|
129
130
|
}
|
|
@@ -138,7 +139,14 @@ function serInlines(ns) {
|
|
|
138
139
|
const lazy = serSeq(ns, false);
|
|
139
140
|
if (JSON.stringify(parseInline(lazy, 0, { refs: [] })) === JSON.stringify(ns))
|
|
140
141
|
return lazy;
|
|
141
|
-
|
|
142
|
+
const escaped = serSeq(ns, true);
|
|
143
|
+
if (JSON.stringify(parseInline(escaped, 0, { refs: [] })) === JSON.stringify(ns))
|
|
144
|
+
return escaped;
|
|
145
|
+
// Neither form round-trips on its own. The case this exists for: a text run
|
|
146
|
+
// ending in `!` immediately before an auto-reference re-reads as an inline
|
|
147
|
+
// projection (`!` + `[[` is one atom since §5.3), so the bang has to be escaped
|
|
148
|
+
// even though nothing about the text itself is a metacharacter.
|
|
149
|
+
return serSeq(ns, true).replace(/!(?=\[\[)/g, "\\!");
|
|
142
150
|
}
|
|
143
151
|
// ---------------------------------------------------------------------------
|
|
144
152
|
// Blocks
|
package/dist/table.d.ts
CHANGED
package/dist/table.js
CHANGED
|
@@ -127,22 +127,34 @@ function lexExpr(s) {
|
|
|
127
127
|
// Display format: a `[printf]` spec bound to a column/cell name (§6).
|
|
128
128
|
// `FY [%.1f]` → name "FY", fmt "%.1f"; `YoY [%.1f%%]` → "%.1f%%"
|
|
129
129
|
// ---------------------------------------------------------------------------
|
|
130
|
+
// The bracket suffix has to contain a `%` to be a format (§6). Without that
|
|
131
|
+
// test, a column whose own name is bracketed — `[Data] = …` — parses as an
|
|
132
|
+
// empty name plus the format `Data`, and the formula silently targets nothing.
|
|
130
133
|
function splitName(lhs) {
|
|
131
|
-
const m = /^(.*?)\s*\[([^\]]*)\]\s*$/.exec(lhs.trim());
|
|
134
|
+
const m = /^(.*?)\s*\[([^\]]*%[^\]]*)\]\s*$/.exec(lhs.trim());
|
|
132
135
|
let name = (m ? m[1] : lhs).trim();
|
|
133
136
|
if (name.startsWith('"') && name.endsWith('"'))
|
|
134
137
|
name = name.slice(1, -1);
|
|
135
138
|
return m ? { name, fmt: m[2] } : { name };
|
|
136
139
|
}
|
|
140
|
+
// A result IEEE-754 produces but a table cannot hold (§6): `x / 0` is ±∞, `0 / 0`
|
|
141
|
+
// is NaN. The cell keeps no value and displays `-`, which is what a reader sees;
|
|
142
|
+
// naming the cause is the difference between "this row had no data" and "this
|
|
143
|
+
// row divided by zero", so it is said out loud like a substituted cell is.
|
|
144
|
+
const nanMsg = (where, v) => `${where}: ${Number.isNaN(v) ? "result is not a number (0/0)" : "division by zero"}; the cell holds no value and shows \`-\``;
|
|
137
145
|
// Default rendering for an unformatted computed number: drop IEEE-754 display
|
|
138
146
|
// noise (0.1+0.2 → "0.3", sum of 1-dp inputs → "263.6") without altering the
|
|
139
147
|
// stored numeric value.
|
|
140
148
|
function defaultNum(v) {
|
|
149
|
+
if (!isFinite(v))
|
|
150
|
+
return "-";
|
|
141
151
|
return String(parseFloat(v.toPrecision(12)));
|
|
142
152
|
}
|
|
143
153
|
// Minimal printf for a single numeric value: handles %f/%e/%d/%g with optional
|
|
144
154
|
// precision, and `%%` as a literal percent. Width/flags are not padded.
|
|
145
155
|
function applyFormat(fmt, v) {
|
|
156
|
+
if (!isFinite(v))
|
|
157
|
+
return "-";
|
|
146
158
|
return fmt.replace(/%%|%[-+ 0]*\d*(?:\.\d+)?[fFeEgGd]/g, (m) => {
|
|
147
159
|
if (m === "%%")
|
|
148
160
|
return "%";
|
|
@@ -232,24 +244,16 @@ function evalExpr(toks, row, col, agg) {
|
|
|
232
244
|
return v;
|
|
233
245
|
}
|
|
234
246
|
// ---------------------------------------------------------------------------
|
|
235
|
-
// Spans
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
|
-
// Parse `r2c1:2x1` → target cell (1-based row/col over body) + size.
|
|
238
|
-
function parseSpan(s) {
|
|
239
|
-
const m = /^r(\d+)c(\d+):(\d+)x(\d+)$/.exec(s.trim());
|
|
240
|
-
if (!m)
|
|
241
|
-
return null;
|
|
242
|
-
return { row: +m[1], col: +m[2], rows: +m[3], cols: +m[4] };
|
|
243
|
-
}
|
|
244
|
-
// ---------------------------------------------------------------------------
|
|
245
247
|
// Public entry
|
|
246
248
|
// ---------------------------------------------------------------------------
|
|
247
249
|
export function parseTable(body, attrs, line, sink) {
|
|
248
250
|
const diagnostics = [];
|
|
249
251
|
const fmt = typeof attrs["format"] === "string" ? attrs["format"] : undefined;
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
252
|
+
// Data from elsewhere (§6): the caller has normalised `src=`/`data=` into `src`.
|
|
253
|
+
// A local or cross-document target is resolved after the scan (resolveTableSources
|
|
254
|
+
// in geml.ts calls back into this function with the resolved lines, so format,
|
|
255
|
+
// header, compute and summary behave identically); only an `http(s)` URL is still
|
|
256
|
+
// a render-time fetch. Either way the inline body must be empty.
|
|
253
257
|
const src = typeof attrs["src"] === "string" ? attrs["src"] : undefined;
|
|
254
258
|
if (src !== undefined) {
|
|
255
259
|
if (body.some((l) => l.trim() !== "")) {
|
|
@@ -308,19 +312,47 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
308
312
|
const v = model.rows[row]?.[ci]?.value;
|
|
309
313
|
return typeof v === "number" ? v : null;
|
|
310
314
|
};
|
|
315
|
+
// A cell a formula reads but cannot read as a number (`x`, `N/A`, `TBD`, an
|
|
316
|
+
// empty cell) counts as 0, so one dirty row does not void the whole column.
|
|
317
|
+
// But counting it silently is how a table quietly reports the wrong total, so
|
|
318
|
+
// say which cell was substituted. One warning per cell, not per mention: a
|
|
319
|
+
// formula naming the same column twice describes one substitution.
|
|
320
|
+
const substituted = new Set();
|
|
311
321
|
const colResolve = (name, row) => {
|
|
312
322
|
const ci = colIndex(name);
|
|
313
|
-
|
|
323
|
+
if (ci < 0)
|
|
324
|
+
return null;
|
|
325
|
+
const n = cellNum(ci, row);
|
|
326
|
+
if (n !== null)
|
|
327
|
+
return n;
|
|
328
|
+
const key = `${ci}\0${row}`;
|
|
329
|
+
if (!substituted.has(key)) {
|
|
330
|
+
substituted.add(key);
|
|
331
|
+
const text = model.rows[row]?.[ci]?.text ?? "";
|
|
332
|
+
diagnostics.push({
|
|
333
|
+
severity: "warning",
|
|
334
|
+
code: "compute-non-numeric-cell",
|
|
335
|
+
message: `column \`${name}\` row ${row + 1} is not a number (${text === "" ? "empty" : `\`${text}\``}); counted as 0`,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return 0;
|
|
314
339
|
};
|
|
315
340
|
const computeAgg = (fn, ci) => {
|
|
341
|
+
if (fn === "count") {
|
|
342
|
+
let c = 0;
|
|
343
|
+
for (let r = 0; r < model.rows.length; r++) {
|
|
344
|
+
const text = model.rows[r]?.[ci]?.text;
|
|
345
|
+
if (text !== undefined && text !== "")
|
|
346
|
+
c++;
|
|
347
|
+
}
|
|
348
|
+
return c;
|
|
349
|
+
}
|
|
316
350
|
const vals = [];
|
|
317
351
|
for (let r = 0; r < model.rows.length; r++) {
|
|
318
352
|
const v = cellNum(ci, r);
|
|
319
353
|
if (v !== null)
|
|
320
354
|
vals.push(v);
|
|
321
355
|
}
|
|
322
|
-
if (fn === "count")
|
|
323
|
-
return vals.length;
|
|
324
356
|
if (vals.length === 0)
|
|
325
357
|
return 0;
|
|
326
358
|
if (fn === "sum")
|
|
@@ -396,13 +428,14 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
396
428
|
try {
|
|
397
429
|
const v = evalExpr(toks, r, colResolve, aggResolve);
|
|
398
430
|
const cell = ensureCell(model.rows[r], ci);
|
|
399
|
-
|
|
400
|
-
|
|
431
|
+
const text = fmt ? applyFormat(fmt, v) : defaultNum(v);
|
|
432
|
+
cell.text = text;
|
|
433
|
+
cell.computed = true;
|
|
434
|
+
cell.inlines = [{ type: "text", value: text }];
|
|
435
|
+
if (Number.isFinite(v))
|
|
401
436
|
cell.value = v;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
cell.inlines = [{ type: "text", value: text }];
|
|
405
|
-
}
|
|
437
|
+
else
|
|
438
|
+
diagnostics.push({ severity: "warning", code: "compute-not-a-number", message: nanMsg(`compute \`${name}\` row ${r + 1}`, v) });
|
|
406
439
|
}
|
|
407
440
|
catch (e) {
|
|
408
441
|
diagnostics.push({ severity: "error", code: "compute-error", message: `compute \`${name}\`: ${e.message}` });
|
|
@@ -456,10 +489,12 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
456
489
|
}
|
|
457
490
|
try {
|
|
458
491
|
const v = evalExpr(toks, 0, noRow, aggResolve);
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
492
|
+
const text = fmt ? applyFormat(fmt, v) : defaultNum(v);
|
|
493
|
+
summary[ci] = { text, inlines: [{ type: "text", value: text }], computed: true };
|
|
494
|
+
if (Number.isFinite(v))
|
|
495
|
+
summary[ci].value = v;
|
|
496
|
+
else
|
|
497
|
+
diagnostics.push({ severity: "warning", code: "compute-not-a-number", message: nanMsg(`summary \`${name}\``, v) });
|
|
463
498
|
}
|
|
464
499
|
catch (e) {
|
|
465
500
|
const msg = /unknown column `(.+)`/.exec(e.message);
|
|
@@ -469,32 +504,6 @@ export function parseTable(body, attrs, line, sink) {
|
|
|
469
504
|
}
|
|
470
505
|
model.summary = summary;
|
|
471
506
|
}
|
|
472
|
-
// Spans: `span="r2c1:2x1"` (one or many: span, span2, …).
|
|
473
|
-
const spanDecls = Object.entries(attrs)
|
|
474
|
-
.filter(([k]) => k === "span" || /^span\d+$/.test(k))
|
|
475
|
-
.map(([, v]) => v)
|
|
476
|
-
.filter((v) => typeof v === "string");
|
|
477
|
-
for (const sd of spanDecls) {
|
|
478
|
-
const sp = parseSpan(sd);
|
|
479
|
-
if (!sp) {
|
|
480
|
-
diagnostics.push({ severity: "error", code: "bad-span", message: `bad span \`${sd}\` (want \`rNcM:RxC\`)` });
|
|
481
|
-
continue;
|
|
482
|
-
}
|
|
483
|
-
const cell = model.rows[sp.row - 1]?.[sp.col - 1];
|
|
484
|
-
if (!cell) {
|
|
485
|
-
diagnostics.push({ severity: "warning", code: "span-outside-table", message: `span \`${sd}\` targets a cell outside the table` });
|
|
486
|
-
continue;
|
|
487
|
-
}
|
|
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 };
|
|
497
|
-
}
|
|
498
507
|
return { model, diagnostics };
|
|
499
508
|
}
|
|
500
509
|
function ensureCell(row, ci) {
|
package/dist/to-md.js
CHANGED
|
@@ -38,6 +38,10 @@ function inline(n) {
|
|
|
38
38
|
case "link": return `[${seq(n.children)}](${linkDest(n)})`;
|
|
39
39
|
// Markdown has no auto-reference; project to a plain link to the anchor.
|
|
40
40
|
case "autoref": return n.doc !== undefined ? `[${n.doc}#${n.anchor}](${n.doc}#${n.anchor})` : `[#${n.anchor}](#${n.anchor})`;
|
|
41
|
+
// An inline projection needs the target's body, which this projection has no
|
|
42
|
+
// resolver for. The link keeps the reference reachable; the loss is reported
|
|
43
|
+
// once for the document by gemlToMd.
|
|
44
|
+
case "project": return n.doc !== undefined ? `[${n.doc}#${n.anchor}](${n.doc}#${n.anchor})` : `[#${n.anchor}](#${n.anchor})`;
|
|
41
45
|
case "footnote": return `[^${n.ref}]`;
|
|
42
46
|
}
|
|
43
47
|
}
|
|
@@ -121,7 +125,10 @@ function typedToMd(b, notes) {
|
|
|
121
125
|
return "";
|
|
122
126
|
}
|
|
123
127
|
if (b.mode === "flow") {
|
|
124
|
-
//
|
|
128
|
+
// A note the author marked `.footnote` projects to a Markdown footnote
|
|
129
|
+
// definition. The parser no longer synthesizes this class — the `[^id]: text`
|
|
130
|
+
// definition line was withdrawn from §5.2 — but an author still writes it,
|
|
131
|
+
// and it is the only way this projection can be produced.
|
|
125
132
|
if (b.type === "note" && b.classes.includes("footnote") && b.id) {
|
|
126
133
|
const text = (b.children ?? []).map((c) => block(c, notes)).join(" ").replace(/\n+/g, " ").trim();
|
|
127
134
|
return `[^${b.id}]: ${text}`;
|
|
@@ -139,8 +146,6 @@ function typedToMd(b, notes) {
|
|
|
139
146
|
return fence(attr(b, "lang") ?? "", raw);
|
|
140
147
|
if (b.type === "math")
|
|
141
148
|
return ["$$", ...raw, "$$"].join("\n");
|
|
142
|
-
if (b.type === "output")
|
|
143
|
-
return fence("", raw);
|
|
144
149
|
if (b.type === "table" && b.table)
|
|
145
150
|
return tableToMd(b.table, notes);
|
|
146
151
|
if (b.type === "diagram") {
|
|
@@ -153,6 +158,15 @@ function typedToMd(b, notes) {
|
|
|
153
158
|
}
|
|
154
159
|
return fence(fmt, raw); // mermaid renders on GitHub; others stay as a code block
|
|
155
160
|
}
|
|
161
|
+
if (b.type === "embed") {
|
|
162
|
+
// Markdown has no transclusion, and the content lives in another file, so
|
|
163
|
+
// there is nothing to inline. A link to the target at least keeps the
|
|
164
|
+
// reference reachable; the unknown-type fallback below would emit an empty
|
|
165
|
+
// fence, which tells a reader nothing.
|
|
166
|
+
const target = typeof b.attrs["src"] === "string" ? b.attrs["src"].trim() : "";
|
|
167
|
+
notes.add("block transclusion projected as a link; the referenced content is not inlined (Markdown has no transclusion)");
|
|
168
|
+
return target === "" ? "" : `[${target}](${target})`;
|
|
169
|
+
}
|
|
156
170
|
// Unknown raw type: preserve the body in a fenced block tagged with the type.
|
|
157
171
|
notes.add(`unknown block type \`${b.type}\` emitted as a fenced code block`);
|
|
158
172
|
return fence(b.type, raw);
|
package/package.json
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@geml/geml",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"mcpName": "io.github.geml-spec/geml",
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"access": "public"
|
|
7
|
-
},
|
|
8
|
-
"description": "CLI and parser for GEML, a plain-text document format where every block has an id — so an AI patches one block instead of rewriting the file; edits, reference checks and rollbacks are all per block. Ships an MCP server.",
|
|
9
|
-
"type": "module",
|
|
10
|
-
"bin": {
|
|
11
|
-
"geml": "dist/geml.js"
|
|
12
|
-
},
|
|
13
|
-
"main": "dist/geml.js",
|
|
14
|
-
"types": "dist/geml.d.ts",
|
|
15
|
-
"files": [
|
|
16
|
-
"dist",
|
|
17
|
-
"codemap",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"engines": {
|
|
22
|
-
"node": ">=22"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"geml",
|
|
26
|
-
"general expressive markup language",
|
|
27
|
-
"mcp",
|
|
28
|
-
"mcp-server",
|
|
29
|
-
"markup",
|
|
30
|
-
"markdown",
|
|
31
|
-
"parser",
|
|
32
|
-
"cli",
|
|
33
|
-
"document",
|
|
34
|
-
"typed-block",
|
|
35
|
-
"ai",
|
|
36
|
-
"agent",
|
|
37
|
-
"llm",
|
|
38
|
-
"addressable",
|
|
39
|
-
"versioning",
|
|
40
|
-
"docs",
|
|
41
|
-
"code-graph"
|
|
42
|
-
],
|
|
43
|
-
"repository": {
|
|
44
|
-
"type": "git",
|
|
45
|
-
"url": "git+https://github.com/geml-spec/geml.git",
|
|
46
|
-
"directory": "geml-parser"
|
|
47
|
-
},
|
|
48
|
-
"homepage": "https://github.com/geml-spec/geml#readme",
|
|
49
|
-
"bugs": {
|
|
50
|
-
"url": "https://github.com/geml-spec/geml/issues"
|
|
51
|
-
},
|
|
52
|
-
"scripts": {
|
|
53
|
-
"build": "tsc",
|
|
54
|
-
"test": "tsc && node test/all.mjs",
|
|
55
|
-
"parse": "node dist/geml.js",
|
|
56
|
-
"coverage": "tsc && c8 --all --include=dist/**/*.js --include=codemap/**/*.mjs --reporter=text --reporter=text-summary node test/all.mjs",
|
|
57
|
-
"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",
|
|
58
|
-
"prepublishOnly": "npm run build"
|
|
59
|
-
},
|
|
60
|
-
"license": "MIT",
|
|
61
|
-
"devDependencies": {
|
|
62
|
-
"@types/node": "^22.19.21",
|
|
63
|
-
"c8": "^10.1.3",
|
|
64
|
-
"typescript": "^5.9.3"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@geml/geml",
|
|
3
|
+
"version": "1.5.1",
|
|
4
|
+
"mcpName": "io.github.geml-spec/geml",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"description": "CLI and parser for GEML, a plain-text document format where every block has an id — so an AI patches one block instead of rewriting the file; edits, reference checks and rollbacks are all per block. Ships an MCP server.",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"geml": "dist/geml.js"
|
|
12
|
+
},
|
|
13
|
+
"main": "dist/geml.js",
|
|
14
|
+
"types": "dist/geml.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"codemap",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=22"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"geml",
|
|
26
|
+
"general expressive markup language",
|
|
27
|
+
"mcp",
|
|
28
|
+
"mcp-server",
|
|
29
|
+
"markup",
|
|
30
|
+
"markdown",
|
|
31
|
+
"parser",
|
|
32
|
+
"cli",
|
|
33
|
+
"document",
|
|
34
|
+
"typed-block",
|
|
35
|
+
"ai",
|
|
36
|
+
"agent",
|
|
37
|
+
"llm",
|
|
38
|
+
"addressable",
|
|
39
|
+
"versioning",
|
|
40
|
+
"docs",
|
|
41
|
+
"code-graph"
|
|
42
|
+
],
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/geml-spec/geml.git",
|
|
46
|
+
"directory": "geml-parser"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/geml-spec/geml#readme",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/geml-spec/geml/issues"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc",
|
|
54
|
+
"test": "tsc && node test/all.mjs",
|
|
55
|
+
"parse": "node dist/geml.js",
|
|
56
|
+
"coverage": "tsc && c8 --all --include=dist/**/*.js --include=codemap/**/*.mjs --reporter=text --reporter=text-summary node test/all.mjs",
|
|
57
|
+
"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",
|
|
58
|
+
"prepublishOnly": "npm run build"
|
|
59
|
+
},
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "^22.19.21",
|
|
63
|
+
"c8": "^10.1.3",
|
|
64
|
+
"typescript": "^5.9.3"
|
|
65
|
+
}
|
|
66
|
+
}
|