@jasonbelmonti/markdown-engine 3.1.1 → 3.3.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 (83) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +45 -11
  3. package/SECURITY.md +4 -4
  4. package/dist/api/declarative-validation.d.ts.map +1 -1
  5. package/dist/api/declarative-validation.js +31 -11
  6. package/dist/api/declarative-validation.js.map +1 -1
  7. package/dist/api/document-set-validation.js +1 -0
  8. package/dist/api/document-set-validation.js.map +1 -1
  9. package/dist/cli/declarative-validation.d.ts.map +1 -1
  10. package/dist/cli/declarative-validation.js +4 -4
  11. package/dist/cli/declarative-validation.js.map +1 -1
  12. package/dist/declarative-validation/applicability/classifier.d.ts +2 -1
  13. package/dist/declarative-validation/applicability/classifier.d.ts.map +1 -1
  14. package/dist/declarative-validation/applicability/classifier.js +2 -2
  15. package/dist/declarative-validation/applicability/classifier.js.map +1 -1
  16. package/dist/declarative-validation/assertions/context.d.ts +4 -0
  17. package/dist/declarative-validation/assertions/context.d.ts.map +1 -1
  18. package/dist/declarative-validation/assertions/diagnostics.d.ts +3 -0
  19. package/dist/declarative-validation/assertions/diagnostics.d.ts.map +1 -1
  20. package/dist/declarative-validation/assertions/diagnostics.js +18 -0
  21. package/dist/declarative-validation/assertions/diagnostics.js.map +1 -1
  22. package/dist/declarative-validation/assertions/evaluator.d.ts +2 -1
  23. package/dist/declarative-validation/assertions/evaluator.d.ts.map +1 -1
  24. package/dist/declarative-validation/assertions/evaluator.js +10 -1
  25. package/dist/declarative-validation/assertions/evaluator.js.map +1 -1
  26. package/dist/declarative-validation/assertions/group-evaluator.d.ts +3 -2
  27. package/dist/declarative-validation/assertions/group-evaluator.d.ts.map +1 -1
  28. package/dist/declarative-validation/assertions/group-evaluator.js +32 -14
  29. package/dist/declarative-validation/assertions/group-evaluator.js.map +1 -1
  30. package/dist/declarative-validation/assertions/selection-count.d.ts +9 -0
  31. package/dist/declarative-validation/assertions/selection-count.d.ts.map +1 -0
  32. package/dist/declarative-validation/assertions/selection-count.js +36 -0
  33. package/dist/declarative-validation/assertions/selection-count.js.map +1 -0
  34. package/dist/declarative-validation/assertions/source-length.d.ts +9 -0
  35. package/dist/declarative-validation/assertions/source-length.d.ts.map +1 -0
  36. package/dist/declarative-validation/assertions/source-length.js +33 -0
  37. package/dist/declarative-validation/assertions/source-length.js.map +1 -0
  38. package/dist/declarative-validation/compiler/assertion-builders.d.ts.map +1 -1
  39. package/dist/declarative-validation/compiler/assertion-builders.js +5 -32
  40. package/dist/declarative-validation/compiler/assertion-builders.js.map +1 -1
  41. package/dist/declarative-validation/compiler/assertion-shapes.d.ts +1 -2
  42. package/dist/declarative-validation/compiler/assertion-shapes.d.ts.map +1 -1
  43. package/dist/declarative-validation/compiler/assertion-shapes.js +1 -25
  44. package/dist/declarative-validation/compiler/assertion-shapes.js.map +1 -1
  45. package/dist/declarative-validation/compiler/assertions.d.ts.map +1 -1
  46. package/dist/declarative-validation/compiler/assertions.js +2 -0
  47. package/dist/declarative-validation/compiler/assertions.js.map +1 -1
  48. package/dist/declarative-validation/compiler/compatibility.d.ts +2 -0
  49. package/dist/declarative-validation/compiler/compatibility.d.ts.map +1 -1
  50. package/dist/declarative-validation/compiler/compatibility.js +11 -0
  51. package/dist/declarative-validation/compiler/compatibility.js.map +1 -1
  52. package/dist/declarative-validation/compiler/index.d.ts.map +1 -1
  53. package/dist/declarative-validation/compiler/index.js +10 -3
  54. package/dist/declarative-validation/compiler/index.js.map +1 -1
  55. package/dist/declarative-validation/compiler/length-assertion-builders.d.ts +8 -0
  56. package/dist/declarative-validation/compiler/length-assertion-builders.d.ts.map +1 -0
  57. package/dist/declarative-validation/compiler/length-assertion-builders.js +64 -0
  58. package/dist/declarative-validation/compiler/length-assertion-builders.js.map +1 -0
  59. package/dist/declarative-validation/compiler/plan.d.ts +8 -0
  60. package/dist/declarative-validation/compiler/plan.d.ts.map +1 -1
  61. package/dist/declarative-validation/evidence/index.d.ts +2 -1
  62. package/dist/declarative-validation/evidence/index.d.ts.map +1 -1
  63. package/dist/declarative-validation/evidence/index.js +25 -2
  64. package/dist/declarative-validation/evidence/index.js.map +1 -1
  65. package/dist/declarative-validation/profile/assertion-schema.d.ts.map +1 -1
  66. package/dist/declarative-validation/profile/assertion-schema.js +19 -50
  67. package/dist/declarative-validation/profile/assertion-schema.js.map +1 -1
  68. package/dist/declarative-validation/profile/index.d.ts +8 -0
  69. package/dist/declarative-validation/profile/index.d.ts.map +1 -1
  70. package/dist/declarative-validation/profile/length-bound-schema.d.ts +7 -0
  71. package/dist/declarative-validation/profile/length-bound-schema.d.ts.map +1 -0
  72. package/dist/declarative-validation/profile/length-bound-schema.js +55 -0
  73. package/dist/declarative-validation/profile/length-bound-schema.js.map +1 -0
  74. package/dist/declarative-validation/results/create-result.js +1 -1
  75. package/dist/declarative-validation/results/create-result.js.map +1 -1
  76. package/dist/declarative-validation/results/types.d.ts +1 -0
  77. package/dist/declarative-validation/results/types.d.ts.map +1 -1
  78. package/dist/internal/package-version.d.ts +1 -1
  79. package/dist/internal/package-version.js +1 -1
  80. package/dist-bundled/markdown-engine-cli.mjs +483 -252
  81. package/docs/contracts/declarative-validation.md +109 -16
  82. package/package.json +9 -5
  83. package/scripts/install-markdown-engine-cli.sh +2 -2
