@geml/geml 1.8.1 → 1.8.3

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.
@@ -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);