@lepid-labs/weft-core 0.1.0

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.
Files changed (266) hide show
  1. package/LICENSE +21 -0
  2. package/dist/anchors/__tests__/markdown.test.d.ts +2 -0
  3. package/dist/anchors/__tests__/markdown.test.d.ts.map +1 -0
  4. package/dist/anchors/__tests__/markdown.test.js +130 -0
  5. package/dist/anchors/__tests__/markdown.test.js.map +1 -0
  6. package/dist/anchors/__tests__/openapi.test.d.ts +2 -0
  7. package/dist/anchors/__tests__/openapi.test.d.ts.map +1 -0
  8. package/dist/anchors/__tests__/openapi.test.js +115 -0
  9. package/dist/anchors/__tests__/openapi.test.js.map +1 -0
  10. package/dist/anchors/index.d.ts +35 -0
  11. package/dist/anchors/index.d.ts.map +1 -0
  12. package/dist/anchors/index.js +68 -0
  13. package/dist/anchors/index.js.map +1 -0
  14. package/dist/anchors/markdown.d.ts +15 -0
  15. package/dist/anchors/markdown.d.ts.map +1 -0
  16. package/dist/anchors/markdown.js +71 -0
  17. package/dist/anchors/markdown.js.map +1 -0
  18. package/dist/anchors/openapi.d.ts +24 -0
  19. package/dist/anchors/openapi.d.ts.map +1 -0
  20. package/dist/anchors/openapi.js +75 -0
  21. package/dist/anchors/openapi.js.map +1 -0
  22. package/dist/browser.d.ts +10 -0
  23. package/dist/browser.d.ts.map +1 -0
  24. package/dist/browser.js +8 -0
  25. package/dist/browser.js.map +1 -0
  26. package/dist/config.d.ts +47 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +393 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/config.test.d.ts +2 -0
  31. package/dist/config.test.d.ts.map +1 -0
  32. package/dist/config.test.js +454 -0
  33. package/dist/config.test.js.map +1 -0
  34. package/dist/content.d.ts +37 -0
  35. package/dist/content.d.ts.map +1 -0
  36. package/dist/content.js +57 -0
  37. package/dist/content.js.map +1 -0
  38. package/dist/content.test.d.ts +2 -0
  39. package/dist/content.test.d.ts.map +1 -0
  40. package/dist/content.test.js +100 -0
  41. package/dist/content.test.js.map +1 -0
  42. package/dist/contributions.d.ts +64 -0
  43. package/dist/contributions.d.ts.map +1 -0
  44. package/dist/contributions.js +184 -0
  45. package/dist/contributions.js.map +1 -0
  46. package/dist/contributions.test.d.ts +2 -0
  47. package/dist/contributions.test.d.ts.map +1 -0
  48. package/dist/contributions.test.js +202 -0
  49. package/dist/contributions.test.js.map +1 -0
  50. package/dist/fetch/auth.d.ts +15 -0
  51. package/dist/fetch/auth.d.ts.map +1 -0
  52. package/dist/fetch/auth.js +38 -0
  53. package/dist/fetch/auth.js.map +1 -0
  54. package/dist/fetch/cache.d.ts +25 -0
  55. package/dist/fetch/cache.d.ts.map +1 -0
  56. package/dist/fetch/cache.js +68 -0
  57. package/dist/fetch/cache.js.map +1 -0
  58. package/dist/fetch/cache.test.d.ts +2 -0
  59. package/dist/fetch/cache.test.d.ts.map +1 -0
  60. package/dist/fetch/cache.test.js +73 -0
  61. package/dist/fetch/cache.test.js.map +1 -0
  62. package/dist/fetch/clone.d.ts +26 -0
  63. package/dist/fetch/clone.d.ts.map +1 -0
  64. package/dist/fetch/clone.js +105 -0
  65. package/dist/fetch/clone.js.map +1 -0
  66. package/dist/fetch/fetch.test.d.ts +2 -0
  67. package/dist/fetch/fetch.test.d.ts.map +1 -0
  68. package/dist/fetch/fetch.test.js +167 -0
  69. package/dist/fetch/fetch.test.js.map +1 -0
  70. package/dist/fetch/resolve.d.ts +34 -0
  71. package/dist/fetch/resolve.d.ts.map +1 -0
  72. package/dist/fetch/resolve.js +59 -0
  73. package/dist/fetch/resolve.js.map +1 -0
  74. package/dist/freshness.d.ts +29 -0
  75. package/dist/freshness.d.ts.map +1 -0
  76. package/dist/freshness.js +170 -0
  77. package/dist/freshness.js.map +1 -0
  78. package/dist/freshness.test.d.ts +2 -0
  79. package/dist/freshness.test.d.ts.map +1 -0
  80. package/dist/freshness.test.js +209 -0
  81. package/dist/freshness.test.js.map +1 -0
  82. package/dist/frontmatter.d.ts +15 -0
  83. package/dist/frontmatter.d.ts.map +1 -0
  84. package/dist/frontmatter.js +24 -0
  85. package/dist/frontmatter.js.map +1 -0
  86. package/dist/frontmatter.test.d.ts +2 -0
  87. package/dist/frontmatter.test.d.ts.map +1 -0
  88. package/dist/frontmatter.test.js +54 -0
  89. package/dist/frontmatter.test.js.map +1 -0
  90. package/dist/git.d.ts +55 -0
  91. package/dist/git.d.ts.map +1 -0
  92. package/dist/git.js +127 -0
  93. package/dist/git.js.map +1 -0
  94. package/dist/git.test.d.ts +2 -0
  95. package/dist/git.test.d.ts.map +1 -0
  96. package/dist/git.test.js +198 -0
  97. package/dist/git.test.js.map +1 -0
  98. package/dist/includes.d.ts +53 -0
  99. package/dist/includes.d.ts.map +1 -0
  100. package/dist/includes.js +73 -0
  101. package/dist/includes.js.map +1 -0
  102. package/dist/includes.test.d.ts +2 -0
  103. package/dist/includes.test.d.ts.map +1 -0
  104. package/dist/includes.test.js +106 -0
  105. package/dist/includes.test.js.map +1 -0
  106. package/dist/index.d.ts +33 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +23 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/links/__tests__/markdown.test.d.ts +2 -0
  111. package/dist/links/__tests__/markdown.test.d.ts.map +1 -0
  112. package/dist/links/__tests__/markdown.test.js +173 -0
  113. package/dist/links/__tests__/markdown.test.js.map +1 -0
  114. package/dist/links/__tests__/sidecar.test.d.ts +2 -0
  115. package/dist/links/__tests__/sidecar.test.d.ts.map +1 -0
  116. package/dist/links/__tests__/sidecar.test.js +238 -0
  117. package/dist/links/__tests__/sidecar.test.js.map +1 -0
  118. package/dist/links/index.d.ts +3 -0
  119. package/dist/links/index.d.ts.map +1 -0
  120. package/dist/links/index.js +3 -0
  121. package/dist/links/index.js.map +1 -0
  122. package/dist/links/markdown.d.ts +13 -0
  123. package/dist/links/markdown.d.ts.map +1 -0
  124. package/dist/links/markdown.js +93 -0
  125. package/dist/links/markdown.js.map +1 -0
  126. package/dist/links/sidecar.d.ts +12 -0
  127. package/dist/links/sidecar.d.ts.map +1 -0
  128. package/dist/links/sidecar.js +88 -0
  129. package/dist/links/sidecar.js.map +1 -0
  130. package/dist/manifest.d.ts +45 -0
  131. package/dist/manifest.d.ts.map +1 -0
  132. package/dist/manifest.js +269 -0
  133. package/dist/manifest.js.map +1 -0
  134. package/dist/manifest.test.d.ts +2 -0
  135. package/dist/manifest.test.d.ts.map +1 -0
  136. package/dist/manifest.test.js +625 -0
  137. package/dist/manifest.test.js.map +1 -0
  138. package/dist/multi-repo.test.d.ts +2 -0
  139. package/dist/multi-repo.test.d.ts.map +1 -0
  140. package/dist/multi-repo.test.js +179 -0
  141. package/dist/multi-repo.test.js.map +1 -0
  142. package/dist/node-path.d.ts +13 -0
  143. package/dist/node-path.d.ts.map +1 -0
  144. package/dist/node-path.js +21 -0
  145. package/dist/node-path.js.map +1 -0
  146. package/dist/node-path.test.d.ts +2 -0
  147. package/dist/node-path.test.d.ts.map +1 -0
  148. package/dist/node-path.test.js +29 -0
  149. package/dist/node-path.test.js.map +1 -0
  150. package/dist/published-links.d.ts +16 -0
  151. package/dist/published-links.d.ts.map +1 -0
  152. package/dist/published-links.js +59 -0
  153. package/dist/published-links.js.map +1 -0
  154. package/dist/published-links.test.d.ts +2 -0
  155. package/dist/published-links.test.d.ts.map +1 -0
  156. package/dist/published-links.test.js +82 -0
  157. package/dist/published-links.test.js.map +1 -0
  158. package/dist/repos.d.ts +32 -0
  159. package/dist/repos.d.ts.map +1 -0
  160. package/dist/repos.js +46 -0
  161. package/dist/repos.js.map +1 -0
  162. package/dist/repos.test.d.ts +2 -0
  163. package/dist/repos.test.d.ts.map +1 -0
  164. package/dist/repos.test.js +61 -0
  165. package/dist/repos.test.js.map +1 -0
  166. package/dist/scalar-source.d.ts +15 -0
  167. package/dist/scalar-source.d.ts.map +1 -0
  168. package/dist/scalar-source.js +21 -0
  169. package/dist/scalar-source.js.map +1 -0
  170. package/dist/search.d.ts +14 -0
  171. package/dist/search.d.ts.map +1 -0
  172. package/dist/search.js +59 -0
  173. package/dist/search.js.map +1 -0
  174. package/dist/service-concurrency.test.d.ts +2 -0
  175. package/dist/service-concurrency.test.d.ts.map +1 -0
  176. package/dist/service-concurrency.test.js +89 -0
  177. package/dist/service-concurrency.test.js.map +1 -0
  178. package/dist/service-history.test.d.ts +2 -0
  179. package/dist/service-history.test.d.ts.map +1 -0
  180. package/dist/service-history.test.js +76 -0
  181. package/dist/service-history.test.js.map +1 -0
  182. package/dist/service.d.ts +118 -0
  183. package/dist/service.d.ts.map +1 -0
  184. package/dist/service.js +347 -0
  185. package/dist/service.js.map +1 -0
  186. package/dist/service.test.d.ts +2 -0
  187. package/dist/service.test.d.ts.map +1 -0
  188. package/dist/service.test.js +313 -0
  189. package/dist/service.test.js.map +1 -0
  190. package/dist/types.d.ts +403 -0
  191. package/dist/types.d.ts.map +1 -0
  192. package/dist/types.js +2 -0
  193. package/dist/types.js.map +1 -0
  194. package/dist/validate/__tests__/artifacts.test.d.ts +2 -0
  195. package/dist/validate/__tests__/artifacts.test.d.ts.map +1 -0
  196. package/dist/validate/__tests__/artifacts.test.js +167 -0
  197. package/dist/validate/__tests__/artifacts.test.js.map +1 -0
  198. package/dist/validate/__tests__/assertions.test.d.ts +2 -0
  199. package/dist/validate/__tests__/assertions.test.d.ts.map +1 -0
  200. package/dist/validate/__tests__/assertions.test.js +254 -0
  201. package/dist/validate/__tests__/assertions.test.js.map +1 -0
  202. package/dist/validate/__tests__/duplicates.test.d.ts +2 -0
  203. package/dist/validate/__tests__/duplicates.test.d.ts.map +1 -0
  204. package/dist/validate/__tests__/duplicates.test.js +130 -0
  205. package/dist/validate/__tests__/duplicates.test.js.map +1 -0
  206. package/dist/validate/__tests__/edge-resolution.test.d.ts +2 -0
  207. package/dist/validate/__tests__/edge-resolution.test.d.ts.map +1 -0
  208. package/dist/validate/__tests__/edge-resolution.test.js +279 -0
  209. package/dist/validate/__tests__/edge-resolution.test.js.map +1 -0
  210. package/dist/validate/__tests__/history.test.d.ts +2 -0
  211. package/dist/validate/__tests__/history.test.d.ts.map +1 -0
  212. package/dist/validate/__tests__/history.test.js +93 -0
  213. package/dist/validate/__tests__/history.test.js.map +1 -0
  214. package/dist/validate/__tests__/includes.test.d.ts +2 -0
  215. package/dist/validate/__tests__/includes.test.d.ts.map +1 -0
  216. package/dist/validate/__tests__/includes.test.js +93 -0
  217. package/dist/validate/__tests__/includes.test.js.map +1 -0
  218. package/dist/validate/__tests__/registry.test.d.ts +2 -0
  219. package/dist/validate/__tests__/registry.test.d.ts.map +1 -0
  220. package/dist/validate/__tests__/registry.test.js +78 -0
  221. package/dist/validate/__tests__/registry.test.js.map +1 -0
  222. package/dist/validate/__tests__/run.test.d.ts +2 -0
  223. package/dist/validate/__tests__/run.test.d.ts.map +1 -0
  224. package/dist/validate/__tests__/run.test.js +215 -0
  225. package/dist/validate/__tests__/run.test.js.map +1 -0
  226. package/dist/validate/history.d.ts +23 -0
  227. package/dist/validate/history.d.ts.map +1 -0
  228. package/dist/validate/history.js +45 -0
  229. package/dist/validate/history.js.map +1 -0
  230. package/dist/validate/index.d.ts +10 -0
  231. package/dist/validate/index.d.ts.map +1 -0
  232. package/dist/validate/index.js +9 -0
  233. package/dist/validate/index.js.map +1 -0
  234. package/dist/validate/registry.d.ts +27 -0
  235. package/dist/validate/registry.d.ts.map +1 -0
  236. package/dist/validate/registry.js +67 -0
  237. package/dist/validate/registry.js.map +1 -0
  238. package/dist/validate/rules/artifacts.d.ts +25 -0
  239. package/dist/validate/rules/artifacts.d.ts.map +1 -0
  240. package/dist/validate/rules/artifacts.js +87 -0
  241. package/dist/validate/rules/artifacts.js.map +1 -0
  242. package/dist/validate/rules/assertions.d.ts +19 -0
  243. package/dist/validate/rules/assertions.d.ts.map +1 -0
  244. package/dist/validate/rules/assertions.js +149 -0
  245. package/dist/validate/rules/assertions.js.map +1 -0
  246. package/dist/validate/rules/duplicates.d.ts +20 -0
  247. package/dist/validate/rules/duplicates.d.ts.map +1 -0
  248. package/dist/validate/rules/duplicates.js +0 -0
  249. package/dist/validate/rules/duplicates.js.map +1 -0
  250. package/dist/validate/rules/edge-resolution.d.ts +15 -0
  251. package/dist/validate/rules/edge-resolution.d.ts.map +1 -0
  252. package/dist/validate/rules/edge-resolution.js +185 -0
  253. package/dist/validate/rules/edge-resolution.js.map +1 -0
  254. package/dist/validate/rules/includes.d.ts +21 -0
  255. package/dist/validate/rules/includes.d.ts.map +1 -0
  256. package/dist/validate/rules/includes.js +112 -0
  257. package/dist/validate/rules/includes.js.map +1 -0
  258. package/dist/validate/run.d.ts +20 -0
  259. package/dist/validate/run.d.ts.map +1 -0
  260. package/dist/validate/run.js +90 -0
  261. package/dist/validate/run.js.map +1 -0
  262. package/dist/validate/types.d.ts +101 -0
  263. package/dist/validate/types.d.ts.map +1 -0
  264. package/dist/validate/types.js +2 -0
  265. package/dist/validate/types.js.map +1 -0
  266. package/package.json +54 -0