@@ -1,8 +1,10 @@
1
1
  # Declarative Validation Contract
2
2
 
3
3
  Status: package 3.0.0, v1 profile syntax with v2 Conditional V2, document contract 1.0.0
4
- Last updated: 2026-06-15
5
- Current v2 surface: flat-rule result/evidence shell, ID count-bound schema and
4
+ Last updated: 2026-08-12
5
+ Current v2 surface: flat-rule result/evidence shell, generic selector
6
+ `selectionCount` bounds, document `sourceLength` schema and runtime
7
+ measurement, ID count-bound schema and
6
8
  runtime evaluator contract, plus `tableColumnCoverage` schema, compiled-plan,
7
9
  and runtime evaluator contract, `frontmatterShape` schema, compiled-plan, and
8
10
  runtime evaluator contract, `textFormat` schema, compiled-plan, and runtime
@@ -25,7 +27,8 @@ rich IR document contract, while the profile admission path recognizes
25
27
  `severity`, `select`, and `assert`; non-recursive `anyOf` and `allOf`; and
26
28
  optional rule-level `when`. The admitted v2 path exposes the result and evidence
27
29
  shell needed to distinguish assertion, grouped, and skipped evaluation output
28
- from v1 output, plus the ID count-bound schema, compiled-plan, and runtime
30
+ from v1 output, plus generic selector `selectionCount` bounds, the ID
31
+ count-bound schema, compiled-plan, and runtime
29
32
  evaluator contract; the `tableColumnCoverage` schema, compiled-plan, and
