@amritk/generate-examples 0.5.1 → 0.5.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,124 +1,100 @@
1
- import { extractRefs } from '@amritk/helpers/extract-refs';
2
- import { refToFilename } from '@amritk/helpers/ref-to-filename';
3
- import { walkRefGraph } from '@amritk/helpers/walk-ref-graph';
4
- /**
5
- * Collects the ref graph as an adjacency map of filename → referenced
6
- * filenames, restricted to nodes that are actually generated as files. Self
7
- * edges are dropped (they are `fc.letrec` recursion, not cross-file cycles).
8
- */
1
+ import { extractRefs } from "@amritk/helpers/extract-refs";
2
+ import { refToFilename } from "@amritk/helpers/ref-to-filename";
3
+ import { walkRefGraph } from "@amritk/helpers/walk-ref-graph";
9
4
  const buildRefGraph = (rootSchema, rootTypeName, typeSuffix) => {
10
- const schemas = new Map();
11
- walkRefGraph(rootSchema, rootTypeName, { typeSuffix }, (node) => {
12
- // `index` is reserved for the barrel and never generated as a definition.
13
- if (node.filename === 'index')
14
- return;
15
- if (!schemas.has(node.filename))
16
- schemas.set(node.filename, node.schema);
17
- });
18
- const graph = new Map();
19
- for (const [filename, schema] of schemas) {
20
- const targets = new Set();
21
- for (const ref of extractRefs(schema)) {
22
- const target = refToFilename(ref);
23
- // Only edges to other generated files matter — an unresolved/external ref
24
- // never becomes an eager cross-module reference.
25
- if (target !== filename && schemas.has(target))
26
- targets.add(target);
27
- }
28
- graph.set(filename, targets);
5
+ const schemas = /* @__PURE__ */ new Map();
6
+ walkRefGraph(rootSchema, rootTypeName, { typeSuffix }, (node) => {
7
+ if (node.filename === "index")
8
+ return;
9
+ if (!schemas.has(node.filename))
10
+ schemas.set(node.filename, node.schema);
11
+ });
12
+ const graph = /* @__PURE__ */ new Map();
13
+ for (const [filename, schema] of schemas) {
14
+ const targets = /* @__PURE__ */ new Set();
15
+ for (const ref of extractRefs(schema)) {
16
+ const target = refToFilename(ref);
17
+ if (target !== filename && schemas.has(target))
18
+ targets.add(target);
29
19
  }
30
- return graph;
20
+ graph.set(filename, targets);
21
+ }
22
+ return graph;
31
23
  };
32
- /**
33
- * Tarjan's strongly-connected-components algorithm, iterative so a deep ref
34
- * graph cannot overflow the call stack. Returns one array of filenames per SCC.
35
- */
36
24
  const stronglyConnectedComponents = (graph) => {
37
- let counter = 0;
38
- const index = new Map();
39
- const lowlink = new Map();
40
- const onStack = new Set();
41
- const stack = [];
42
- const sccs = [];
43
- for (const start of graph.keys()) {
44
- if (index.has(start))
45
- continue;
46
- const callStack = [{ node: start, iter: (graph.get(start) ?? new Set()).values() }];
47
- index.set(start, counter);
48
- lowlink.set(start, counter);
49
- counter++;
50
- stack.push(start);
51
- onStack.add(start);
52
- while (callStack.length > 0) {
53
- const frame = callStack[callStack.length - 1];
54
- const node = frame.node;
55
- let descended = false;
56
- let next = frame.iter.next();
57
- while (!next.done) {
58
- const child = next.value;
59
- if (!index.has(child)) {
60
- index.set(child, counter);
61
- lowlink.set(child, counter);
62
- counter++;
63
- stack.push(child);
64
- onStack.add(child);
65
- callStack.push({ node: child, iter: (graph.get(child) ?? new Set()).values() });
66
- descended = true;
67
- break;
68
- }
69
- if (onStack.has(child)) {
70
- lowlink.set(node, Math.min(lowlink.get(node), index.get(child)));
71
- }
72
- next = frame.iter.next();
73
- }
74
- if (descended)
75
- continue;
76
- // All successors visited: close this node.
77
- if (lowlink.get(node) === index.get(node)) {
78
- const scc = [];
79
- let member;
80
- do {
81
- member = stack.pop();
82
- onStack.delete(member);
83
- scc.push(member);
84
- } while (member !== node);
85
- sccs.push(scc);
86
- }
87
- callStack.pop();
88
- const parent = callStack[callStack.length - 1];
89
- if (parent) {
90
- lowlink.set(parent.node, Math.min(lowlink.get(parent.node), lowlink.get(node)));
91
- }
25
+ let counter = 0;
26
+ const index = /* @__PURE__ */ new Map();
27
+ const lowlink = /* @__PURE__ */ new Map();
28
+ const onStack = /* @__PURE__ */ new Set();
29
+ const stack = [];
30
+ const sccs = [];
31
+ for (const start of graph.keys()) {
32
+ if (index.has(start))
33
+ continue;
34
+ const callStack = [{ node: start, iter: (graph.get(start) ?? /* @__PURE__ */ new Set()).values() }];
35
+ index.set(start, counter);
36
+ lowlink.set(start, counter);
37
+ counter++;
38
+ stack.push(start);
39
+ onStack.add(start);
40
+ while (callStack.length > 0) {
41
+ const frame = callStack[callStack.length - 1];
42
+ const node = frame.node;
43
+ let descended = false;
44
+ let next = frame.iter.next();
45
+ while (!next.done) {
46
+ const child = next.value;
47
+ if (!index.has(child)) {
48
+ index.set(child, counter);
49
+ lowlink.set(child, counter);
50
+ counter++;
51
+ stack.push(child);
52
+ onStack.add(child);
53
+ callStack.push({ node: child, iter: (graph.get(child) ?? /* @__PURE__ */ new Set()).values() });
54
+ descended = true;
55
+ break;
56
+ }
57
+ if (onStack.has(child)) {
58
+ lowlink.set(node, Math.min(lowlink.get(node), index.get(child)));
92
59
  }
60
+ next = frame.iter.next();
61
+ }
62
+ if (descended)
63
+ continue;
64
+ if (lowlink.get(node) === index.get(node)) {
65
+ const scc = [];
66
+ let member;
67
+ do {
68
+ member = stack.pop();
69
+ onStack.delete(member);
70
+ scc.push(member);
71
+ } while (member !== node);
72
+ sccs.push(scc);
73
+ }
74
+ callStack.pop();
75
+ const parent = callStack[callStack.length - 1];
76
+ if (parent) {
77
+ lowlink.set(parent.node, Math.min(lowlink.get(parent.node), lowlink.get(node)));
78
+ }
93
79
  }
94
- return sccs;
80
+ }
81
+ return sccs;
95
82
  };
96
- /**
97
- * Detects cross-file `$ref` cycles in a schema's ref graph.
98
- *
99
- * Walks the graph via {@link walkRefGraph}, groups files into strongly connected
100
- * components, and returns — for every file inside a multi-file component — the
101
- * sibling files it must reference lazily to avoid a circular-ESM TDZ crash.
102
- * Files not involved in any cross-file cycle are absent from the result.
103
- *
104
- * @param rootSchema - The root JSON Schema being built.
105
- * @param rootTypeName - The name for the root type (e.g. `'Document'`).
106
- * @param typeSuffix - Suffix appended to every `$ref`-derived name (default `''`).
107
- */
108
- export const findSchemaCycles = (rootSchema, rootTypeName, typeSuffix = '') => {
109
- const graph = buildRefGraph(rootSchema, rootTypeName, typeSuffix);
110
- const cycles = new Map();
111
- for (const scc of stronglyConnectedComponents(graph)) {
112
- // A single-file component is either an isolated node or pure self-recursion;
113
- // neither needs cross-file lazy references.
114
- if (scc.length < 2)
115
- continue;
116
- const members = new Set(scc);
117
- for (const member of scc) {
118
- const siblings = new Set(members);
119
- siblings.delete(member);
120
- cycles.set(member, siblings);
121
- }
83
+ const findSchemaCycles = (rootSchema, rootTypeName, typeSuffix = "") => {
84
+ const graph = buildRefGraph(rootSchema, rootTypeName, typeSuffix);
85
+ const cycles = /* @__PURE__ */ new Map();
86
+ for (const scc of stronglyConnectedComponents(graph)) {
87
+ if (scc.length < 2)
88
+ continue;
89
+ const members = new Set(scc);
90
+ for (const member of scc) {
91
+ const siblings = new Set(members);
92
+ siblings.delete(member);
93
+ cycles.set(member, siblings);
122
94
  }
123
- return cycles;
95
+ }
96
+ return cycles;
97
+ };
98
+ export {
99
+ findSchemaCycles
124
100
  };