@@ -0,0 +1,149 @@
1
+ export const ASSERT_VERSION_MISMATCH = {
2
+ id: "assert-version-mismatch",
3
+ description: "A link asserts a version its target no longer declares",
4
+ // The expensive one: a stale version pointer reads as current, and nothing
5
+ // about the document looks wrong to the reader acting on it.
6
+ defaultSeverity: "error",
7
+ };
8
+ export const ASSERT_LINE_COUNT_MISMATCH = {
9
+ id: "assert-line-count-mismatch",
10
+ description: "A link asserts a line count its target no longer has",
11
+ // A length claim drifts with every ordinary edit, so it warns rather than
12
+ // failing a build that is otherwise correct.
13
+ defaultSeverity: "warn",
14
+ };
15
+ export const ASSERT_MODIFIED_MISMATCH = {
16
+ id: "assert-modified-mismatch",
17
+ description: "A link asserts a modification date its target no longer matches",
18
+ defaultSeverity: "warn",
19
+ };
20
+ export const ASSERT_UNVERIFIABLE = {
21
+ id: "assert-unverifiable",
22
+ description: "A link asserts something that cannot be checked against its target",
23
+ // Not a mismatch — nothing is known to be wrong. But an assertion nobody can
24
+ // check is a check the author believes they have and does not.
25
+ defaultSeverity: "warn",
26
+ };
27
+ /** Properties a link may assert, for the message when it names something else. */
28
+ const ASSERTABLE = ["version", "lineCount", "modified"];
29
+ /** How far a `~N` line count may be off, as a fraction of the asserted value. */
30
+ const APPROX_TOLERANCE = 0.1;
31
+ function parseLineCount(asserted) {
32
+ if (typeof asserted === "number") {
33
+ return Number.isInteger(asserted) && asserted >= 0
34
+ ? { value: asserted, approximate: false }
35
+ : undefined;
36
+ }
37
+ if (typeof asserted !== "string")
38
+ return undefined;
39
+ const match = asserted.trim().match(/^(~?)\s*(\d+)$/);
40
+ return match ? { value: Number(match[2]), approximate: match[1] === "~" } : undefined;
41
+ }
42
+ function unverifiable(edge, property, asserted, reason, hint) {
43
+ return {
44
+ rule: ASSERT_UNVERIFIABLE.id,
45
+ message: `Cannot check the asserted ${property}: ${reason}`,
46
+ target: { kind: "edge", edge },
47
+ hint,
48
+ data: { property, asserted },
49
+ };
50
+ }
51
+ function mismatch(rule, edge, property, message, hint, asserted, actual) {
52
+ return {
53
+ rule: rule.id,
54
+ message,
55
+ target: { kind: "edge", edge },
56
+ hint,
57
+ data: { property, asserted, actual },
58
+ };
59
+ }
60
+ function checkVersion(edge, target, asserted) {
61
+ const claimed = String(asserted);
62
+ if (target.version === undefined) {
63
+ return unverifiable(edge, "version", claimed, `${target.id} declares no version`, "Add `version:` to the target's frontmatter, or drop the assertion.");
64
+ }
65
+ if (target.version === claimed)
66
+ return undefined;
67
+ return mismatch(ASSERT_VERSION_MISMATCH, edge, "version", `${target.id} is version ${target.version}, not ${claimed}`, `Update the assertion to ${target.version}, and check whether the surrounding prose cites the old version too.`, claimed, target.version);
68
+ }
69
+ function checkLineCount(edge, target, asserted) {
70
+ const claim = parseLineCount(asserted);
71
+ if (!claim) {
72
+ return unverifiable(edge, "lineCount", asserted, `${JSON.stringify(asserted)} is not a line count`, 'Write a whole number, or "~3500" to allow ten percent either way.');
73
+ }
74
+ const actual = target.lineCount;
75
+ if (actual === undefined) {
76
+ return unverifiable(edge, "lineCount", asserted, `${target.id} has no line count`, "Only a document Weft read from disk has one; a node an external tool declared may not.");
77
+ }
78
+ const satisfied = claim.approximate
79
+ ? Math.abs(actual - claim.value) <= claim.value * APPROX_TOLERANCE
80
+ : actual === claim.value;
81
+ if (satisfied)
82
+ return undefined;
83
+ return mismatch(ASSERT_LINE_COUNT_MISMATCH, edge, "lineCount", `${target.id} has ${actual} lines, not ${claim.approximate ? `~${claim.value}` : claim.value}`, `Update the assertion to ${actual}${claim.approximate ? `, or widen it to ~${actual}` : ""}.`, asserted, actual);
84
+ }
85
+ function checkModified(edge, target, asserted) {
86
+ const claimed = String(asserted);
87
+ if (!target.modified) {
88
+ return unverifiable(edge, "modified", claimed, `${target.id} has no modification date`, "Dates come from git history, so the file has to be committed and the project a repository.");
89
+ }
90
+ // A prefix, so "2026-07" asserts the month and a full timestamp asserts the
91
+ // instant. The alternative — parsing both sides into dates — would make
92
+ // "2026-07" mean midnight on the first, which is not what it says.
93
+ if (target.modified.startsWith(claimed))
94
+ return undefined;
95
+ const actual = target.modified.slice(0, 10);
96
+ return mismatch(ASSERT_MODIFIED_MISMATCH, edge, "modified", `${target.id} last changed ${actual}, which does not match ${claimed}`, `Update the assertion to ${actual}, or to a prefix of it.`, claimed, target.modified);
97
+ }
98
+ /**
99
+ * Check the claims links make about the documents they point at.
100
+ *
101
+ * A version cited across several documents is the most expensive thing in a
102
+ * documentation set to maintain by hand, because nothing signals when one goes
103
+ * stale: the claim was true when written, the prose still reads as current, and
104
+ * the discovery is accidental. This turns that into a build failure.
105
+ *
106
+ * Only assertions are checked here. Whether the link resolves at all belongs to
107
+ * the edge-resolution rules, so an edge whose target is missing or still pending
108
+ * is left to them rather than reported twice.
109
+ */
110
+ export const assertionValidator = {
111
+ rules: [
112
+ ASSERT_VERSION_MISMATCH,
113
+ ASSERT_LINE_COUNT_MISMATCH,
114
+ ASSERT_MODIFIED_MISMATCH,
115
+ ASSERT_UNVERIFIABLE,
116
+ ],
117
+ run({ manifest, nodes }) {
118
+ const findings = [];
119
+ for (const edge of manifest.edges) {
120
+ if (!edge.asserts || edge.pending)
121
+ continue;
122
+ const target = nodes.get(edge.to.node);
123
+ if (!target)
124
+ continue;
125
+ for (const [property, asserted] of Object.entries(edge.asserts)) {
126
+ if (asserted === undefined || asserted === null)
127
+ continue;
128
+ let finding;
129
+ switch (property) {
130
+ case "version":
131
+ finding = checkVersion(edge, target, asserted);
132
+ break;
133
+ case "lineCount":
134
+ finding = checkLineCount(edge, target, asserted);
135
+ break;
136
+ case "modified":
137
+ finding = checkModified(edge, target, asserted);
138
+ break;
139
+ default:
140
+ finding = unverifiable(edge, property, asserted, `no node property is called ${property}`, `Assertable properties are ${ASSERTABLE.join(", ")}.`);
141
+ }
142
+ if (finding)
143
+ findings.push(finding);
144
+ }
145
+ }
146
+ return findings;
147
+ },
148
+ };
149
+ //# sourceMappingURL=assertions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.js","sourceRoot":"","sources":["../../../src/validate/rules/assertions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Rule, Validator } from "../types.js";
2
+ export declare const NODE_DUPLICATE: Rule;
3
+ export declare const NODE_DIVERGED: Rule;
4
+ /**
5
+ * Report copies of one document, both while they still agree and once they
6
+ * have stopped.
7
+ *
8
+ * Two halves, because a copy is a different problem before and after it drifts.
9
+ * Identical copies are found by comparing current content hashes. Diverged ones
10
+ * cannot be — the moment two files differ they no longer share a hash, so a
11
+ * check built only on that goes silent exactly when the problem appears. Git
12
+ * blobs answer the question the hashes no longer can: these two paths held the
13
+ * same content once, and do not now.
14
+ *
15
+ * Both halves read only nodes that reached the manifest, so `ignore` is already
16
+ * respected and a build output directory excluded from indexing cannot make
17
+ * every document in the project look like a copy of itself.
18
+ */
19
+ export declare const duplicateValidator: Validator;
20
+ //# sourceMappingURL=duplicates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicates.d.ts","sourceRoot":"","sources":["../../../src/validate/rules/duplicates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAyB,IAAI,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE1E,eAAO,MAAM,cAAc,EAAE,IAO5B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,IAM3B,CAAC;AA4BF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAgChC,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicates.js","sourceRoot":"","sources":["../../../src/validate/rules/duplicates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { Rule, Validator } from "../types.js";
2
+ export declare const EDGE_TARGET_MISSING: Rule;
3
+ export declare const EDGE_ANCHOR_MISSING: Rule;
4
+ export declare const EDGE_SOURCE_ANCHOR_MISSING: Rule;
5
+ export declare const EDGE_PENDING: Rule;
6
+ export declare const EDGE_PENDING_RESOLVED: Rule;
7
+ /**
8
+ * Check that every edge resolves against the graph it belongs to.
9
+ *
10
+ * Nothing new is extracted here — this is a set difference over the built
11
+ * manifest. `edge.to.node` must be a node, and `edge.to.anchor` must be one of
12
+ * that node's anchors.
13
+ */
14
+ export declare const edgeResolutionValidator: Validator;
15
+ //# sourceMappingURL=edge-resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-resolution.d.ts","sourceRoot":"","sources":["../../../src/validate/rules/edge-resolution.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,IAAI,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE5D,eAAO,MAAM,mBAAmB,EAAE,IAIjC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,IAIjC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,IAIxC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,IAI1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,IAInC,CAAC;AAiDF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAsHrC,CAAC"}
@@ -0,0 +1,185 @@
1
+ import { isIndexedPath, resolveIndexedExtensions } from "../../manifest.js";
2
+ export const EDGE_TARGET_MISSING = {
3
+ id: "edge-target-missing",
4
+ description: "An edge points at a document that is not in the graph",
5
+ defaultSeverity: "error",
6
+ };
7
+ export const EDGE_ANCHOR_MISSING = {
8
+ id: "edge-anchor-missing",
9
+ description: "An edge points at an anchor its target document does not define",
10
+ defaultSeverity: "error",
11
+ };
12
+ export const EDGE_SOURCE_ANCHOR_MISSING = {
13
+ id: "edge-source-anchor-missing",
14
+ description: "An edge declares a source anchor its own document does not define",
15
+ defaultSeverity: "error",
16
+ };
17
+ export const EDGE_PENDING = {
18
+ id: "edge-pending",
19
+ description: "An edge marked pending still does not resolve",
20
+ defaultSeverity: "info",
21
+ };
22
+ export const EDGE_PENDING_RESOLVED = {
23
+ id: "edge-pending-resolved",
24
+ description: "An edge marked pending now resolves, so the marker can be dropped",
25
+ defaultSeverity: "info",
26
+ };
27
+ /** Levenshtein distance, iterative with two rows. */
28
+ function distance(a, b) {
29
+ if (a === b)
30
+ return 0;
31
+ if (!a.length)
32
+ return b.length;
33
+ if (!b.length)
34
+ return a.length;
35
+ let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
36
+ for (let i = 1; i <= a.length; i++) {
37
+ const current = [i];
38
+ for (let j = 1; j <= b.length; j++) {
39
+ const substitution = previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1);
40
+ current[j] = Math.min(current[j - 1] + 1, previous[j] + 1, substitution);
41
+ }
42
+ previous = current;
43
+ }
44
+ return previous[b.length];
45
+ }
46
+ /**
47
+ * Find the anchor a broken one was most likely renamed from.
48
+ *
49
+ * A slug that vanished while a very similar one exists is a reworded heading,
50
+ * not a deleted section — the distinction a bare slug list could never express.
51
+ * The threshold scales with length so short slugs are not matched on noise.
52
+ */
53
+ function closestAnchor(anchors, missing) {
54
+ const limit = Math.max(2, Math.floor(missing.length * 0.25));
55
+ let best;
56
+ let bestDistance = Number.POSITIVE_INFINITY;
57
+ for (const anchor of anchors) {
58
+ const d = distance(missing.toLowerCase(), anchor.slug.toLowerCase());
59
+ if (d < bestDistance) {
60
+ bestDistance = d;
61
+ best = anchor;
62
+ }
63
+ }
64
+ return bestDistance <= limit ? best : undefined;
65
+ }
66
+ function hasAnchor(node, slug) {
67
+ return node.anchors.some((anchor) => anchor.slug === slug);
68
+ }
69
+ /**
70
+ * Check that every edge resolves against the graph it belongs to.
71
+ *
72
+ * Nothing new is extracted here — this is a set difference over the built
73
+ * manifest. `edge.to.node` must be a node, and `edge.to.anchor` must be one of
74
+ * that node's anchors.
75
+ */
76
+ export const edgeResolutionValidator = {
77
+ rules: [
78
+ EDGE_TARGET_MISSING,
79
+ EDGE_ANCHOR_MISSING,
80
+ EDGE_SOURCE_ANCHOR_MISSING,
81
+ EDGE_PENDING,
82
+ EDGE_PENDING_RESOLVED,
83
+ ],
84
+ // Only to explain a broken link, never to decide there is one.
85
+ needsHistory: true,
86
+ run({ manifest, nodes, history, config }) {
87
+ const findings = [];
88
+ const indexedExtensions = resolveIndexedExtensions(config);
89
+ for (const edge of manifest.edges) {
90
+ // A declared source anchor is a claim about the document making the
91
+ // link, so it is checked whatever happens at the other end.
92
+ if (edge.from.anchor) {
93
+ const source = nodes.get(edge.from.node);
94
+ if (source && !hasAnchor(source, edge.from.anchor)) {
95
+ const suggestion = closestAnchor(source.anchors, edge.from.anchor);
96
+ findings.push({
97
+ rule: EDGE_SOURCE_ANCHOR_MISSING.id,
98
+ message: `${edge.from.node} defines no anchor ${edge.from.anchor}`,
99
+ target: { kind: "edge", edge },
100
+ ...(suggestion
101
+ ? { hint: `Did you mean ${suggestion.slug} ("${suggestion.text}")?` }
102
+ : {}),
103
+ data: {
104
+ anchor: edge.from.anchor,
105
+ ...(suggestion ? { suggestion: suggestion.slug } : {}),
106
+ },
107
+ });
108
+ }
109
+ }
110
+ // Weft only makes nodes from documents it indexes, so a link to an
111
+ // image or a PDF was never going to resolve to one. That is not a
112
+ // broken reference, and reporting it would bury the real ones.
113
+ if (!isIndexedPath(edge.to.node, indexedExtensions))
114
+ continue;
115
+ const target = nodes.get(edge.to.node);
116
+ if (!target) {
117
+ if (edge.pending) {
118
+ findings.push({
119
+ rule: EDGE_PENDING.id,
120
+ message: "Target document does not exist yet",
121
+ target: { kind: "edge", edge },
122
+ });
123
+ continue;
124
+ }
125
+ // Moving a document is ordinary maintenance, and it breaks every
126
+ // link to it. Git already knows what moved where, so say so rather
127
+ // than leaving a pile of dangling references to be worked out by
128
+ // hand. Only when the destination is really in the graph — a rename
129
+ // to something since deleted explains nothing.
130
+ const movedTo = history.renames.get(edge.to.node);
131
+ const renamedTo = movedTo && nodes.has(movedTo) ? movedTo : undefined;
132
+ findings.push({
133
+ rule: EDGE_TARGET_MISSING.id,
134
+ message: renamedTo
135
+ ? `${edge.to.node} moved to ${renamedTo}`
136
+ : `No document ${edge.to.node} is in the graph`,
137
+ target: { kind: "edge", edge },
138
+ hint: renamedTo
139
+ ? `Point the link at ${renamedTo}.`
140
+ : "Create the document, fix the path, or mark the link pending in a sidecar.",
141
+ data: { target: edge.to.node, ...(renamedTo ? { renamedTo } : {}) },
142
+ });
143
+ continue;
144
+ }
145
+ if (edge.to.anchor && !hasAnchor(target, edge.to.anchor)) {
146
+ if (edge.pending) {
147
+ findings.push({
148
+ rule: EDGE_PENDING.id,
149
+ message: "Target anchor does not exist yet",
150
+ target: { kind: "edge", edge },
151
+ });
152
+ continue;
153
+ }
154
+ const suggestion = closestAnchor(target.anchors, edge.to.anchor);
155
+ findings.push({
156
+ rule: EDGE_ANCHOR_MISSING.id,
157
+ // Worth separating from a missing document: the target is right
158
+ // and only the heading moved, which is a different fix.
159
+ message: `${edge.to.node} exists but defines no anchor ${edge.to.anchor}`,
160
+ target: { kind: "edge", edge },
161
+ hint: suggestion
162
+ ? `Did you mean ${suggestion.slug} ("${suggestion.text}")?`
163
+ : "No similarly named anchor exists; the section may have been removed.",
164
+ data: {
165
+ target: edge.to.node,
166
+ anchor: edge.to.anchor,
167
+ ...(suggestion ? { suggestion: suggestion.slug } : {}),
168
+ },
169
+ });
170
+ continue;
171
+ }
172
+ // Resolves, but is still carrying a pending marker — say so, or the
173
+ // suppression outlives the reason for it.
174
+ if (edge.pending) {
175
+ findings.push({
176
+ rule: EDGE_PENDING_RESOLVED.id,
177
+ message: "Resolves now, so `pending: true` can be removed",
178
+ target: { kind: "edge", edge },
179
+ });
180
+ }
181
+ }
182
+ return findings;
183
+ },
184
+ };
185
+ //# sourceMappingURL=edge-resolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-resolution.js","sourceRoot":"","sources":["../../../src/validate/rules/edge-resolution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Rule, Validator } from "../types.js";
2
+ export declare const INCLUDE_CYCLE: Rule;
3
+ /**
4
+ * Report cycles in the `includes` edge graph.
5
+ *
6
+ * Cycles are detected at document granularity even when the edges select anchor
7
+ * ranges: a range that provably excludes the back-reference is possible in
8
+ * principle, but proving it means re-implementing range extraction here and
9
+ * keeping two implementations agreeing forever. Simplicity wins — a document
10
+ * pair that includes each other's disjoint halves is rare enough to restructure.
11
+ *
12
+ * Each cycle is reported once, keyed by its sorted member set, so a cycle of
13
+ * three documents is one finding rather than three. The finding targets the
14
+ * graph: nothing knows which document started it, and naming one would imply
15
+ * the others are innocent.
16
+ *
17
+ * Pending edges are skipped — the target does not exist yet, so nothing can
18
+ * expand through it, and `edge-pending` already reports the marker.
19
+ */
20
+ export declare const includeValidator: Validator;
21
+ //# sourceMappingURL=includes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"includes.d.ts","sourceRoot":"","sources":["../../../src/validate/rules/includes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAW,IAAI,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE5D,eAAO,MAAM,aAAa,EAAE,IAM3B,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAyB9B,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { INCLUDES } from "../../includes.js";
2
+ export const INCLUDE_CYCLE = {
3
+ id: "include-cycle",
4
+ description: "Documents include each other in a cycle, so no composed form of them exists",
5
+ // A cycle is not a matter of taste: expanding it terminates nowhere, and the
6
+ // renderer's own guard degrades the page rather than fixing the graph.
7
+ defaultSeverity: "error",
8
+ };
9
+ /**
10
+ * Report cycles in the `includes` edge graph.
11
+ *
12
+ * Cycles are detected at document granularity even when the edges select anchor
13
+ * ranges: a range that provably excludes the back-reference is possible in
14
+ * principle, but proving it means re-implementing range extraction here and
15
+ * keeping two implementations agreeing forever. Simplicity wins — a document
16
+ * pair that includes each other's disjoint halves is rare enough to restructure.
17
+ *
18
+ * Each cycle is reported once, keyed by its sorted member set, so a cycle of
19
+ * three documents is one finding rather than three. The finding targets the
20
+ * graph: nothing knows which document started it, and naming one would imply
21
+ * the others are innocent.
22
+ *
23
+ * Pending edges are skipped — the target does not exist yet, so nothing can
24
+ * expand through it, and `edge-pending` already reports the marker.
25
+ */
26
+ export const includeValidator = {
27
+ rules: [INCLUDE_CYCLE],
28
+ run({ manifest }) {
29
+ const adjacency = new Map();
30
+ for (const edge of manifest.edges) {
31
+ if (edge.type !== INCLUDES || edge.pending)
32
+ continue;
33
+ const targets = adjacency.get(edge.from.node) ?? new Set();
34
+ targets.add(edge.to.node);
35
+ adjacency.set(edge.from.node, targets);
36
+ }
37
+ const findings = [];
38
+ for (const cycle of findCycles(adjacency)) {
39
+ const members = [...cycle].sort();
40
+ findings.push({
41
+ rule: INCLUDE_CYCLE.id,
42
+ message: `Include cycle: ${members.join(" → ")} → ${members[0]}`,
43
+ target: { kind: "graph" },
44
+ hint: "Break the cycle by removing one include, or restructure so the shared content lives in a document neither includes.",
45
+ data: { nodes: members },
46
+ });
47
+ }
48
+ return findings;
49
+ },
50
+ };
51
+ /**
52
+ * Strongly connected components with more than one member, plus self-loops —
53
+ * exactly the node sets whose expansion never terminates. Tarjan, iteratively,
54
+ * so a pathological include chain cannot overflow the call stack.
55
+ */
56
+ function findCycles(adjacency) {
57
+ const index = new Map();
58
+ const lowlink = new Map();
59
+ const onStack = new Set();
60
+ const stack = [];
61
+ const cycles = [];
62
+ let counter = 0;
63
+ for (const start of adjacency.keys()) {
64
+ if (index.has(start))
65
+ continue;
66
+ // Each frame is a node plus an iterator over its unvisited successors.
67
+ const frames = [];
68
+ const push = (node) => {
69
+ index.set(node, counter);
70
+ lowlink.set(node, counter);
71
+ counter++;
72
+ stack.push(node);
73
+ onStack.add(node);
74
+ frames.push({ node, successors: (adjacency.get(node) ?? new Set()).values() });
75
+ };
76
+ push(start);
77
+ while (frames.length) {
78
+ const frame = frames[frames.length - 1];
79
+ const next = frame.successors.next();
80
+ if (!next.done) {
81
+ const target = next.value;
82
+ if (!index.has(target))
83
+ push(target);
84
+ else if (onStack.has(target)) {
85
+ const low = Math.min(lowlink.get(frame.node), index.get(target));
86
+ lowlink.set(frame.node, low);
87
+ }
88
+ continue;
89
+ }
90
+ frames.pop();
91
+ const parent = frames[frames.length - 1];
92
+ if (parent) {
93
+ const low = Math.min(lowlink.get(parent.node), lowlink.get(frame.node));
94
+ lowlink.set(parent.node, low);
95
+ }
96
+ if (lowlink.get(frame.node) === index.get(frame.node)) {
97
+ const component = [];
98
+ let member;
99
+ do {
100
+ member = stack.pop();
101
+ onStack.delete(member);
102
+ component.push(member);
103
+ } while (member !== frame.node);
104
+ const selfLoop = component.length === 1 && adjacency.get(frame.node)?.has(frame.node);
105
+ if (component.length > 1 || selfLoop)
106
+ cycles.push(component);
107
+ }
108
+ }
109
+ }
110
+ return cycles;
111
+ }
112
+ //# sourceMappingURL=includes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"includes.js","sourceRoot":"","sources":["../../../src/validate/rules/includes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,MAAM,CAAC,MAAM,aAAa,GAAS;IAClC,EAAE,EAAE,eAAe;IACnB,WAAW,EAAE,6EAA6E;IAC1F,6EAA6E;IAC7E,uEAAuE;IACvE,eAAe,EAAE,OAAO;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAc;IAC1C,KAAK,EAAE,CAAC,aAAa,CAAC;IAEtB,GAAG,CAAC,EAAE,QAAQ,EAAE;QACf,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO;gBAAE,SAAS;YACrD,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;YAC3D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC1B,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,aAAa,CAAC,EAAE;gBACtB,OAAO,EAAE,kBAAkB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE;gBAChE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;gBACzB,IAAI,EAAE,qHAAqH;gBAC3H,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE;aACxB,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IACjB,CAAC;CACD,CAAC;AAEF;;;;GAIG;AACH,SAAS,UAAU,CAAC,SAAmC;IACtD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAE/B,uEAAuE;QACvE,MAAM,MAAM,GAAqD,EAAE,CAAC;QACpE,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;YAC7B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC3B,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChF,CAAC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC;QAEZ,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YAErC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;oBAAE,IAAI,CAAC,MAAM,CAAC,CAAC;qBAChC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAW,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAW,CAAC,CAAC;oBACrF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAC9B,CAAC;gBACD,SAAS;YACV,CAAC;YAED,MAAM,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAW,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAW,CAAC,CAAC;gBAC5F,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/B,CAAC;YAED,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvD,MAAM,SAAS,GAAa,EAAE,CAAC;gBAC/B,IAAI,MAAc,CAAC;gBACnB,GAAG,CAAC;oBACH,MAAM,GAAG,KAAK,CAAC,GAAG,EAAY,CAAC;oBAC/B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACvB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC,QAAQ,MAAM,KAAK,KAAK,CAAC,IAAI,EAAE;gBAEhC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACtF,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ;oBAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9D,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Manifest, WeftConfig } from "../types.js";
2
+ import { type ValidatorRegistry } from "./registry.js";
3
+ import type { GraphHistory, ValidationResult } from "./types.js";
4
+ /**
5
+ * Whether running this registry under this config will read git history.
6
+ *
7
+ * Exported so a caller that builds the graph itself — the service — can pay
8
+ * for one full history walk up front and hand the result to both the indexer
9
+ * and {@link validateManifest}, instead of each walking on its own.
10
+ */
11
+ export declare function registryWantsHistory(registry: ValidatorRegistry, config: WeftConfig): boolean;
12
+ /**
13
+ * Run every registered check over a built manifest.
14
+ *
15
+ * Validation is a separate stage from extraction on purpose: it reads the
16
+ * finished graph and never mutates it, so a check can be added without touching
17
+ * the indexer.
18
+ */
19
+ export declare function validateManifest(manifest: Manifest, config: WeftConfig, registry?: ValidatorRegistry, precomputedHistory?: GraphHistory): Promise<ValidationResult>;
20
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/validate/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAA0B,UAAU,EAAY,MAAM,aAAa,CAAC;AAE1F,OAAO,EAAwB,KAAK,iBAAiB,EAAmB,MAAM,eAAe,CAAC;AAC9F,OAAO,KAAK,EAGX,YAAY,EAGZ,gBAAgB,EAChB,MAAM,YAAY,CAAC;AAOpB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAK7F;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,UAAU,EAClB,QAAQ,GAAE,iBAAqC,EAC/C,kBAAkB,CAAC,EAAE,YAAY,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAyE3B"}