30
33
  runtime evaluator contract; the `frontmatterShape` schema, private
31
34
  compiled-plan, and runtime evaluator contract; the `textFormat` schema,
@@ -63,8 +66,19 @@ validateDocumentSet(
63
66
  entries: readonly ValidateDocumentSetEntry[],
64
67
  options?: ValidateDocumentSetOptions,
65
68
  ): ValidateDocumentSetResult
69
+
70
+ interface DeclarativeValidationOptions {
71
+ path?: string;
72
+ includeEvidence?: boolean;
73
+ sourceText?: string;
74
+ }
66
75
  ```
67
76
 
77
+ `sourceText` carries the complete original Markdown string to validation. It is
78
+ required only when an evaluated v2 `sourceLength` assertion needs to measure
79
+ the pre-normalization input; it does not become an enumerable
80
+ `EngineDocument` field.
81
+
68
82
  Compiled declarative validation plans are internal. They are not exported from
69
83
  the package root, are not serialized in API or CLI results, and carry no semver
70
84
  stability guarantee.
@@ -87,8 +101,9 @@ syntaxVersion: markdown-engine.validation@v2
87
101
  ```
88
102
 
89
103
  This release recognizes v2 as a distinct syntax version at profile admission,
90
- admits ID count bounds at the schema, compiled-plan, and runtime evaluator
91
- layers, admits `tableColumnCoverage` at the schema, internal compiled-plan, and
104
+ admits `selectionCount` and ID count bounds at the schema, compiled-plan, and
105
+ runtime evaluator layers, admits `tableColumnCoverage` at the schema, internal
106
+ compiled-plan, and
92
107
  runtime evaluator layers, admits `frontmatterShape` at the schema, internal
93
108
  compiled-plan, and runtime evaluator layers, admits `textFormat` at the schema,
94
109
  internal compiled-plan, and runtime evaluator layers, admits non-recursive
