@jasonbelmonti/markdown-engine 1.0.0 → 3.0.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 (373) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +113 -56
  3. package/SECURITY.md +5 -3
  4. package/dist/api/annotation-source-range.d.ts +7 -0
  5. package/dist/api/annotation-source-range.d.ts.map +1 -0
  6. package/dist/api/annotation-source-range.js +103 -0
  7. package/dist/api/annotation-source-range.js.map +1 -0
  8. package/dist/api/annotation-target-candidate.d.ts +10 -0
  9. package/dist/api/annotation-target-candidate.d.ts.map +1 -0
  10. package/dist/api/annotation-target-candidate.js +14 -0
  11. package/dist/api/annotation-target-candidate.js.map +1 -0
  12. package/dist/api/annotation-target-cloning.d.ts +5 -0
  13. package/dist/api/annotation-target-cloning.d.ts.map +1 -0
  14. package/dist/api/annotation-target-cloning.js +122 -0
  15. package/dist/api/annotation-target-cloning.js.map +1 -0
  16. package/dist/api/annotation-target-diagnostics.d.ts +8 -0
  17. package/dist/api/annotation-target-diagnostics.d.ts.map +1 -0
  18. package/dist/api/annotation-target-diagnostics.js +57 -0
  19. package/dist/api/annotation-target-diagnostics.js.map +1 -0
  20. package/dist/api/annotation-target-validation.d.ts +2 -2
  21. package/dist/api/annotation-target-validation.d.ts.map +1 -1
  22. package/dist/api/annotation-target-validation.js +5 -272
  23. package/dist/api/annotation-target-validation.js.map +1 -1
  24. package/dist/api/contracts.d.ts +2 -1
  25. package/dist/api/contracts.d.ts.map +1 -1
  26. package/dist/api/contracts.js +1 -0
  27. package/dist/api/contracts.js.map +1 -1
  28. package/dist/api/declarative-validation.d.ts +13 -0
  29. package/dist/api/declarative-validation.d.ts.map +1 -0
  30. package/dist/api/declarative-validation.js +85 -0
  31. package/dist/api/declarative-validation.js.map +1 -0
  32. package/dist/api/document-queries.d.ts.map +1 -1
  33. package/dist/api/document-queries.js +74 -3
  34. package/dist/api/document-queries.js.map +1 -1
  35. package/dist/api/document.d.ts +44 -0
  36. package/dist/api/document.d.ts.map +1 -1
  37. package/dist/api/engine-node-attributes.d.ts +15 -0
  38. package/dist/api/engine-node-attributes.d.ts.map +1 -0
  39. package/dist/api/engine-node-attributes.js +99 -0
  40. package/dist/api/engine-node-attributes.js.map +1 -0
  41. package/dist/api/normalize.d.ts.map +1 -1
  42. package/dist/api/normalize.js +22 -1
  43. package/dist/api/normalize.js.map +1 -1
  44. package/dist/api/serialize.js +2 -14
  45. package/dist/api/serialize.js.map +1 -1
  46. package/dist/cli/args.d.ts +6 -2
  47. package/dist/cli/args.d.ts.map +1 -1
  48. package/dist/cli/args.js +33 -25
  49. package/dist/cli/args.js.map +1 -1
  50. package/dist/cli/declarative-validation.d.ts +18 -0
  51. package/dist/cli/declarative-validation.d.ts.map +1 -0
  52. package/dist/cli/declarative-validation.js +126 -0
  53. package/dist/cli/declarative-validation.js.map +1 -0
  54. package/dist/cli/files.d.ts +1 -0
  55. package/dist/cli/files.d.ts.map +1 -1
  56. package/dist/cli/files.js +3 -0
  57. package/dist/cli/files.js.map +1 -1
  58. package/dist/cli/run.d.ts.map +1 -1
  59. package/dist/cli/run.js +18 -3
  60. package/dist/cli/run.js.map +1 -1
  61. package/dist/cli/validate-args.d.ts +18 -0
  62. package/dist/cli/validate-args.d.ts.map +1 -0
  63. package/dist/cli/validate-args.js +131 -0
  64. package/dist/cli/validate-args.js.map +1 -0
  65. package/dist/declarative-validation/applicability/classifier.d.ts +18 -0
  66. package/dist/declarative-validation/applicability/classifier.d.ts.map +1 -0
  67. package/dist/declarative-validation/applicability/classifier.js +37 -0
  68. package/dist/declarative-validation/applicability/classifier.js.map +1 -0
  69. package/dist/declarative-validation/applicability/index.d.ts +2 -0
  70. package/dist/declarative-validation/applicability/index.d.ts.map +1 -0
  71. package/dist/declarative-validation/applicability/index.js +2 -0
  72. package/dist/declarative-validation/applicability/index.js.map +1 -0
  73. package/dist/declarative-validation/assertions/context.d.ts +8 -0
  74. package/dist/declarative-validation/assertions/context.d.ts.map +1 -0
  75. package/dist/declarative-validation/assertions/context.js +2 -0
  76. package/dist/declarative-validation/assertions/context.js.map +1 -0
  77. package/dist/declarative-validation/assertions/diagnostics.d.ts +25 -0
  78. package/dist/declarative-validation/assertions/diagnostics.d.ts.map +1 -0
  79. package/dist/declarative-validation/assertions/diagnostics.js +96 -0
  80. package/dist/declarative-validation/assertions/diagnostics.js.map +1 -0
  81. package/dist/declarative-validation/assertions/document-text-offsets.d.ts +3 -0
  82. package/dist/declarative-validation/assertions/document-text-offsets.d.ts.map +1 -0
  83. package/dist/declarative-validation/assertions/document-text-offsets.js +32 -0
  84. package/dist/declarative-validation/assertions/document-text-offsets.js.map +1 -0
  85. package/dist/declarative-validation/assertions/evaluator.d.ts +5 -0
  86. package/dist/declarative-validation/assertions/evaluator.d.ts.map +1 -0
  87. package/dist/declarative-validation/assertions/evaluator.js +49 -0
  88. package/dist/declarative-validation/assertions/evaluator.js.map +1 -0
  89. package/dist/declarative-validation/assertions/exists.d.ts +4 -0
  90. package/dist/declarative-validation/assertions/exists.d.ts.map +1 -0
  91. package/dist/declarative-validation/assertions/exists.js +8 -0
  92. package/dist/declarative-validation/assertions/exists.js.map +1 -0
  93. package/dist/declarative-validation/assertions/frontmatter-required.d.ts +9 -0
  94. package/dist/declarative-validation/assertions/frontmatter-required.d.ts.map +1 -0
  95. package/dist/declarative-validation/assertions/frontmatter-required.js +15 -0
  96. package/dist/declarative-validation/assertions/frontmatter-required.js.map +1 -0
  97. package/dist/declarative-validation/assertions/group-evaluator.d.ts +6 -0
  98. package/dist/declarative-validation/assertions/group-evaluator.d.ts.map +1 -0
  99. package/dist/declarative-validation/assertions/group-evaluator.js +57 -0
  100. package/dist/declarative-validation/assertions/group-evaluator.js.map +1 -0
  101. package/dist/declarative-validation/assertions/id-targets.d.ts +44 -0
  102. package/dist/declarative-validation/assertions/id-targets.d.ts.map +1 -0
  103. package/dist/declarative-validation/assertions/id-targets.js +391 -0
  104. package/dist/declarative-validation/assertions/id-targets.js.map +1 -0
  105. package/dist/declarative-validation/assertions/id-tokens.d.ts +15 -0
  106. package/dist/declarative-validation/assertions/id-tokens.d.ts.map +1 -0
  107. package/dist/declarative-validation/assertions/id-tokens.js +27 -0
  108. package/dist/declarative-validation/assertions/id-tokens.js.map +1 -0
  109. package/dist/declarative-validation/assertions/ids.d.ts +9 -0
  110. package/dist/declarative-validation/assertions/ids.d.ts.map +1 -0
  111. package/dist/declarative-validation/assertions/ids.js +128 -0
  112. package/dist/declarative-validation/assertions/ids.js.map +1 -0
  113. package/dist/declarative-validation/assertions/index.d.ts +4 -0
  114. package/dist/declarative-validation/assertions/index.d.ts.map +1 -0
  115. package/dist/declarative-validation/assertions/index.js +4 -0
  116. package/dist/declarative-validation/assertions/index.js.map +1 -0
  117. package/dist/declarative-validation/assertions/literal-text.d.ts +2 -0
  118. package/dist/declarative-validation/assertions/literal-text.d.ts.map +1 -0
  119. package/dist/declarative-validation/assertions/literal-text.js +14 -0
  120. package/dist/declarative-validation/assertions/literal-text.js.map +1 -0
  121. package/dist/declarative-validation/assertions/normalized-source-ranges.d.ts +3 -0
  122. package/dist/declarative-validation/assertions/normalized-source-ranges.d.ts.map +1 -0
  123. package/dist/declarative-validation/assertions/normalized-source-ranges.js +105 -0
  124. package/dist/declarative-validation/assertions/normalized-source-ranges.js.map +1 -0
  125. package/dist/declarative-validation/assertions/ordering.d.ts +6 -0
  126. package/dist/declarative-validation/assertions/ordering.d.ts.map +1 -0
  127. package/dist/declarative-validation/assertions/ordering.js +71 -0
  128. package/dist/declarative-validation/assertions/ordering.js.map +1 -0
  129. package/dist/declarative-validation/assertions/references.d.ts +9 -0
  130. package/dist/declarative-validation/assertions/references.d.ts.map +1 -0
  131. package/dist/declarative-validation/assertions/references.js +354 -0
  132. package/dist/declarative-validation/assertions/references.js.map +1 -0
  133. package/dist/declarative-validation/assertions/sections-required.d.ts +9 -0
  134. package/dist/declarative-validation/assertions/sections-required.d.ts.map +1 -0
  135. package/dist/declarative-validation/assertions/sections-required.js +49 -0
  136. package/dist/declarative-validation/assertions/sections-required.js.map +1 -0
  137. package/dist/declarative-validation/assertions/table-column-coverage.d.ts +9 -0
  138. package/dist/declarative-validation/assertions/table-column-coverage.d.ts.map +1 -0
  139. package/dist/declarative-validation/assertions/table-column-coverage.js +108 -0
  140. package/dist/declarative-validation/assertions/table-column-coverage.js.map +1 -0
  141. package/dist/declarative-validation/assertions/table-columns-required.d.ts +9 -0
  142. package/dist/declarative-validation/assertions/table-columns-required.d.ts.map +1 -0
  143. package/dist/declarative-validation/assertions/table-columns-required.js +31 -0
  144. package/dist/declarative-validation/assertions/table-columns-required.js.map +1 -0
  145. package/dist/declarative-validation/assertions/text-length.d.ts +9 -0
  146. package/dist/declarative-validation/assertions/text-length.d.ts.map +1 -0
  147. package/dist/declarative-validation/assertions/text-length.js +40 -0
  148. package/dist/declarative-validation/assertions/text-length.js.map +1 -0
  149. package/dist/declarative-validation/assertions/text-occurrence-count.d.ts +9 -0
  150. package/dist/declarative-validation/assertions/text-occurrence-count.d.ts.map +1 -0
  151. package/dist/declarative-validation/assertions/text-occurrence-count.js +22 -0
  152. package/dist/declarative-validation/assertions/text-occurrence-count.js.map +1 -0
  153. package/dist/declarative-validation/assertions/text.d.ts +9 -0
  154. package/dist/declarative-validation/assertions/text.d.ts.map +1 -0
  155. package/dist/declarative-validation/assertions/text.js +32 -0
  156. package/dist/declarative-validation/assertions/text.js.map +1 -0
  157. package/dist/declarative-validation/compiler/applicability-plan.d.ts +5 -0
  158. package/dist/declarative-validation/compiler/applicability-plan.d.ts.map +1 -0
  159. package/dist/declarative-validation/compiler/applicability-plan.js +22 -0
  160. package/dist/declarative-validation/compiler/applicability-plan.js.map +1 -0
  161. package/dist/declarative-validation/compiler/assertion-builders.d.ts +7 -0
  162. package/dist/declarative-validation/compiler/assertion-builders.d.ts.map +1 -0
  163. package/dist/declarative-validation/compiler/assertion-builders.js +237 -0
  164. package/dist/declarative-validation/compiler/assertion-builders.js.map +1 -0
  165. package/dist/declarative-validation/compiler/assertion-shapes.d.ts +20 -0
  166. package/dist/declarative-validation/compiler/assertion-shapes.d.ts.map +1 -0
  167. package/dist/declarative-validation/compiler/assertion-shapes.js +219 -0
  168. package/dist/declarative-validation/compiler/assertion-shapes.js.map +1 -0
  169. package/dist/declarative-validation/compiler/assertions.d.ts +6 -0
  170. package/dist/declarative-validation/compiler/assertions.d.ts.map +1 -0
  171. package/dist/declarative-validation/compiler/assertions.js +35 -0
  172. package/dist/declarative-validation/compiler/assertions.js.map +1 -0
  173. package/dist/declarative-validation/compiler/compatibility.d.ts +4 -0
  174. package/dist/declarative-validation/compiler/compatibility.d.ts.map +1 -0
  175. package/dist/declarative-validation/compiler/compatibility.js +29 -0
  176. package/dist/declarative-validation/compiler/compatibility.js.map +1 -0
  177. package/dist/declarative-validation/compiler/diagnostics.d.ts +3 -0
  178. package/dist/declarative-validation/compiler/diagnostics.d.ts.map +1 -0
  179. package/dist/declarative-validation/compiler/diagnostics.js +9 -0
  180. package/dist/declarative-validation/compiler/diagnostics.js.map +1 -0
  181. package/dist/declarative-validation/compiler/group-plans.d.ts +6 -0
  182. package/dist/declarative-validation/compiler/group-plans.d.ts.map +1 -0
  183. package/dist/declarative-validation/compiler/group-plans.js +67 -0
  184. package/dist/declarative-validation/compiler/group-plans.js.map +1 -0
  185. package/dist/declarative-validation/compiler/index.d.ts +5 -0
  186. package/dist/declarative-validation/compiler/index.d.ts.map +1 -0
  187. package/dist/declarative-validation/compiler/index.js +199 -0
  188. package/dist/declarative-validation/compiler/index.js.map +1 -0
  189. package/dist/declarative-validation/compiler/plan.d.ts +126 -0
  190. package/dist/declarative-validation/compiler/plan.d.ts.map +1 -0
  191. package/dist/declarative-validation/compiler/plan.js +2 -0
  192. package/dist/declarative-validation/compiler/plan.js.map +1 -0
  193. package/dist/declarative-validation/compiler/rule-fields.d.ts +6 -0
  194. package/dist/declarative-validation/compiler/rule-fields.d.ts.map +1 -0
  195. package/dist/declarative-validation/compiler/rule-fields.js +40 -0
  196. package/dist/declarative-validation/compiler/rule-fields.js.map +1 -0
  197. package/dist/declarative-validation/diagnostics/index.d.ts +7 -0
  198. package/dist/declarative-validation/diagnostics/index.d.ts.map +1 -0
  199. package/dist/declarative-validation/diagnostics/index.js +2 -0
  200. package/dist/declarative-validation/diagnostics/index.js.map +1 -0
  201. package/dist/declarative-validation/diagnostics/profile-config-diagnostics.d.ts +10 -0
  202. package/dist/declarative-validation/diagnostics/profile-config-diagnostics.d.ts.map +1 -0
  203. package/dist/declarative-validation/diagnostics/profile-config-diagnostics.js +51 -0
  204. package/dist/declarative-validation/diagnostics/profile-config-diagnostics.js.map +1 -0
  205. package/dist/declarative-validation/evidence/index.d.ts +14 -0
  206. package/dist/declarative-validation/evidence/index.d.ts.map +1 -0
  207. package/dist/declarative-validation/evidence/index.js +38 -0
  208. package/dist/declarative-validation/evidence/index.js.map +1 -0
  209. package/dist/declarative-validation/profile/applicability-schema.d.ts +4 -0
  210. package/dist/declarative-validation/profile/applicability-schema.d.ts.map +1 -0
  211. package/dist/declarative-validation/profile/applicability-schema.js +24 -0
  212. package/dist/declarative-validation/profile/applicability-schema.js.map +1 -0
  213. package/dist/declarative-validation/profile/assertion-schema.d.ts +5 -0
  214. package/dist/declarative-validation/profile/assertion-schema.d.ts.map +1 -0
  215. package/dist/declarative-validation/profile/assertion-schema.js +420 -0
  216. package/dist/declarative-validation/profile/assertion-schema.js.map +1 -0
  217. package/dist/declarative-validation/profile/data-closure.d.ts +6 -0
  218. package/dist/declarative-validation/profile/data-closure.d.ts.map +1 -0
  219. package/dist/declarative-validation/profile/data-closure.js +167 -0
  220. package/dist/declarative-validation/profile/data-closure.js.map +1 -0
  221. package/dist/declarative-validation/profile/direct-profile-diagnostics.d.ts +7 -0
  222. package/dist/declarative-validation/profile/direct-profile-diagnostics.d.ts.map +1 -0
  223. package/dist/declarative-validation/profile/direct-profile-diagnostics.js +81 -0
  224. package/dist/declarative-validation/profile/direct-profile-diagnostics.js.map +1 -0
  225. package/dist/declarative-validation/profile/group-schema.d.ts +5 -0
  226. package/dist/declarative-validation/profile/group-schema.d.ts.map +1 -0
  227. package/dist/declarative-validation/profile/group-schema.js +55 -0
  228. package/dist/declarative-validation/profile/group-schema.js.map +1 -0
  229. package/dist/declarative-validation/profile/ids-assertion-contract.d.ts +12 -0
  230. package/dist/declarative-validation/profile/ids-assertion-contract.d.ts.map +1 -0
  231. package/dist/declarative-validation/profile/ids-assertion-contract.js +32 -0
  232. package/dist/declarative-validation/profile/ids-assertion-contract.js.map +1 -0
  233. package/dist/declarative-validation/profile/index.d.ts +153 -0
  234. package/dist/declarative-validation/profile/index.d.ts.map +1 -0
  235. package/dist/declarative-validation/profile/index.js +2 -0
  236. package/dist/declarative-validation/profile/index.js.map +1 -0
  237. package/dist/declarative-validation/profile/materialization.d.ts +9 -0
  238. package/dist/declarative-validation/profile/materialization.d.ts.map +1 -0
  239. package/dist/declarative-validation/profile/materialization.js +112 -0
  240. package/dist/declarative-validation/profile/materialization.js.map +1 -0
  241. package/dist/declarative-validation/profile/parse.d.ts +3 -0
  242. package/dist/declarative-validation/profile/parse.d.ts.map +1 -0
  243. package/dist/declarative-validation/profile/parse.js +89 -0
  244. package/dist/declarative-validation/profile/parse.js.map +1 -0
  245. package/dist/declarative-validation/profile/schema-values.d.ts +14 -0
  246. package/dist/declarative-validation/profile/schema-values.d.ts.map +1 -0
  247. package/dist/declarative-validation/profile/schema-values.js +81 -0
  248. package/dist/declarative-validation/profile/schema-values.js.map +1 -0
  249. package/dist/declarative-validation/profile/schema.d.ts +9 -0
  250. package/dist/declarative-validation/profile/schema.d.ts.map +1 -0
  251. package/dist/declarative-validation/profile/schema.js +159 -0
  252. package/dist/declarative-validation/profile/schema.js.map +1 -0
  253. package/dist/declarative-validation/profile/selector-schema.d.ts +4 -0
  254. package/dist/declarative-validation/profile/selector-schema.d.ts.map +1 -0
  255. package/dist/declarative-validation/profile/selector-schema.js +145 -0
  256. package/dist/declarative-validation/profile/selector-schema.js.map +1 -0
  257. package/dist/declarative-validation/profile/syntax-version.d.ts +7 -0
  258. package/dist/declarative-validation/profile/syntax-version.d.ts.map +1 -0
  259. package/dist/declarative-validation/profile/syntax-version.js +11 -0
  260. package/dist/declarative-validation/profile/syntax-version.js.map +1 -0
  261. package/dist/declarative-validation/results/clone-rule-result.d.ts +6 -0
  262. package/dist/declarative-validation/results/clone-rule-result.d.ts.map +1 -0
  263. package/dist/declarative-validation/results/clone-rule-result.js +125 -0
  264. package/dist/declarative-validation/results/clone-rule-result.js.map +1 -0
  265. package/dist/declarative-validation/results/create-result.d.ts +15 -0
  266. package/dist/declarative-validation/results/create-result.d.ts.map +1 -0
  267. package/dist/declarative-validation/results/create-result.js +58 -0
  268. package/dist/declarative-validation/results/create-result.js.map +1 -0
  269. package/dist/declarative-validation/results/index.d.ts +4 -0
  270. package/dist/declarative-validation/results/index.d.ts.map +1 -0
  271. package/dist/declarative-validation/results/index.js +3 -0
  272. package/dist/declarative-validation/results/index.js.map +1 -0
  273. package/dist/declarative-validation/results/skipped-rule-result.d.ts +10 -0
  274. package/dist/declarative-validation/results/skipped-rule-result.d.ts.map +1 -0
  275. package/dist/declarative-validation/results/skipped-rule-result.js +18 -0
  276. package/dist/declarative-validation/results/skipped-rule-result.js.map +1 -0
  277. package/dist/declarative-validation/results/types.d.ts +77 -0
  278. package/dist/declarative-validation/results/types.d.ts.map +1 -0
  279. package/dist/declarative-validation/results/types.js +2 -0
  280. package/dist/declarative-validation/results/types.js.map +1 -0
  281. package/dist/declarative-validation/selectors/index.d.ts +57 -0
  282. package/dist/declarative-validation/selectors/index.d.ts.map +1 -0
  283. package/dist/declarative-validation/selectors/index.js +149 -0
  284. package/dist/declarative-validation/selectors/index.js.map +1 -0
  285. package/dist/declarative-validation/selectors/source.d.ts +8 -0
  286. package/dist/declarative-validation/selectors/source.d.ts.map +1 -0
  287. package/dist/declarative-validation/selectors/source.js +57 -0
  288. package/dist/declarative-validation/selectors/source.js.map +1 -0
  289. package/dist/declarative-validation/selectors/table-targets.d.ts +36 -0
  290. package/dist/declarative-validation/selectors/table-targets.d.ts.map +1 -0
  291. package/dist/declarative-validation/selectors/table-targets.js +149 -0
  292. package/dist/declarative-validation/selectors/table-targets.js.map +1 -0
  293. package/dist/declarative-validation/selectors/table-text.d.ts +4 -0
  294. package/dist/declarative-validation/selectors/table-text.d.ts.map +1 -0
  295. package/dist/declarative-validation/selectors/table-text.js +16 -0
  296. package/dist/declarative-validation/selectors/table-text.js.map +1 -0
  297. package/dist/{ir → internal}/document-node-walk.d.ts +5 -0
  298. package/dist/internal/document-node-walk.d.ts.map +1 -0
  299. package/dist/internal/document-node-walk.js +36 -0
  300. package/dist/internal/document-node-walk.js.map +1 -0
  301. package/dist/internal/stable-json.d.ts +3 -0
  302. package/dist/internal/stable-json.d.ts.map +1 -0
  303. package/dist/internal/stable-json.js +17 -0
  304. package/dist/internal/stable-json.js.map +1 -0
  305. package/dist/ir/document-derived-views.d.ts.map +1 -1
  306. package/dist/ir/document-derived-views.js +2 -0
  307. package/dist/ir/document-derived-views.js.map +1 -1
  308. package/dist/ir/document-link-reference-views.d.ts +3 -0
  309. package/dist/ir/document-link-reference-views.d.ts.map +1 -0
  310. package/dist/ir/document-link-reference-views.js +150 -0
  311. package/dist/ir/document-link-reference-views.js.map +1 -0
  312. package/dist/ir/document-link-views.d.ts.map +1 -1
  313. package/dist/ir/document-link-views.js +7 -8
  314. package/dist/ir/document-link-views.js.map +1 -1
  315. package/dist/ir/document-list-views.d.ts.map +1 -1
  316. package/dist/ir/document-list-views.js +14 -13
  317. package/dist/ir/document-list-views.js.map +1 -1
  318. package/dist/ir/document-sections.d.ts.map +1 -1
  319. package/dist/ir/document-sections.js +2 -4
  320. package/dist/ir/document-sections.js.map +1 -1
  321. package/dist/ir/document-table-views.js +1 -1
  322. package/dist/ir/document-table-views.js.map +1 -1
  323. package/dist/ir/document-text-spans.js +1 -1
  324. package/dist/ir/document-text-spans.js.map +1 -1
  325. package/dist/ir/document.d.ts +2 -3
  326. package/dist/ir/document.d.ts.map +1 -1
  327. package/dist/ir/document.js +1 -1
  328. package/dist/ir/document.js.map +1 -1
  329. package/dist/ir/index.d.ts +1 -0
  330. package/dist/ir/index.d.ts.map +1 -1
  331. package/dist/ir/normalization-input.d.ts +12 -0
  332. package/dist/ir/normalization-input.d.ts.map +1 -0
  333. package/dist/ir/normalization-input.js +2 -0
  334. package/dist/ir/normalization-input.js.map +1 -0
  335. package/dist/rules/code-fence-languages.d.ts.map +1 -1
  336. package/dist/rules/code-fence-languages.js +4 -6
  337. package/dist/rules/code-fence-languages.js.map +1 -1
  338. package/dist/rules/document-query.d.ts +0 -2
  339. package/dist/rules/document-query.d.ts.map +1 -1
  340. package/dist/rules/document-query.js +1 -17
  341. package/dist/rules/document-query.js.map +1 -1
  342. package/dist/rules/index.d.ts +2 -6
  343. package/dist/rules/index.d.ts.map +1 -1
  344. package/dist/rules/index.js +3 -37
  345. package/dist/rules/index.js.map +1 -1
  346. package/dist/rules/links-allowed-schemes.d.ts.map +1 -1
  347. package/dist/rules/links-allowed-schemes.js +3 -2
  348. package/dist/rules/links-allowed-schemes.js.map +1 -1
  349. package/dist/rules/registry.d.ts +12 -0
  350. package/dist/rules/registry.d.ts.map +1 -0
  351. package/dist/rules/registry.js +61 -0
  352. package/dist/rules/registry.js.map +1 -0
  353. package/dist-bundled/markdown-engine-cli.mjs +26826 -0
  354. package/docs/contracts/api.md +665 -0
  355. package/docs/contracts/declarative-validation.md +842 -0
  356. package/docs/contracts/frontmatter.md +122 -0
  357. package/fixtures/declarative-validation/examples/operational-spec/fail.md +32 -0
  358. package/fixtures/declarative-validation/examples/operational-spec/pass.md +34 -0
  359. package/fixtures/declarative-validation/examples/operational-spec/profile.yaml +131 -0
  360. package/fixtures/declarative-validation/examples/release-checklist/fail.md +22 -0
  361. package/fixtures/declarative-validation/examples/release-checklist/pass.md +22 -0
  362. package/fixtures/declarative-validation/examples/release-checklist/profile.yaml +96 -0
  363. package/fixtures/declarative-validation/examples/requirements-traceability/fail.md +27 -0
  364. package/fixtures/declarative-validation/examples/requirements-traceability/pass.md +27 -0
  365. package/fixtures/declarative-validation/examples/requirements-traceability/profile.yaml +119 -0
  366. package/package.json +26 -6
  367. package/skills/profile-backed-markdown/SKILL.md +54 -0
  368. package/skills/profile-backed-markdown/assets/profiles/operational-spec.yaml +98 -0
  369. package/skills/profile-backed-markdown/references/repair-brief.md +14 -0
  370. package/skills/profile-backed-markdown/scripts/validate-profile-backed-markdown.mjs +590 -0
  371. package/dist/ir/document-node-walk.d.ts.map +0 -1
  372. package/dist/ir/document-node-walk.js +0 -16
  373. package/dist/ir/document-node-walk.js.map +0 -1
