@geml/geml 1.8.2 → 1.8.4
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 +288 -288
- 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 +34 -34
- package/codemap/build.mjs +629 -629
- package/codemap/cross-stack.mjs +303 -303
- package/codemap/detect.mjs +399 -399
- package/codemap/emit.mjs +510 -510
- package/codemap/entries.mjs +129 -129
- package/codemap/exclude.mjs +56 -56
- package/codemap/find.mjs +49 -49
- package/codemap/foldings.mjs +110 -110
- package/codemap/joern-export.sc +83 -83
- package/codemap/mcp-server.mjs +434 -434
- package/codemap/normalize.mjs +275 -275
- package/codemap/recipe-trust.mjs +103 -103
- package/codemap/refresh.mjs +313 -313
- package/codemap/render-all.mjs +90 -90
- package/codemap/serve.mjs +585 -585
- package/codemap/sfc-virtualize.mjs +367 -367
- package/codemap/verify.mjs +158 -158
- package/dist/cli.js +129 -129
- package/dist/geml.js +73 -25
- package/dist/mcp.js +19 -19
- package/dist/render-html.js +35 -35
- package/dist/render.js +157 -157
- package/dist/serialize.js +7 -1
- package/dist/to-md.js +8 -1
- package/package.json +67 -67
- package/skill/SKILL.md +167 -167
- package/skill/references/authoring.geml +369 -369
package/codemap/render-all.mjs
CHANGED
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// geml codemap render — render every codemap document to a sibling .html.
|
|
3
|
-
//
|
|
4
|
-
// geml codemap render [codemap-dir]
|
|
5
|
-
//
|
|
6
|
-
// The output folder then works with NO server: open index.html straight from
|
|
7
|
-
// disk (file://). Module click-through opens each container page inside the
|
|
8
|
-
// graph area (nested frame), so the whole map is browsable offline — this is
|
|
9
|
-
// the "copy the folder to someone" mode. For a live view that never goes
|
|
10
|
-
// stale, use `geml codemap serve` instead.
|
|
11
|
-
import { readdirSync, readFileSync, writeFileSync, realpathSync, unlinkSync } from "node:fs";
|
|
12
|
-
import { join, basename, sep, resolve as resolvePath } from "node:path";
|
|
13
|
-
import { parse, renderHtml } from "../dist/geml.js";
|
|
14
|
-
|
|
15
|
-
if (process.argv[2] === "--help" || process.argv[2] === "-h") {
|
|
16
|
-
console.error("usage: geml codemap render [codemap-dir] (dir defaults to ./.geml-code-graph)");
|
|
17
|
-
process.exit(2);
|
|
18
|
-
}
|
|
19
|
-
const dir = process.argv[2] || ".geml-code-graph";
|
|
20
|
-
|
|
21
|
-
// One shared cache for the whole batch: every page's graph slice crosses the
|
|
22
|
-
// same neighbour documents, and a fresh parse per page turns N pages into
|
|
23
|
-
// O(N x working set) — hours at repo scale. A one-shot process has no
|
|
24
|
-
// staleness to worry about, so cache unconditionally (the whole codemap's
|
|
25
|
-
// text + parsed docs live in memory for the duration of the run).
|
|
26
|
-
const texts = new Map(); // rel -> text | null
|
|
27
|
-
const parsed = new Map(); // text -> Document
|
|
28
|
-
// `rel` is document-controlled — a `src=` composed by the renderer — and the
|
|
29
|
-
// output of this command is a published artifact, so an unconfined read here
|
|
30
|
-
// writes any .geml on the filesystem into a file that then gets served. Gate on
|
|
31
|
-
// the realpath, the same shape `serve` and the CLI resolver use.
|
|
32
|
-
let realDir = null;
|
|
33
|
-
try { realDir = realpathSync(resolvePath(dir)); } catch { realDir = null; }
|
|
34
|
-
const loadDoc = (rel) => {
|
|
35
|
-
if (!texts.has(rel)) {
|
|
36
|
-
let text = null;
|
|
37
|
-
if (realDir !== null) {
|
|
38
|
-
try {
|
|
39
|
-
const real = realpathSync(join(dir, rel));
|
|
40
|
-
if (real === realDir || real.startsWith(realDir + sep)) text = readFileSync(real, "utf8");
|
|
41
|
-
} catch { text = null; }
|
|
42
|
-
}
|
|
43
|
-
texts.set(rel, text);
|
|
44
|
-
}
|
|
45
|
-
return texts.get(rel);
|
|
46
|
-
};
|
|
47
|
-
const parseDoc = (s) => {
|
|
48
|
-
let d = parsed.get(s);
|
|
49
|
-
if (!d) { d = parse(s); parsed.set(s, d); }
|
|
50
|
-
return d;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
let n = 0;
|
|
54
|
-
const failed = [];
|
|
55
|
-
let files;
|
|
56
|
-
try {
|
|
57
|
-
files = readdirSync(dir);
|
|
58
|
-
} catch {
|
|
59
|
-
console.error(`error: cannot read directory ${dir}`);
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
for (const f of files) {
|
|
63
|
-
if (!f.endsWith(".geml")) continue;
|
|
64
|
-
try {
|
|
65
|
-
const text = loadDoc(f);
|
|
66
|
-
if (text === null) throw new Error("unreadable");
|
|
67
|
-
const doc = parseDoc(text);
|
|
68
|
-
const html = renderHtml(doc, { source: basename(f), loadDoc, parseDoc });
|
|
69
|
-
writeFileSync(join(dir, f.replace(/\.geml$/, ".html")), html);
|
|
70
|
-
n++;
|
|
71
|
-
} catch (e) {
|
|
72
|
-
failed.push(f);
|
|
73
|
-
console.error(`render: ${f}: ${e.message}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// Each tool prunes what it owns: build removes the documents it no longer
|
|
77
|
-
// produces, and this removes the pages whose document is gone. An orphan page
|
|
78
|
-
// is worse than a stale one — it is unreachable from index.html yet still
|
|
79
|
-
// served, so a copied folder ships a page describing deleted code with no way
|
|
80
|
-
// to notice. Only a `<base>.html` whose `<base>.geml` is absent qualifies, so
|
|
81
|
-
// nothing that has a document behind it is ever touched.
|
|
82
|
-
const prunedPages = [];
|
|
83
|
-
for (const f of files) {
|
|
84
|
-
if (!f.endsWith(".html")) continue;
|
|
85
|
-
if (files.includes(f.replace(/\.html$/, ".geml"))) continue;
|
|
86
|
-
try { unlinkSync(join(dir, f)); prunedPages.push(f); } catch { /* already gone */ }
|
|
87
|
-
}
|
|
88
|
-
console.error(`rendered ${n} page(s) -> ${dir}${failed.length ? `; FAILED: ${failed.join(", ")}` : ""}`);
|
|
89
|
-
if (prunedPages.length) console.error(` pruned ${prunedPages.length} orphan page(s): ${prunedPages.join(", ")}`);
|
|
90
|
-
process.exit(failed.length ? 1 : 0);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// geml codemap render — render every codemap document to a sibling .html.
|
|
3
|
+
//
|
|
4
|
+
// geml codemap render [codemap-dir]
|
|
5
|
+
//
|
|
6
|
+
// The output folder then works with NO server: open index.html straight from
|
|
7
|
+
// disk (file://). Module click-through opens each container page inside the
|
|
8
|
+
// graph area (nested frame), so the whole map is browsable offline — this is
|
|
9
|
+
// the "copy the folder to someone" mode. For a live view that never goes
|
|
10
|
+
// stale, use `geml codemap serve` instead.
|
|
11
|
+
import { readdirSync, readFileSync, writeFileSync, realpathSync, unlinkSync } from "node:fs";
|
|
12
|
+
import { join, basename, sep, resolve as resolvePath } from "node:path";
|
|
13
|
+
import { parse, renderHtml } from "../dist/geml.js";
|
|
14
|
+
|
|
15
|
+
if (process.argv[2] === "--help" || process.argv[2] === "-h") {
|
|
16
|
+
console.error("usage: geml codemap render [codemap-dir] (dir defaults to ./.geml-code-graph)");
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
const dir = process.argv[2] || ".geml-code-graph";
|
|
20
|
+
|
|
21
|
+
// One shared cache for the whole batch: every page's graph slice crosses the
|
|
22
|
+
// same neighbour documents, and a fresh parse per page turns N pages into
|
|
23
|
+
// O(N x working set) — hours at repo scale. A one-shot process has no
|
|
24
|
+
// staleness to worry about, so cache unconditionally (the whole codemap's
|
|
25
|
+
// text + parsed docs live in memory for the duration of the run).
|
|
26
|
+
const texts = new Map(); // rel -> text | null
|
|
27
|
+
const parsed = new Map(); // text -> Document
|
|
28
|
+
// `rel` is document-controlled — a `src=` composed by the renderer — and the
|
|
29
|
+
// output of this command is a published artifact, so an unconfined read here
|
|
30
|
+
// writes any .geml on the filesystem into a file that then gets served. Gate on
|
|
31
|
+
// the realpath, the same shape `serve` and the CLI resolver use.
|
|
32
|
+
let realDir = null;
|
|
33
|
+
try { realDir = realpathSync(resolvePath(dir)); } catch { realDir = null; }
|
|
34
|
+
const loadDoc = (rel) => {
|
|
35
|
+
if (!texts.has(rel)) {
|
|
36
|
+
let text = null;
|
|
37
|
+
if (realDir !== null) {
|
|
38
|
+
try {
|
|
39
|
+
const real = realpathSync(join(dir, rel));
|
|
40
|
+
if (real === realDir || real.startsWith(realDir + sep)) text = readFileSync(real, "utf8");
|
|
41
|
+
} catch { text = null; }
|
|
42
|
+
}
|
|
43
|
+
texts.set(rel, text);
|
|
44
|
+
}
|
|
45
|
+
return texts.get(rel);
|
|
46
|
+
};
|
|
47
|
+
const parseDoc = (s) => {
|
|
48
|
+
let d = parsed.get(s);
|
|
49
|
+
if (!d) { d = parse(s); parsed.set(s, d); }
|
|
50
|
+
return d;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
let n = 0;
|
|
54
|
+
const failed = [];
|
|
55
|
+
let files;
|
|
56
|
+
try {
|
|
57
|
+
files = readdirSync(dir);
|
|
58
|
+
} catch {
|
|
59
|
+
console.error(`error: cannot read directory ${dir}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
for (const f of files) {
|
|
63
|
+
if (!f.endsWith(".geml")) continue;
|
|
64
|
+
try {
|
|
65
|
+
const text = loadDoc(f);
|
|
66
|
+
if (text === null) throw new Error("unreadable");
|
|
67
|
+
const doc = parseDoc(text);
|
|
68
|
+
const html = renderHtml(doc, { source: basename(f), loadDoc, parseDoc });
|
|
69
|
+
writeFileSync(join(dir, f.replace(/\.geml$/, ".html")), html);
|
|
70
|
+
n++;
|
|
71
|
+
} catch (e) {
|
|
72
|
+
failed.push(f);
|
|
73
|
+
console.error(`render: ${f}: ${e.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Each tool prunes what it owns: build removes the documents it no longer
|
|
77
|
+
// produces, and this removes the pages whose document is gone. An orphan page
|
|
78
|
+
// is worse than a stale one — it is unreachable from index.html yet still
|
|
79
|
+
// served, so a copied folder ships a page describing deleted code with no way
|
|
80
|
+
// to notice. Only a `<base>.html` whose `<base>.geml` is absent qualifies, so
|
|
81
|
+
// nothing that has a document behind it is ever touched.
|
|
82
|
+
const prunedPages = [];
|
|
83
|
+
for (const f of files) {
|
|
84
|
+
if (!f.endsWith(".html")) continue;
|
|
85
|
+
if (files.includes(f.replace(/\.html$/, ".geml"))) continue;
|
|
86
|
+
try { unlinkSync(join(dir, f)); prunedPages.push(f); } catch { /* already gone */ }
|
|
87
|
+
}
|
|
88
|
+
console.error(`rendered ${n} page(s) -> ${dir}${failed.length ? `; FAILED: ${failed.join(", ")}` : ""}`);
|
|
89
|
+
if (prunedPages.length) console.error(` pruned ${prunedPages.length} orphan page(s): ${prunedPages.join(", ")}`);
|
|
90
|
+
process.exit(failed.length ? 1 : 0);
|