@@ -281,6 +296,10 @@ Supported assertion members are:
281
296
  ```ts
282
297
  interface DeclarativeAssertion {
283
298
  exists?: true;
299
+ selectionCount?: {
300
+ min?: number;
301
+ max?: number;
302
+ };
284
303
  sectionsRequired?: {
285
304
  headings: readonly string[];
286
305
  order?: "none" | "strict";
@@ -334,6 +353,10 @@ interface DeclarativeAssertion {
334
353
  min?: number;
335
354
  max?: number;
336
355
  };
356
+ sourceLength?: {
357
+ min?: number;
358
+ max?: number;
359
+ };
337
360
  textFormat?: {
338
361
  format: "isoDate";
339
362
  };
@@ -355,6 +378,7 @@ Selector/assertion compatibility is part of the public contract:
355
378
  | Assertion | Compatible selector targets |
356
379
  | --- | --- |
357
380
  | `exists` | all supported selector targets |
381
+ | `selectionCount` | all supported selector targets |
358
382
  | `sectionsRequired` | `document` |
359
383
  | `tableColumnsRequired` | `table` |
360
384
  | `ids` | all supported selector targets |
@@ -364,6 +388,7 @@ Selector/assertion compatibility is part of the public contract:
364
388
  | `text` | all supported selector targets |
365
389
  | `textOccurrenceCount` | all supported selector targets |
366
390
  | `textLength` | all supported selector targets |
391
+ | `sourceLength` | `document` |
367
392
  | `textFormat` | all supported selector targets |
368
393
  | `frontmatterRequired` | `document` |
369
394
 
@@ -374,6 +399,16 @@ Incompatible supported selector/assertion pairs emit
374
399
  target and fails with `profile.validation.emptySelection` when the selector
375
400
  resolves zero targets.
376
401
 
402
+ For v2 profiles, `selectionCount` must include `min`, `max`, or both. Bounds
403
+ are inclusive non-negative integers, and `min` must be less than or equal to
404
+ `max` when both are present. It evaluates the number of targets resolved by the
405
+ rule selector and is compatible with every supported selector target. An empty
406
+ selection is count zero, so `max: 0` passes and `min: 1` fails with
407
+ `profile.validation.assertionFailed`; `selectionCount` does not replace its
408
+ result with `profile.validation.emptySelection`. Maximum-bound failures use the
409
+ first excess selected target as source evidence when available. Minimum-bound
410
+ failures at zero omit source location rather than fabricating one.
411
+
377
412
  `sectionsRequired.order` defaults to `none`. `strict` checks that configured
378
413
  headings appear as an ordered subsequence in the normalized section tree
379
414
  flattened in source order.
@@ -442,6 +477,17 @@ integers, `min` must be less than or equal to `max` when both are present, and
442
477
  evaluation uses JavaScript string `.length` for each selected target's
443
478
  normalized text.
444
479
 
480
+ For v2 profiles, `sourceLength` must include `min`, `max`, or both with the same
481
+ non-negative integer and ordered-range rules. It is compatible only with a
482
+ `document` selector and evaluates the complete `sourceText` supplied to
483
+ `validateWithProfile`, including frontmatter, Markdown syntax, whitespace, line
484
+ endings, and surrogate pairs, using JavaScript string `.length` (UTF-16 code
485
+ units). The CLI and `validateDocumentSet` supply the exact Markdown input they
486
+ read. When an evaluated `sourceLength` assertion has no complete source
487
+ context, validation fails closed with
488
+ `profile.validation.sourceUnavailable`; normalized document text and source
489
+ ranges are never used as fallbacks.
490
+
445
491
  For v2 profiles, `textFormat` is admitted as a flat-rule schema and internal
446
492
  compiled-plan assertion. `textFormat.format` must be exactly `"isoDate"`;
447
493
  custom formats, locale options, regex-like formats, profile-supplied patterns,
@@ -455,9 +501,10 @@ profile-supplied regular expressions, call `Date.parse`, perform locale
455
501
  parsing, or implement date ordering.
456
502
 
457
503
  Empty selector results produce `profile.validation.emptySelection` for exists,
458
- table, ID, reference, text, occurrence, text-length, and text-format
459
- assertions. Document-scoped required-section, required-frontmatter, and
460
- frontmatter-shape assertions evaluate against the document.
504
+ table, ID, reference, text, occurrence, text-length, and text-format assertions.
505
+ `selectionCount` instead evaluates the empty selection as zero. Document-scoped
506
+ required-section, required-frontmatter, and frontmatter-shape assertions
507
+ evaluate against the document.
461
508
 
462
509
  ## Diagnostics
463
510
 
@@ -470,9 +517,12 @@ rather than fabricated when unavailable.
470
517
 
471
518
  Rule-level `when` uses the existing validation diagnostic codes. When
472
519
  applicability does not match, those diagnostics are cloned into
473
- `ruleResults[].when.diagnostics`; they are not promoted into top-level
520
+ `ruleResults[].when.diagnostics`; they are not normally promoted into top-level
474
521
  `diagnostics`, so a skipped rule with a nested error-severity applicability
475
- diagnostic can still leave the aggregate `valid` value `true`.
522
+ diagnostic can still leave the aggregate `valid` value `true`. The
523
+ `profile.validation.sourceUnavailable` safety diagnostic is the exception: it
524
+ is promoted with error severity so unavailable raw-source context cannot yield
525
+ an unproven pass.
476
526
 
477
527
  | Code | Severity source | Emitted when |
478
528
  | --- | --- | --- |
@@ -486,7 +536,7 @@ diagnostic can still leave the aggregate `valid` value `true`.
486
536
  | `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. |
487
537
  | `profile.compile.incompatibleSelectorAssertion` | `error` | A supported selector target is paired with an incompatible supported assertion. |
488
538
  | `profile.validation.emptySelection` | Rule severity | A rule cannot evaluate because its selector matches no applicable target. |
