@ontrails/core 1.0.0-beta.2 → 1.0.0-beta.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.
- package/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +16 -0
- package/dist/derive.d.ts +1 -1
- package/dist/derive.d.ts.map +1 -1
- package/dist/derive.js +4 -1
- package/dist/derive.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/result.d.ts.map +1 -1
- package/dist/result.js +15 -4
- package/dist/result.js.map +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +45 -7
- package/dist/serialization.js.map +1 -1
- package/dist/topo.d.ts.map +1 -1
- package/dist/topo.js +6 -0
- package/dist/topo.js.map +1 -1
- package/dist/validate-topo.d.ts.map +1 -1
- package/dist/validate-topo.js +49 -1
- package/dist/validate-topo.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/derive.test.ts +44 -0
- package/src/__tests__/serialization.test.ts +166 -1
- package/src/__tests__/topo.test.ts +97 -61
- package/src/__tests__/validate-topo.test.ts +82 -3
- package/src/derive.ts +12 -2
- package/src/index.ts +4 -0
- package/src/result.ts +18 -4
- package/src/serialization.ts +56 -11
- package/src/topo.ts +10 -0
- package/src/validate-topo.ts +60 -1
package/src/validate-topo.ts
CHANGED
|
@@ -28,6 +28,64 @@ export interface TopoIssue {
|
|
|
28
28
|
// Validators
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
|
|
31
|
+
const WHITE = 0;
|
|
32
|
+
const GRAY = 1;
|
|
33
|
+
const BLACK = 2;
|
|
34
|
+
|
|
35
|
+
/** Build an adjacency list and initial color map from hikes. */
|
|
36
|
+
const buildFollowGraph = (
|
|
37
|
+
hikes: ReadonlyMap<string, AnyHike>
|
|
38
|
+
): {
|
|
39
|
+
graph: Map<string, readonly string[]>;
|
|
40
|
+
color: Map<string, number>;
|
|
41
|
+
} => {
|
|
42
|
+
const graph = new Map<string, readonly string[]>();
|
|
43
|
+
for (const [id, h] of hikes) {
|
|
44
|
+
graph.set(id, h.follows);
|
|
45
|
+
}
|
|
46
|
+
const color = new Map<string, number>();
|
|
47
|
+
for (const id of graph.keys()) {
|
|
48
|
+
color.set(id, WHITE);
|
|
49
|
+
}
|
|
50
|
+
return { color, graph };
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Detect multi-node cycles in the hike follow graph via DFS. */
|
|
54
|
+
const detectFollowCycles = (
|
|
55
|
+
hikes: ReadonlyMap<string, AnyHike>
|
|
56
|
+
): TopoIssue[] => {
|
|
57
|
+
const issues: TopoIssue[] = [];
|
|
58
|
+
const { color, graph } = buildFollowGraph(hikes);
|
|
59
|
+
|
|
60
|
+
const dfs = (node: string, path: string[]): void => {
|
|
61
|
+
color.set(node, GRAY);
|
|
62
|
+
for (const next of graph.get(node) ?? []) {
|
|
63
|
+
if (!graph.has(next)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const c = color.get(next) ?? WHITE;
|
|
67
|
+
if (c === GRAY) {
|
|
68
|
+
const cycle = [...path.slice(path.indexOf(next)), next];
|
|
69
|
+
issues.push({
|
|
70
|
+
message: `Cycle detected: ${cycle.join(' → ')}`,
|
|
71
|
+
rule: 'follow-cycle',
|
|
72
|
+
trailId: next,
|
|
73
|
+
});
|
|
74
|
+
} else if (c === WHITE) {
|
|
75
|
+
dfs(next, [...path, next]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
color.set(node, BLACK);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
for (const id of graph.keys()) {
|
|
82
|
+
if (color.get(id) === WHITE) {
|
|
83
|
+
dfs(id, [id]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return issues;
|
|
87
|
+
};
|
|
88
|
+
|
|
31
89
|
const checkFollows = (
|
|
32
90
|
hikes: ReadonlyMap<string, AnyHike>,
|
|
33
91
|
topo: Topo
|
|
@@ -50,6 +108,7 @@ const checkFollows = (
|
|
|
50
108
|
}
|
|
51
109
|
}
|
|
52
110
|
}
|
|
111
|
+
issues.push(...detectFollowCycles(hikes));
|
|
53
112
|
return issues;
|
|
54
113
|
};
|
|
55
114
|
|
|
@@ -66,7 +125,7 @@ const checkOneExample = (
|
|
|
66
125
|
): TopoIssue[] => {
|
|
67
126
|
const issues: TopoIssue[] = [];
|
|
68
127
|
const result = validateInput(inputSchema as AnyTrail['input'], example.input);
|
|
69
|
-
if (result.isErr() && example.error
|
|
128
|
+
if (result.isErr() && example.error !== 'ValidationError') {
|
|
70
129
|
issues.push({
|
|
71
130
|
message: `Example "${example.name}" input does not parse against schema`,
|
|
72
131
|
rule: 'example-input-valid',
|