@@ -0,0 +1,842 @@
1
+ # Declarative Validation Contract
2
+
3
+ Status: package 3.0.0, v1 profile syntax with v2 Conditional V2, document contract 1.0.0
4
+ Last updated: 2026-06-05
5
+ Current v2 surface: flat-rule result/evidence shell, ID count-bound schema and
6
+ runtime evaluator contract, plus `tableColumnCoverage` schema, compiled-plan,
7
+ and runtime evaluator contract, grouped rule runtime contract, and rule-level
8
+ `when` schema, matcher, public skipped-rule result, skipped counts, and evidence
9
+ cloning contract.
10
+
11
+ This document defines the public declarative validation contract for
12
+ `@jasonbelmonti/markdown-engine`. The stable surface is the package-root API,
13
+ the v1 profile syntax, the admitted v2 profile syntax and runtime subset, the
14
+ CLI validation command, diagnostic codes, serialized result shapes, and evidence
15
+ fields. Internal parser output, compiled rule-plan records, selector target
16
+ records, and evaluator implementation modules are not public contracts.
17
+
18
+ Package 3.0 does not introduce `documentVersion: "3.0.0"` or CLI JSON
19
+ discrimination.
20
+ Declarative validation continues to use the existing `documentVersion: "1.0.0"`
21
+ rich IR document contract, while the profile admission path recognizes
22
+ `markdown-engine.validation@v2` for the same flat rule shape with `id`, optional
23
+ `severity`, `select`, and `assert`; non-recursive `anyOf` and `allOf`; and
24
+ optional rule-level `when`. The admitted v2 path exposes the result and evidence
25
+ shell needed to distinguish assertion, grouped, and skipped evaluation output
26
+ from v1 output, plus the ID count-bound schema, compiled-plan, and runtime
27
+ evaluator contract; the `tableColumnCoverage` schema, compiled-plan, and
28
+ runtime evaluator contract; and the `when` schema plus private compiled-plan and
29
+ matcher contract. Matched applicability continues into normal rule evaluation.
30
+ Non-matching applicability returns a public skipped rule result with
31
+ `status: "skipped"`, `passed: true`, `evaluation.kind: "skipped"`,
32
+ `reason: "whenNotMatched"`, `skippedRuleCount`, no top-level diagnostics, and a
33
+ nested `when` applicability result.
34
+
35
+ ## 1.0 Contract
36
+
37
+ Declarative validation is a local, deterministic validation layer over a
38
+ normalized `EngineDocument`. It accepts inert YAML-compatible profile data,
39
+ compiles supported selectors and assertions into engine-owned rule plans, and
40
+ returns stable diagnostics, rule results, profile metadata, and optional
41
+ evidence.
42
+
43
+ The public API functions are:
44
+
45
+ ```ts
46
+ parseValidationProfile(
47
+ input: string | JsonSafeValue,
48
+ options?: DeclarativeProfileParseOptions,
49
+ ): DeclarativeProfileParseResult
50
+
51
+ validateWithProfile(
52
+ document: EngineDocument,
53
+ profile: ValidationProfile,
54
+ options?: DeclarativeValidationOptions,
55
+ ): DeclarativeValidationResult
56
+ ```
57
+
58
+ Compiled declarative validation plans are internal. They are not exported from
59
+ the package root, are not serialized in API or CLI results, and carry no semver
60
+ stability guarantee.
61
+
62
+ ## Syntax Versioning
63
+
64
+ The v1 syntax is selected with:
65
+
66
+ ```yaml
67
+ syntaxVersion: markdown-engine.validation@v1
68
+ ```
69
+
70
+ `syntaxVersion` is required. Missing or unsupported values emit
71
+ `profile.config.unsupportedSyntaxVersion`.
72
+
73
+ The v2 syntax is admitted as an additive profile syntax:
74
+
75
+ ```yaml
76
+ syntaxVersion: markdown-engine.validation@v2
77
+ ```
78
+
79
+ This release recognizes v2 as a distinct syntax version at profile admission,
80
+ admits ID count bounds at the schema, compiled-plan, and runtime evaluator
81
+ layers, admits `tableColumnCoverage` at the schema, internal compiled-plan, and
82
+ runtime evaluator layers, admits non-recursive grouped rules at the schema,
83
+ compiled-plan, and runtime evaluator layers, and admits optional rule-level
84
+ `when` at the schema, internal compiled-plan, and matcher layers. Matching
85
+ `when` rules continue through normal flat or grouped evaluation and do not add a
86
+ public `when` field to the evaluated rule result. Non-matching `when` rules are
87
+ not evaluated; they return the public skipped-rule result shape, increment
88
+ `skippedRuleCount`, and leave `evaluatedRuleCount` unchanged.
89
+
90
+ The admitted v1/v2 flat vocabulary is closed. Unknown profile keys, rule keys,
91
+ selector keys, known assertion keys, and nested assertion keys emit
92
+ `profile.config.unsupportedKey` unless the contract assigns a more specific
93
+ compile diagnostic for an unsupported selector target or unsupported assertion
94
+ member.
95
+
96
+ Regex-like keys are explicitly unsupported in v1:
97
+
98
+ - `matches`
99
+ - `pattern`
100
+ - `regex`
101
+ - `regexp`
102
+
103
+ Executable-like keys are also unsupported:
104
+
105
+ - `callback`
106
+ - `eval`
107
+ - `execute`
108
+ - `expression`
109
+ - `function`
110
+ - `import`
111
+ - `imports`
112
+ - `plugin`
113
+ - `script`
114
+
115
+ These keys are treated as data-only unsupported config. They are not executed,
116
+ imported, evaluated, or compiled.
117
+
118
+ ## Document-Version Behavior
119
+
120
+ Profiles may include:
121
+
122
+ ```yaml
123
+ documentVersion: 1.0.0
124
+ ```
125
+
126
+ Supported profile `documentVersion` values are `"0.0.0"` and `"1.0.0"`.
127
+ Omission is allowed. `parseValidationProfile` preserves omission and does not
128
+ inject a default into the parsed profile.
129
+
130
+ Direct object inputs to `parseValidationProfile` are closed as JSON-safe data
131
+ before schema traversal. Accessors, proxies, cyclic values, sparse arrays,
132
+ functions, non-finite numbers, explicit `undefined`, and `__proto__` data
133
+ properties are rejected with inert diagnostics rather than being executed or
134
+ compiled.
135
+
136
+ `validateWithProfile` resolves an omitted profile `documentVersion` to the
137
+ supplied `EngineDocument.version`. The returned
138
+ `DeclarativeValidationResult.profile.documentVersion` records that resolved
139
+ version.
140
+
141
+ If the resolved profile `documentVersion` differs from `document.version`,
142
+ validation emits `profile.config.documentVersionMismatch`, returns no rule
143
+ results, and does not evaluate rules.
144
+
145
+ ## Profile Shape
146
+
147
+ The top-level profile shape is:
148
+
149
+ ```ts
150
+ type ValidationProfileSyntaxVersion =
151
+ | "markdown-engine.validation@v1"
152
+ | "markdown-engine.validation@v2";
153
+
154
+ interface ValidationProfile {
155
+ syntaxVersion: ValidationProfileSyntaxVersion;
156
+ documentVersion?: EngineDocumentVersion;
157
+ rules: readonly DeclarativeValidationRule[];
158
+ }
159
+
160
+ type DeclarativeValidationRule =
161
+ | DeclarativeValidationFlatRule
162
+ | DeclarativeValidationGroupRule;
163
+
164
+ interface DeclarativeValidationRuleFields {
165
+ id: string;
166
+ severity?: "error" | "warning" | "info";
167
+ when?: DeclarativeValidationApplicability;
168
+ }
169
+
170
+ interface DeclarativeValidationFlatRule extends DeclarativeValidationRuleFields {
171
+ select: DeclarativeSelector;
172
+ assert: DeclarativeAssertion;
173
+ }
174
+
175
+ interface DeclarativeValidationApplicability {
176
+ select: DeclarativeSelector;
177
+ assert: DeclarativeAssertion;
178
+ }
179
+
180
+ type DeclarativeValidationGroupRule =
181
+ | DeclarativeValidationAnyOfRule
182
+ | DeclarativeValidationAllOfRule;
183
+
184
+ interface DeclarativeValidationAnyOfRule
185
+ extends DeclarativeValidationRuleFields {
186
+ anyOf: readonly DeclarativeValidationBranch[];
187
+ }
188
+
189
+ interface DeclarativeValidationAllOfRule
190
+ extends DeclarativeValidationRuleFields {
191
+ allOf: readonly DeclarativeValidationBranch[];
192
+ }
193
+
194
+ interface DeclarativeValidationBranch {
195
+ label?: string;
196
+ select: DeclarativeSelector;
197
+ assert: DeclarativeAssertion;
198
+ }
199
+ ```
200
+
201
+ Rule IDs must be non-empty strings and unique within one profile. Duplicate rule
202
+ IDs emit `profile.config.invalidShape` because diagnostics, rule results, and
203
+ evidence identify output by `ruleId`.
204
+
205
+ Rule `severity` defaults to `error` when omitted. Unsupported severity values
206
+ emit `profile.config.invalidShape`.
207
+
208
+ Rule-level `when` is allowed only on v2 rules. Branch-level `when` remains
209
+ unsupported. V1 profiles preserve the original flat rule authoring contract;
210
+ grouped `anyOf` / `allOf`, ID count bounds, `tableColumnCoverage`, and
211
+ rule-level `when` are v2 additions.
212
+
213
+ Profile values must be JSON-safe data properties after YAML materialization.
214
+ Functions, accessors, proxies, cyclic structures, sparse arrays, `undefined`
215
+ payloads in required positions, non-finite numbers, and `__proto__` properties
216
+ are rejected as invalid shape.
217
+
218
+ ## Selector Contract
219
+
220
+ Selectors resolve against public `EngineDocument` structure and query helper
221
+ semantics. Supported selector targets are:
222
+
223
+ ```ts
224
+ type DeclarativeSelector =
225
+ | { target: "document" }
226
+ | { target: "section"; title?: string; depth?: number }
227
+ | { target: "heading"; text?: string; depth?: number }
228
+ | { target: "table"; section?: string; header?: readonly string[] }
229
+ | {
230
+ target: "tableRow";
231
+ section?: string;
232
+ tableHeader?: readonly string[];
233
+ where?: { column: string; equals?: string; includes?: string };
234
+ }
235
+ | {
236
+ target: "tableCell";
237
+ section?: string;
238
+ tableHeader?: readonly string[];
239
+ column: string;
240
+ rowWhere?: { column: string; equals?: string; includes?: string };
241
+ }
242
+ | { target: "textSpan"; section?: string; nodeType?: string; textIncludes?: string }
243
+ | { target: "link"; section?: string; text?: string; url?: string }
244
+ | { target: "list"; section?: string; ordered?: boolean; depth?: number };
245
+ ```
246
+
247
+ Unsupported selector targets emit `profile.compile.unsupportedSelector`.
248
+
249
+ String matching is deterministic literal matching. Heading, section, header,
250
+ column, `equals`, and frontmatter field names use exact string equality.
251
+ `includes`, `contains`, `excludes`, and `textOccurrenceCount.text` use literal
252
+ substring matching. No profile-supplied regular expression is compiled.
253
+
254
+ Table `header` and `tableHeader` arrays match normalized table header cells as
255
+ an exact-title ordered subsequence. Unrelated columns may appear before, between,
256
+ or after listed values. Duplicate supplied values require separate matching
257
+ header cells.
258
+
259
+ `tableRow.where` and `tableCell.rowWhere` require a non-empty `column` and at
260
+ least one of `equals` or `includes`. When both are present, both tests must
261
+ pass. A missing predicate column makes the row fail the predicate; it does not
262
+ emit a diagnostic by itself.
263
+
264
+ ## Assertion Contract
265
+
266
+ Supported assertion members are:
267
+
268
+ ```ts
269
+ interface DeclarativeAssertion {
270
+ exists?: true;
271
+ sectionsRequired?: {
272
+ headings: readonly string[];
273
+ order?: "none" | "strict";
274
+ };
275
+ tableColumnsRequired?: {
276
+ columns: readonly string[];
277
+ };
278
+ ids?: {
279
+ prefix?: string;
280
+ unique?: boolean;
281
+ caseSensitive?: boolean;
282
+ minCount?: number;
283
+ maxCount?: number;
284
+ };
285
+ references?: {
286
+ idsFrom: { section?: string; column?: string; prefix?: string };
287
+ mustAppearIn: readonly string[];
288
+ };
289
+ tableColumnCoverage?: {
290
+ source: {
291
+ section: string;
292
+ column: string;
293
+ prefix?: string;
294
+ caseSensitive?: boolean;
295
+ };
296
+ target: {
297
+ section: string;
298
+ tableHeader?: readonly string[];
299
+ column: string;
300
+ };
301
+ require: "everySourceId";
302
+ };
303
+ text?: {
304
+ contains?: string;
305
+ excludes?: readonly string[];
306
+ };
307
+ textOccurrenceCount?: {
308
+ text: string;
309
+ count: number;
310
+ };
311
+ textLength?: {
312
+ min?: number;
313
+ max?: number;
314
+ };
315
+ frontmatterRequired?: {
316
+ fields: readonly string[];
317
+ };
318
+ }
319
+ ```
320
+
321
+ Unsupported first-level assertion members parsed from YAML or JSON-safe profile
322
+ input emit `profile.compile.unsupportedAssertion`, except regex-like and
323
+ executable-like keys, which retain `profile.config.unsupportedKey` precedence.
324
+ Direct typed profile objects passed to validation are hardened as closed
325
+ JSON-safe data before execution; unsupported assertion properties on that path
326
+ emit `profile.config.unsupportedKey`.
327
+
328
+ Selector/assertion compatibility is part of the public contract:
329
+
330
+ | Assertion | Compatible selector targets |
331
+ | --- | --- |
332
+ | `exists` | all supported selector targets |
333
+ | `sectionsRequired` | `document` |
334
+ | `tableColumnsRequired` | `table` |
335
+ | `ids` | all supported selector targets |
336
+ | `references` | `document` |
337
+ | `tableColumnCoverage` | `document` |
338
+ | `text` | all supported selector targets |
339
+ | `textOccurrenceCount` | all supported selector targets |
340
+ | `textLength` | all supported selector targets |
341
+ | `frontmatterRequired` | `document` |
342
+
343
+ Incompatible supported selector/assertion pairs emit
344
+ `profile.compile.incompatibleSelectorAssertion`.
345
+
346
+ `exists` must be `true`. It passes when the selector resolves at least one
347
+ target and fails with `profile.validation.emptySelection` when the selector
348
+ resolves zero targets.
349
+
350
+ `sectionsRequired.order` defaults to `none`. `strict` checks that configured
351
+ headings appear as an ordered subsequence in the normalized section tree
352
+ flattened in source order.
353
+
354
+ For v1 profiles, `ids.unique` must be `true`. For v2 profiles, `ids.unique`
355
+ must be `true` when provided and may be omitted when `ids.minCount` or
356
+ `ids.maxCount` provides the predicate. `prefix` and `caseSensitive` are modifiers,
357
+ not standalone predicates. `caseSensitive` defaults to `true`. ID tokens use the
358
+ documented token grammar `[A-Za-z][A-Za-z0-9]*-[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*`.
359
+ For v2 profiles, `ids.minCount` and `ids.maxCount` are admitted as non-negative
360
+ integer schema and compiled-plan fields. When both are present, `minCount` must
361
+ be less than or equal to `maxCount`. Runtime count evaluation uses unique
362
+ comparison values after prefix filtering and duplicate occurrence de-duplication.
363
+ Failed lower and upper bounds emit `profile.validation.idCountTooLow` and
364
+ `profile.validation.idCountTooHigh`.
365
+
366
+ For v2 profiles, `tableColumnCoverage` is admitted as a flat-rule schema and
367
+ internal compiled-plan assertion. It is compatible only with a `document`
368
+ selector because the assertion owns its source and target table-column inputs.
369
+ `source.section`, `source.column`, `target.section`, and `target.column` are
370
+ required non-empty strings. `source.prefix` is optional and must be non-empty
371
+ when provided. `source.caseSensitive` is optional and defaults to `true` in the
372
+ compiled plan. `target.tableHeader` is an optional non-empty string array.
373
+ `require` must be exactly `"everySourceId"`. Runtime evaluation extracts unique
374
+ source IDs from `source.section` and `source.column`, applies `source.prefix`
375
+ and `source.caseSensitive`, and requires every source ID comparison value to
376
+ appear in the configured target table column. IDs appearing elsewhere in the
377
+ target section do not satisfy coverage. Missing target sections, missing target
378
+ columns, and missing target-column IDs emit deterministic validation diagnostics
379
+ source-grounded to the source ID when source evidence is available.
380
+
381
+ `text` must include `contains` or a non-empty `excludes` array.
382
+ `textOccurrenceCount.count` is a finite number and counts non-overlapping
383
+ literal occurrences per selected target.
384
+ `textLength` must include `min`, `max`, or both. Bounds are non-negative
385
+ integers, `min` must be less than or equal to `max` when both are present, and
386
+ evaluation uses JavaScript string `.length` for each selected target's
387
+ normalized text.
388
+
389
+ Empty selector results produce `profile.validation.emptySelection` for exists,
390
+ table, ID, reference, text, occurrence, and text-length assertions.
391
+ Document-scoped required-section and required-frontmatter assertions evaluate
392
+ against the document.
393
+
394
+ ## Diagnostics
395
+
396
+ All declarative validation diagnostics use the public `MarkdownDiagnostic`
397
+ shape. Config diagnostics are error severity except
398
+ `profile.config.yamlWarning`, which is warning severity. Compile diagnostics are
399
+ error severity. Validation diagnostics use the rule severity. Source ranges are
400
+ included when a selected target has source evidence; locations are omitted
401
+ rather than fabricated when unavailable.
402
+
403
+ Rule-level `when` uses the existing validation diagnostic codes. When
404
+ applicability does not match, those diagnostics are cloned into
405
+ `ruleResults[].when.diagnostics`; they are not promoted into top-level
406
+ `diagnostics`, so a skipped rule with a nested error-severity applicability
407
+ diagnostic can still leave the aggregate `valid` value `true`.
408
+
409
+ | Code | Severity source | Emitted when |
410
+ | --- | --- | --- |
411
+ | `profile.config.invalidYaml` | `error` | YAML text cannot be parsed or materialized as JSON-safe profile data. |
412
+ | `profile.config.yamlWarning` | `warning` | YAML materialization produces a non-fatal parser warning. |
413
+ | `profile.config.unsupportedSyntaxVersion` | `error` | `syntaxVersion` is missing or is not `markdown-engine.validation@v1` or `markdown-engine.validation@v2`. |
414
+ | `profile.config.invalidShape` | `error` | Required fields are missing, fields have wrong types, arrays or strings are empty, rule IDs duplicate, scalar values are invalid, table predicates are ineffective, or assertion payloads contain no effective predicate. |
415
+ | `profile.config.documentVersionMismatch` | `error` | Resolved profile `documentVersion` differs from the supplied `EngineDocument.version`. |
416
+ | `profile.config.unsupportedKey` | `error` | A closed profile, rule, selector, known assertion object, nested object, regex-like key, executable-like key, or direct typed profile object contains unsupported syntax. |
417
+ | `profile.compile.unsupportedSelector` | `error` | `select.target` is not a supported v1 target. |
418
+ | `profile.compile.unsupportedAssertion` | `error` | Parsed YAML or JSON-safe `assert` input contains an unsupported first-level assertion member that does not have unsupported-key precedence. |
419
+ | `profile.compile.incompatibleSelectorAssertion` | `error` | A supported selector target is paired with an incompatible supported assertion. |
420
+ | `profile.validation.emptySelection` | Rule severity | A rule cannot evaluate because its selector matches no applicable target. |
421
+ | `profile.validation.assertionFailed` | Rule severity | A supported assertion evaluates and fails without a more specific diagnostic code, including missing table columns, exact occurrence-count mismatches, and text-length bound failures. |
422
+ | `profile.validation.duplicateId` | Rule severity | An `ids.unique` assertion finds repeated IDs. |
423
+ | `profile.validation.frontmatterFieldMissing` | Rule severity | A required frontmatter field is absent. |
424
+ | `profile.validation.idCountTooHigh` | Rule severity | Unique ID count after filtering is higher than `ids.maxCount`. |
425
+ | `profile.validation.idCountTooLow` | Rule severity | Unique ID count after filtering is lower than `ids.minCount`. |
426
+ | `profile.validation.referenceMissing` | Rule severity | A source ID is absent from a required target section. |
427
+ | `profile.validation.sectionMissing` | Rule severity | A required section heading is absent. |
428
+ | `profile.validation.sectionOrder` | Rule severity | A strict required-section order cannot be satisfied. |
429
+ | `profile.validation.tableColumnCoverageIdMissing` | Rule severity | A source ID is absent from the configured target table column. |
430
+ | `profile.validation.tableColumnCoverageTargetColumnMissing` | Rule severity | The configured target table column cannot be resolved. |
431
+ | `profile.validation.tableColumnCoverageTargetSectionMissing` | Rule severity | The configured target section cannot be resolved. |
432
+ | `profile.validation.textExcluded` | Rule severity | A selected target contains forbidden literal text. |
433
+ | `profile.validation.textMissing` | Rule severity | A selected target lacks required literal text from a `text.contains` assertion. |
434
+ | `profile.validation.assertionUnsupported` | `error` | A compiled assertion or compiled assertion feature has no evaluator implementation; this is an internal safety diagnostic. |
435
+
436
+ ## Result Shape
437
+
438
+ `DeclarativeValidationResult` extends the public validation result shape:
439
+
440
+ ```ts
441
+ interface DeclarativeValidationResult extends ValidationResult {
442
+ valid: boolean;
443
+ diagnostics: readonly MarkdownDiagnostic[];
444
+ ruleResults: readonly (
445
+ | ValidationRuleResult
446
+ | DeclarativeValidationRuleResultV2
447
+ )[];
448
+ profile: {
449
+ syntaxVersion: ValidationProfileSyntaxVersion;
450
+ documentVersion: EngineDocumentVersion;
451
+ ruleCount: number;
452
+ };
453
+ evidence?: DeclarativeValidationEvidence;
454
+ }
455
+ ```
456
+
457
+ For admitted v2 profiles, result metadata records
458
+ `syntaxVersion: "markdown-engine.validation@v2"`, `evaluatedRuleCount`, and
459
+ `skippedRuleCount`. V2 rule results include the v1-compatible `ruleId`,
460
+ `passed`, and `diagnostics` fields plus `status`, optional skipped
461
+ applicability metadata, and flat, grouped, or skipped evaluation metadata:
462
+
463
+ ```ts
464
+ interface DeclarativeValidationRuleResultV2 extends ValidationRuleResult {
465
+ status: "passed" | "failed" | "skipped";
466
+ when?: DeclarativeValidationApplicabilityResult;
467
+ evaluation:
468
+ | { kind: "assertions"; diagnostics: readonly MarkdownDiagnostic[] }
469
+ | {
470
+ kind: "anyOf";
471
+ selectedBranch?: DeclarativeValidationBranchReference;
472
+ branches: readonly DeclarativeValidationBranchResult[];
473
+ }
474
+ | {
475
+ kind: "allOf";
476
+ branches: readonly DeclarativeValidationBranchResult[];
477
+ }
478
+ | { kind: "skipped"; reason: "whenNotMatched" };
479
+ }
480
+
481
+ interface DeclarativeValidationApplicabilityResult {
482
+ status: "matched" | "notMatched";
483
+ diagnostics: readonly MarkdownDiagnostic[];
484
+ }
485
+
486
+ interface DeclarativeValidationBranchReference {
487
+ branchIndex: number;
488
+ label?: string;
489
+ }
490
+
491
+ interface DeclarativeValidationBranchResult
492
+ extends DeclarativeValidationBranchReference {
493
+ status: "passed" | "failed";
494
+ diagnostics: readonly MarkdownDiagnostic[];
495
+ }
496
+ ```
497
+
498
+ For configured `when`, matched applicability continues into normal flat or
499
+ grouped evaluation and contributes one evaluated rule. The evaluated rule result
500
+ does not serialize a `when` field. Non-matching applicability returns one
501
+ skipped rule result with `status: "skipped"`, `passed: true`, empty top-level
502
+ rule `diagnostics`, `when.status: "notMatched"`, nested applicability
503
+ diagnostics, `evaluation.kind: "skipped"`, and `reason: "whenNotMatched"`.
504
+ Skipped rules increment `skippedRuleCount`, do not increment
505
+ `evaluatedRuleCount`, and do not evaluate flat assertions or grouped branches.
506
+
507
+ `valid` is `false` when any top-level error-severity diagnostic exists in
508
+ `diagnostics`. Nested skipped applicability diagnostics under
509
+ `ruleResults[].when.diagnostics` do not by themselves make the aggregate result
510
+ invalid. Warning and info validation diagnostics can make a rule result fail
511
+ without making the aggregate result invalid.
512
+
513
+ Rule results are sorted deterministically. Each rule result includes the public
514
+ `ruleId`, `passed`, and cloned diagnostics. Results do not expose compiled rule
515
+ plans or selector internals.
516
+
517
+ ## Evidence Fields
518
+
519
+ Evidence is emitted only when `DeclarativeValidationOptions.includeEvidence` is
520
+ `true`:
521
+
522
+ ```ts
523
+ interface DeclarativeValidationEvidence<
524
+ RuleResult extends ValidationRuleResult = ValidationRuleResult,
525
+ > {
526
+ inputHash: string;
527
+ profileHash: string;
528
+ engineVersion: string;
529
+ runtimeVersion: string;
530
+ ruleResults: readonly RuleResult[];
531
+ diagnostics: readonly MarkdownDiagnostic[];
532
+ }
533
+ ```
534
+
535
+ For v1 profiles, `ruleResults` contains the unchanged v1 rule-result shape. For
536
+ admitted v2 profiles, `ruleResults` clones the public v2 rule-result shape,
537
+ including `status`, flat assertion evaluation, and grouped `anyOf` / `allOf`
538
+ branch evaluation. Skipped v2 rule results are cloned through evidence in the
539
+ same `ruleResults` array, and `evidence.diagnostics` clones the top-level
540
+ diagnostics array. Evidence does not serialize compiled rule plans, selector
541
+ target records, assertion-specific ID count evidence, or assertion-specific
542
+ table-column coverage evidence.
543
+
544
+ `inputHash` is a lowercase hexadecimal SHA-256 digest of the stable JSON
545
+ serialization of the supplied normalized `EngineDocument` after omitting only
546
+ the top-level `document.path` field. Structural target paths remain part of the
547
+ canonical input.
548
+
549
+ `profileHash` is a lowercase hexadecimal SHA-256 digest of the stable JSON
550
+ serialization of the resolved `ValidationProfile` after applying the resolved
551
+ `documentVersion` and default rule severity of `error`. An omitted
552
+ `documentVersion` and an explicit matching `documentVersion` therefore produce
553
+ the same profile hash for the same document version and rules.
554
+
555
+ `engineVersion` records the package version that produced the evidence. In the
556
+ 3.0 release line this is `"3.0.0"` even though `documentVersion` remains
557
+ `"1.0.0"`.
558
+
559
+ Raw Markdown bytes, raw YAML bytes, YAML comments, caller file paths, and
560
+ `includeEvidence` itself are not part of either evidence hash.
561
+
562
+ ## CLI Behavior
563
+
564
+ The declarative validation CLI command is:
565
+
566
+ ```sh
567
+ markdown-engine validate --file <markdown-file> --profile <profile-file> [--format json]
568
+ ```
569
+
570
+ `--format json` is the default and only supported validation output format.
571
+ The command always normalizes Markdown with `documentVersion: "1.0.0"` and does
572
+ not accept `--document-version`.
573
+
574
+ The CLI reads and checks the profile before reading the Markdown file. Profile
575
+ parse, config, and compile failures emit profile-stage JSON and do not parse or
576
+ validate the Markdown file.
577
+
578
+ After profile compilation succeeds, the CLI emits a validation-result JSON
579
+ shape whether the document passes or fails. Validation CLI results include
580
+ evidence. V2 CLI results use the same validation-result arm of the CLI JSON
581
+ union; there is no extra CLI discriminator beyond
582
+ `profile.syntaxVersion: "markdown-engine.validation@v2"`.
583
+
584
+ ## CLI JSON Union
585
+
586
+ The CLI JSON output is:
587
+
588
+ ```ts
589
+ type DeclarativeValidationCliJsonResult =
590
+ | DeclarativeValidationResult
591
+ | DeclarativeValidationConfigErrorResult;
592
+
593
+ interface DeclarativeValidationConfigErrorResult {
594
+ valid: false;
595
+ stage: "profile";
596
+ diagnostics: readonly MarkdownDiagnostic[];
597
+ ruleResults: readonly [];
598
+ profile?: undefined;
599
+ evidence?: undefined;
600
+ }
601
+ ```
602
+
603
+ Profile-stage JSON is used for invalid YAML, invalid profile shape,
604
+ unsupported syntax version, unsupported keys, unsupported selector targets,
605
+ unsupported assertion members, and incompatible selector/assertion pairs. It
606
+ contains no `profile` and no `evidence`.
607
+
608
+ Validation-result JSON is used after profile compilation succeeds. It contains
609
+ `profile`, `ruleResults`, `diagnostics`, `valid`, and `evidence`. For v2
610
+ profiles, that same validation-result JSON can include `evaluatedRuleCount`,
611
+ `skippedRuleCount`, `status: "skipped"`, nested `when` diagnostics, and
612
+ `evaluation.kind: "skipped"`.
613
+
614
+ ## Exit Codes
615
+
616
+ | Exit code | Meaning |
617
+ | --- | --- |
618
+ | `0` | Validation completed with no top-level error-severity diagnostics. |
619
+ | `1` | Profile/config/compile, Markdown normalization, document-version mismatch, or top-level validation diagnostics include at least one error. |
620
+ | `2` | CLI usage, unsupported format, unknown argument, missing argument value, repeated singleton flag, unsupported `--document-version`, or local file read error. |
621
+
622
+ ## Compatibility And Migration
623
+
624
+ The v1 declarative validation syntax is a durable authoring contract for the
625
+ 3.0 package release line. Changes to profile syntax names, selector names,
626
+ assertion names, result fields, diagnostic codes, CLI flags, CLI JSON shape, or
627
+ evidence hash inputs require explicit compatibility review.
628
+
629
+ V1 preservation is explicit: v1 authoring syntax, v1 rule result shape, v1
630
+ diagnostic inventory, v1 CLI JSON behavior, and v1 evidence hash inputs remain
631
+ unchanged by the admitted v2 syntax.
632
+
633
+ Compatibility examples:
634
+
635
+ ```yaml
636
+ # v1 compatibility profile: remains on the v1 authoring and result contract.
637
+ syntaxVersion: markdown-engine.validation@v1
638
+ rules:
639
+ - id: sections.present
640
+ select:
641
+ target: document
642
+ assert:
643
+ sectionsRequired:
644
+ headings:
645
+ - Mission Brief
646
+ ```
647
+
648
+ ```yaml
649
+ # v2 opt-in profile: selects Conditional V2 behavior explicitly.
650
+ syntaxVersion: markdown-engine.validation@v2
651
+ rules:
652
+ - id: release.docs
653
+ anyOf:
654
+ - label: release-section
655
+ select:
656
+ target: section
657
+ title: Release
658
+ assert:
659
+ exists: true
660
+ - label: changelog-link
661
+ select:
662
+ target: link
663
+ text: changelog
664
+ assert:
665
+ exists: true
666
+ ```
667
+
668
+ The v1 profile above continues to emit the v1 validation-result shape. The v2
669
+ profile above emits syntax-versioned v2 result metadata with
670
+ `evaluatedRuleCount` and `skippedRuleCount`; v2 rule results include `status`
671
+ and `evaluation`. The CLI does not add a second discriminator for v2; consumers
672
+ branch on
673
+ `profile.syntaxVersion: "markdown-engine.validation@v2"`.
674
+
675
+ Migration notes:
676
+
677
+ - Consumers using fixed `validate(document, config)` rule families can continue
678
+ using that API. Declarative validation is additive and does not replace fixed
679
+ rule validation.
680
+ - Consumers that need reusable structural policies should move profile-owned
681
+ checks into `parseValidationProfile` and `validateWithProfile`.
682
+ - Consumers parsing CLI validation output must handle the
683
+ `DeclarativeValidationCliJsonResult` union. Profile-stage failures do not
684
+ include `profile` or `evidence`.
685
+ - Consumers opting into `markdown-engine.validation@v2` must handle rule
686
+ `status` values of `"passed"`, `"failed"`, and `"skipped"`, plus
687
+ `evaluatedRuleCount`, `skippedRuleCount`, grouped branch results, and nested
688
+ skipped-rule `when` diagnostics. Aggregate validity is still determined from
689
+ top-level diagnostics.
690
+ - Consumers that compare evidence hashes must normalize expectations around
691
+ resolved `documentVersion`, default rule severity, stable key order, and
692
+ exclusion of only top-level `document.path` from `inputHash`.
693
+ - Regex-like matching, JavaScript predicates, plugins, semantic scoring, and
694
+ profile-specific rules belong outside this package unless a future contract
695
+ explicitly expands the engine boundary.
696
+
697
+ ## Examples
698
+
699
+ Minimal profile:
700
+
701
+ ```yaml
702
+ syntaxVersion: markdown-engine.validation@v1
703
+ rules:
704
+ - id: sections.present
705
+ select:
706
+ target: document
707
+ assert:
708
+ sectionsRequired:
709
+ headings:
710
+ - Mission Brief
711
+ ```
712
+
713
+ Link existence profile:
714
+
715
+ ```yaml
716
+ syntaxVersion: markdown-engine.validation@v1
717
+ rules:
718
+ - id: rollback-link.exists
719
+ select:
720
+ target: link
721
+ section: Escalation
722
+ text: rollback guide
723
+ url: ./rollback-guide.md
724
+ assert:
725
+ exists: true
726
+ ```
727
+
728
+ Table cell text profile:
729
+
730
+ ```yaml
731
+ syntaxVersion: markdown-engine.validation@v1
732
+ documentVersion: 1.0.0
733
+ rules:
734
+ - id: requirement-text
735
+ severity: error
736
+ select:
737
+ target: tableCell
738
+ section: Requirements
739
+ tableHeader:
740
+ - ID
741
+ - Requirement statement
742
+ column: Requirement statement
743
+ assert:
744
+ text:
745
+ contains: shall
746
+ excludes:
747
+ - and/or
748
+ textOccurrenceCount:
749
+ text: shall
750
+ count: 1
751
+ ```
752
+
753
+ Conditional v2 grouped rule with applicability:
754
+
755
+ ```yaml
756
+ syntaxVersion: markdown-engine.validation@v2
757
+ rules:
758
+ - id: release.when.docs-ready
759
+ when:
760
+ select:
761
+ target: section
762
+ title: Release
763
+ assert:
764
+ exists: true
765
+ anyOf:
766
+ - label: contract-link
767
+ select:
768
+ target: link
769
+ section: Release
770
+ text: contract
771
+ assert:
772
+ exists: true
773
+ - label: contract-heading
774
+ select:
775
+ target: heading
776
+ text: Contract
777
+ assert:
778
+ exists: true
779
+ ```
780
+
781
+ CLI invocation:
782
+
783
+ ```sh
784
+ markdown-engine validate --file docs/mission.md --profile validation-profile.yaml
785
+ ```
786
+
787
+ Reader-facing operational spec, release checklist, and requirements
788
+ traceability examples live under
789
+ `fixtures/declarative-validation/examples/**`. After building from the
790
+ repository root, run one passing and one intentionally failing example with:
791
+
792
+ ```sh
793
+ node dist/cli/index.js validate --file fixtures/declarative-validation/examples/operational-spec/pass.md --profile fixtures/declarative-validation/examples/operational-spec/profile.yaml
794
+ node dist/cli/index.js validate --file fixtures/declarative-validation/examples/operational-spec/fail.md --profile fixtures/declarative-validation/examples/operational-spec/profile.yaml
795
+ ```
796
+
797
+ The passing command exits `0`; the intentionally failing command exits `1` and
798
+ emits validation JSON with representative diagnostics and evidence.
799
+
800
+ ## Boundary And Non-Goals
801
+
802
+ Declarative validation remains inside the `markdown-engine` deterministic local
803
+ boundary: parse, normalize, validate, diagnose, serialize, and emit evidence.
804
+
805
+ The v1 contract explicitly excludes:
806
+
807
+ - arbitrary JavaScript
808
+ - expression evaluation
809
+ - user-supplied regular expression compilation
810
+ - profile-sourced regex compilation
811
+ - plugins and plugin loading
812
+ - network calls
813
+ - LLM calls
814
+ - file watching
815
+ - persistence
816
+ - profile-specific core semantics
817
+ - operational-design-spec, AGENTS.md, TASK.md, or other domain-specific rule
818
+ meaning in core engine code
819
+
820
+ The admitted v2 Conditional V2 surface also excludes `documentVersion: "3.0.0"`,
821
+ recursive grouped rules, branch-level `when`, profile-defined predicates,
822
+ assertion-specific evidence payloads, a separate skipped-rule evidence channel,
823
+ and a new CLI JSON discriminator.
824
+
825
+ The CLI reads only the caller-specified local Markdown and profile files. The
826
+ API owns no file traversal, daemon, database, browser runtime, network service,
827
+ agent adapter, MCP transport, runtime lens, or persistent cache.
828
+
829
+ ## Contract Review Gates
830
+
831
+ The BEL-985 contract gates are:
832
+
833
+ ```sh
834
+ npm run docs:declarative-validation-contract
835
+ npm run audit:declarative-validation-boundary
836
+ ```
837
+
838
+ The documentation gate checks this contract, README links, legacy contract and
839
+ boundary evidence files, Conditional V2 EVD-6 reviewer notes, and package script
840
+ wiring. The boundary audit checks dependency drift, source-level runtime
841
+ boundary patterns, unsupported regex-like and executable profile-key coverage,
842
+ and declarative validation boundary evidence.