489
- | `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, text-length bound failures, and text-format `isoDate` failures. |
539
+ | `profile.validation.assertionFailed` | Rule severity | A supported assertion evaluates and fails without a more specific diagnostic code, including selector-count bound failures, missing table columns, exact occurrence-count mismatches, text-length bound failures, and text-format `isoDate` failures. |
490
540
  | `profile.validation.duplicateId` | Rule severity | An `ids.unique` assertion finds repeated IDs. |
491
541
  | `profile.validation.frontmatterForbidden` | Rule severity | A `frontmatterShape` assertion with `presence: "forbidden"` finds present frontmatter. |
492
542
  | `profile.validation.frontmatterFieldEmpty` | Rule severity | A frontmatter field configured with `nonEmpty: true` is not a non-empty string. |
@@ -498,6 +548,7 @@ diagnostic can still leave the aggregate `valid` value `true`.
498
548
  | `profile.validation.referenceMissing` | Rule severity | A source ID is absent from a required target section. |
499
549
  | `profile.validation.sectionMissing` | Rule severity | A required section heading is absent. |
500
550
  | `profile.validation.sectionOrder` | Rule severity | A strict required-section order cannot be satisfied. |
551
+ | `profile.validation.sourceUnavailable` | `error` | An evaluated `sourceLength` assertion cannot access the complete original Markdown source. |
501
552
  | `profile.validation.tableColumnCoverageIdMissing` | Rule severity | A source ID is absent from the configured target table column. |
502
553
  | `profile.validation.tableColumnCoverageTargetColumnMissing` | Rule severity | The configured target table column cannot be resolved. |
503
554
  | `profile.validation.tableColumnCoverageTargetSectionMissing` | Rule severity | The configured target section cannot be resolved. |
@@ -599,6 +650,7 @@ interface DeclarativeValidationEvidence<
599
650
  profileHash: string;
600
651
  engineVersion: string;
601
652
  runtimeVersion: string;
653
+ sourceLength?: number;
602
654
  ruleResults: readonly RuleResult[];
603
655
  diagnostics: readonly MarkdownDiagnostic[];
604
656
  }
@@ -613,10 +665,18 @@ diagnostics array. Evidence does not serialize compiled rule plans, selector
613
665
  target records, assertion-specific ID count evidence, or assertion-specific
614
666
  table-column coverage evidence.
615
667
 
668
+ When a v2 profile uses `sourceLength` and complete source context is available,
669
+ evidence exposes the measured UTF-16 code-unit count as `sourceLength`.
670
+ Profiles that do not use the assertion omit this field and preserve their
671
+ existing evidence serialization.
672
+
616
673
  `inputHash` is a lowercase hexadecimal SHA-256 digest of the stable JSON
617
674
  serialization of the supplied normalized `EngineDocument` after omitting only
618
675
  the top-level `document.path` field. Structural target paths remain part of the
619
- canonical input.
676
+ canonical input. For a profile using `sourceLength`, the canonical input is an
677
+ object containing that normalized document plus the exposed `sourceLength`
678
+ measurement, so otherwise equivalent normalized documents with different raw
679
+ source lengths produce different input hashes.
620
680
 
621
681
  `profileHash` is a lowercase hexadecimal SHA-256 digest of the stable JSON
622
682
  serialization of the resolved `ValidationProfile` after applying the resolved
@@ -628,8 +688,10 @@ the same profile hash for the same document version and rules.
628
688
  matches the package metadata version even though `documentVersion` remains
629
689
  `"1.0.0"`.
630
690
 
631
- Raw Markdown bytes, raw YAML bytes, YAML comments, caller file paths, and
632
- `includeEvidence` itself are not part of either evidence hash.
691
+ Raw Markdown content, raw YAML bytes, YAML comments, caller file paths, and
692
+ `includeEvidence` itself are not part of either evidence hash. Only the numeric
693
+ raw-source length measurement is added to `inputHash`, and only for profiles
694
+ that use `sourceLength`.
633
695
 
634
696
  ## CLI Behavior
635
697
 
@@ -750,6 +812,18 @@ rules:
750
812
  format: isoDate
751
813
  ```
752
814
 
815
+ ```yaml
816
+ # v2 source budget: bounds the complete original Markdown input.
817
+ syntaxVersion: markdown-engine.validation@v2
818
+ rules:
819
+ - id: document.source-budget
820
+ select:
821
+ target: document
822
+ assert:
823
+ sourceLength:
824
+ max: 12000
825
+ ```
826
+
753
827
  The v1 profile above continues to emit the v1 validation-result shape. V2
754
828
  profiles emit syntax-versioned v2 result metadata with
755
829
  `evaluatedRuleCount` and `skippedRuleCount`; v2 rule results include `status`
@@ -773,8 +847,9 @@ Migration notes:
773
847
  skipped-rule `when` diagnostics. Aggregate validity is still determined from
774
848
  top-level diagnostics.
775
849
  - Consumers that compare evidence hashes must normalize expectations around
776
- resolved `documentVersion`, default rule severity, stable key order, and
777
- exclusion of only top-level `document.path` from `inputHash`.
850
+ resolved `documentVersion`, default rule severity, stable key order,
851
+ exclusion of only top-level `document.path`, and conditional inclusion of the
852
+ numeric `sourceLength` measurement in `inputHash`.
778
853
  - Regex-like matching, JavaScript predicates, plugins, semantic scoring, and
779
854
  profile-specific rules belong outside this package unless a future contract
780
855
  explicitly expands the engine boundary.
@@ -863,6 +938,24 @@ rules:
863
938
  exists: true
864
939
  ```
865
940
 
941
+ V2 selector cardinality profile:
942
+
943
+ ```yaml
944
+ syntaxVersion: markdown-engine.validation@v2
945
+ rules:
946
+ - id: actions.table.exactly-one
947
+ select:
948
+ target: table
949
+ section: Execution Actions
950
+ header:
951
+ - Step ID
952
+ - Action
953
+ assert:
954
+ selectionCount:
955
+ min: 1
956
+ max: 1
957
+ ```
958
+
866
959
  ### OKF v0.1 Hard-Validation Profile Composition
867
960
 
868
961
  `markdown-engine` does not ship a built-in OKF validator. Consumers that want to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jasonbelmonti/markdown-engine",
3
- "version": "3.1.1",
3
+ "version": "3.3.0",
4
4
  "description": "Deterministic Markdown parsing and validation engine package.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -49,8 +49,9 @@
49
49
  "build:cli-bundle": "node scripts/build-cli-bundle.mjs",
50
50
  "prepack": "npm run release:verify",
51
51
  "prepublishOnly": "npm run release:verify",
52
- "release:verify": "npm run typecheck && npm test && node scripts/check-boundaries.mjs && npm run docs:rich-ir-contract && npm run docs:declarative-validation-contract && npm run audit:declarative-validation-boundary && npm run build && npm run build:cli:bundled && node scripts/prove-repeatability.mjs --runs 10 && npm run release:check-clean",
53
- "release:check-clean": "git diff --check HEAD -- && git diff --exit-code HEAD --",
52
+ "release:verify": "npm run typecheck && npm test && node scripts/check-boundaries.mjs && npm run docs:rich-ir-contract && npm run docs:declarative-validation-contract && npm run audit:declarative-validation-boundary && npm run build && npm run build:cli:bundled && npm run release:verify:installer-pin && node scripts/prove-repeatability.mjs --runs 10 && npm run release:check-clean",
53
+ "release:verify:installer-pin": "node scripts/check-installer-pin.mjs",
54
+ "release:check-clean": "node scripts/check-release-clean.mjs",
54
55
  "snapshots:update:parser": "npm run build && vitest run tests/parser-fixtures.test.ts -u \"--exclude=.worktrees/**\"",
55
56
  "snapshots:update:rules": "npm run build && vitest run tests/rules.test.ts -u \"--exclude=.worktrees/**\"",
56
57
  "snapshots:update:rich-ir": "npm run build && vitest run tests/rich-ir-targets.test.ts tests/rich-ir-queries.test.ts tests/rich-ir-link-references.test.ts -u \"--exclude=.worktrees/**\"",
@@ -70,7 +71,7 @@
70
71
  "test:validation:profile": "npm run build && vitest run tests/declarative-validation-profile.test.ts \"--exclude=.worktrees/**\"",
71
72
  "test:validation:compiler": "npm run build && vitest run tests/declarative-validation-compiler.test.ts \"--exclude=.worktrees/**\"",
72
73
  "test:validation:selectors": "npm run build && vitest run tests/declarative-validation-selectors.test.ts \"--exclude=.worktrees/**\"",
73
- "test:validation:assertions": "npm run build && vitest run tests/declarative-validation-assertions.test.ts tests/declarative-validation-frontmatter-shape-assertions.test.ts tests/declarative-validation-table-column-coverage-fixtures.test.ts tests/declarative-validation-grouped-rules-fixtures.test.ts tests/declarative-validation-when-skipped-rules-fixtures.test.ts \"--exclude=.worktrees/**\"",
74
+ "test:validation:assertions": "npm run build && vitest run tests/declarative-validation-assertions.test.ts tests/declarative-validation-frontmatter-shape-assertions.test.ts tests/declarative-validation-table-column-coverage-fixtures.test.ts tests/declarative-validation-source-assertion-coverage.test.ts tests/declarative-validation-source-length.test.ts tests/declarative-validation-selection-count.test.ts tests/declarative-validation-normalized-source-ranges.test.ts tests/declarative-validation-grouped-rules-fixtures.test.ts tests/declarative-validation-when-skipped-rules-fixtures.test.ts \"--exclude=.worktrees/**\"",
74
75
  "test:validation:diagnostics": "npm run build && vitest run tests/declarative-validation-diagnostics.test.ts \"--exclude=.worktrees/**\"",
75
76
  "test:validation:cli": "npm run build && vitest run tests/declarative-validation-cli.test.ts \"--exclude=.worktrees/**\"",
76
77
  "test:validation:examples": "npm run build && vitest run tests/declarative-validation-examples.test.ts \"--exclude=.worktrees/**\"",
@@ -80,6 +81,8 @@
80
81
  "docs:declarative-validation-contract": "node scripts/check-declarative-validation-contract-docs.mjs",
81
82
  "typecheck": "tsc -p tsconfig.json --noEmit",
82
83
  "test": "npm run build && vitest run \"--exclude=.worktrees/**\"",
84
+ "test:coverage": "npm run build && npm run build:cli:bundled && vitest run --coverage \"--exclude=.worktrees/**\"",
85
+ "test:coverage:ci": "npm run test:coverage",
83
86
  "test:snapshots": "npm run build && vitest run tests/parser-fixtures.test.ts tests/rules.test.ts tests/rich-ir-targets.test.ts tests/rich-ir-queries.test.ts tests/rich-ir-link-references.test.ts tests/serialization-repeatability.test.ts \"--exclude=.worktrees/**\""
84
87
  },
85
88
  "engines": {
@@ -87,10 +90,11 @@
87
90
  },
88
91
  "devDependencies": {
89
92
  "@types/node": "^22.19.17",
93
+ "@vitest/coverage-v8": "^3.2.7",
90
94
  "cmark-gfm": "^0.9.0",
91
95
  "esbuild": "^0.27.7",
92
96
  "typescript": "^5.8.3",
93
- "vitest": "^3.1.3"
97
+ "vitest": "^3.2.7"
94
98
  },
95
99
  "dependencies": {
96
100
  "remark-gfm": "^4.0.1",
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env sh
2
2
  set -eu
3
3
 
4
- VERSION="3.1.1"
4
+ VERSION="3.3.0"
5
5
  PACKAGE="@jasonbelmonti/markdown-engine"
6
- EXPECTED_SHA256="8c7ff572765cbdc6c38b94de52d69709f583ee7b4d2b7e25ba6be8c92125addf"
6
+ EXPECTED_SHA256="367455824fde63074afe896510fd2133690bb3c06222257e579e575d59105768"
7
7
  DEFAULT_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
8
8
  MARKDOWN_ENGINE_HOME="${MARKDOWN_ENGINE_HOME:-$DEFAULT_DATA_HOME/markdown-engine}"
9
9
  MARKDOWN_ENGINE_BIN_DIR="${MARKDOWN_ENGINE_BIN_DIR:-$HOME/.local/bin}"