@jasonbelmonti/markdown-engine 3.1.0 → 3.2.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.
- package/CHANGELOG.md +23 -0
- package/README.md +29 -10
- package/SECURITY.md +4 -4
- package/dist/api/declarative-validation.d.ts.map +1 -1
- package/dist/api/declarative-validation.js +31 -11
- package/dist/api/declarative-validation.js.map +1 -1
- package/dist/api/document-set-validation.js +1 -0
- package/dist/api/document-set-validation.js.map +1 -1
- package/dist/cli/declarative-validation.d.ts.map +1 -1
- package/dist/cli/declarative-validation.js +4 -4
- package/dist/cli/declarative-validation.js.map +1 -1
- package/dist/declarative-validation/applicability/classifier.d.ts +2 -1
- package/dist/declarative-validation/applicability/classifier.d.ts.map +1 -1
- package/dist/declarative-validation/applicability/classifier.js +2 -2
- package/dist/declarative-validation/applicability/classifier.js.map +1 -1
- package/dist/declarative-validation/assertions/context.d.ts +4 -0
- package/dist/declarative-validation/assertions/context.d.ts.map +1 -1
- package/dist/declarative-validation/assertions/diagnostics.d.ts +3 -0
- package/dist/declarative-validation/assertions/diagnostics.d.ts.map +1 -1
- package/dist/declarative-validation/assertions/diagnostics.js +18 -0
- package/dist/declarative-validation/assertions/diagnostics.js.map +1 -1
- package/dist/declarative-validation/assertions/evaluator.d.ts +2 -1
- package/dist/declarative-validation/assertions/evaluator.d.ts.map +1 -1
- package/dist/declarative-validation/assertions/evaluator.js +7 -1
- package/dist/declarative-validation/assertions/evaluator.js.map +1 -1
- package/dist/declarative-validation/assertions/group-evaluator.d.ts +3 -2
- package/dist/declarative-validation/assertions/group-evaluator.d.ts.map +1 -1
- package/dist/declarative-validation/assertions/group-evaluator.js +32 -14
- package/dist/declarative-validation/assertions/group-evaluator.js.map +1 -1
- package/dist/declarative-validation/assertions/source-length.d.ts +9 -0
- package/dist/declarative-validation/assertions/source-length.d.ts.map +1 -0
- package/dist/declarative-validation/assertions/source-length.js +33 -0
- package/dist/declarative-validation/assertions/source-length.js.map +1 -0
- package/dist/declarative-validation/compiler/assertion-builders.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/assertion-builders.js +4 -32
- package/dist/declarative-validation/compiler/assertion-builders.js.map +1 -1
- package/dist/declarative-validation/compiler/assertion-shapes.d.ts +1 -2
- package/dist/declarative-validation/compiler/assertion-shapes.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/assertion-shapes.js +1 -25
- package/dist/declarative-validation/compiler/assertion-shapes.js.map +1 -1
- package/dist/declarative-validation/compiler/assertions.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/assertions.js +1 -0
- package/dist/declarative-validation/compiler/assertions.js.map +1 -1
- package/dist/declarative-validation/compiler/compatibility.d.ts +2 -0
- package/dist/declarative-validation/compiler/compatibility.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/compatibility.js +10 -0
- package/dist/declarative-validation/compiler/compatibility.js.map +1 -1
- package/dist/declarative-validation/compiler/index.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/index.js +10 -3
- package/dist/declarative-validation/compiler/index.js.map +1 -1
- package/dist/declarative-validation/compiler/length-assertion-builders.d.ts +7 -0
- package/dist/declarative-validation/compiler/length-assertion-builders.d.ts.map +1 -0
- package/dist/declarative-validation/compiler/length-assertion-builders.js +58 -0
- package/dist/declarative-validation/compiler/length-assertion-builders.js.map +1 -0
- package/dist/declarative-validation/compiler/plan.d.ts +4 -0
- package/dist/declarative-validation/compiler/plan.d.ts.map +1 -1
- package/dist/declarative-validation/evidence/index.d.ts +2 -1
- package/dist/declarative-validation/evidence/index.d.ts.map +1 -1
- package/dist/declarative-validation/evidence/index.js +27 -3
- package/dist/declarative-validation/evidence/index.js.map +1 -1
- package/dist/declarative-validation/profile/assertion-schema.d.ts.map +1 -1
- package/dist/declarative-validation/profile/assertion-schema.js +11 -50
- package/dist/declarative-validation/profile/assertion-schema.js.map +1 -1
- package/dist/declarative-validation/profile/index.d.ts +4 -0
- package/dist/declarative-validation/profile/index.d.ts.map +1 -1
- package/dist/declarative-validation/profile/length-bound-schema.d.ts +7 -0
- package/dist/declarative-validation/profile/length-bound-schema.d.ts.map +1 -0
- package/dist/declarative-validation/profile/length-bound-schema.js +55 -0
- package/dist/declarative-validation/profile/length-bound-schema.js.map +1 -0
- package/dist/declarative-validation/results/create-result.js +1 -1
- package/dist/declarative-validation/results/create-result.js.map +1 -1
- package/dist/declarative-validation/results/types.d.ts +1 -0
- package/dist/declarative-validation/results/types.d.ts.map +1 -1
- package/dist/internal/package-version.d.ts +2 -0
- package/dist/internal/package-version.d.ts.map +1 -0
- package/dist/internal/package-version.js +2 -0
- package/dist/internal/package-version.js.map +1 -0
- package/dist-bundled/markdown-engine-cli.mjs +702 -525
- package/docs/contracts/declarative-validation.md +66 -10
- package/package.json +9 -5
- package/scripts/install-markdown-engine-cli.sh +2 -2
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Status: package 3.0.0, v1 profile syntax with v2 Conditional V2, document contract 1.0.0
|
|
4
4
|
Last updated: 2026-06-15
|
|
5
|
-
Current v2 surface: flat-rule result/evidence shell,
|
|
5
|
+
Current v2 surface: flat-rule result/evidence shell, document `sourceLength`
|
|
6
|
+
schema and runtime measurement, ID count-bound schema and
|
|
6
7
|
runtime evaluator contract, plus `tableColumnCoverage` schema, compiled-plan,
|
|
7
8
|
and runtime evaluator contract, `frontmatterShape` schema, compiled-plan, and
|
|
8
9
|
runtime evaluator contract, `textFormat` schema, compiled-plan, and runtime
|
|
@@ -63,8 +64,19 @@ validateDocumentSet(
|
|
|
63
64
|
entries: readonly ValidateDocumentSetEntry[],
|
|
64
65
|
options?: ValidateDocumentSetOptions,
|
|
65
66
|
): ValidateDocumentSetResult
|
|
67
|
+
|
|
68
|
+
interface DeclarativeValidationOptions {
|
|
69
|
+
path?: string;
|
|
70
|
+
includeEvidence?: boolean;
|
|
71
|
+
sourceText?: string;
|
|
72
|
+
}
|
|
66
73
|
```
|
|
67
74
|
|
|
75
|
+
`sourceText` carries the complete original Markdown string to validation. It is
|
|
76
|
+
required only when an evaluated v2 `sourceLength` assertion needs to measure
|
|
77
|
+
the pre-normalization input; it does not become an enumerable
|
|
78
|
+
`EngineDocument` field.
|
|
79
|
+
|
|
68
80
|
Compiled declarative validation plans are internal. They are not exported from
|
|
69
81
|
the package root, are not serialized in API or CLI results, and carry no semver
|
|
70
82
|
stability guarantee.
|
|
@@ -334,6 +346,10 @@ interface DeclarativeAssertion {
|
|
|
334
346
|
min?: number;
|
|
335
347
|
max?: number;
|
|
336
348
|
};
|
|
349
|
+
sourceLength?: {
|
|
350
|
+
min?: number;
|
|
351
|
+
max?: number;
|
|
352
|
+
};
|
|
337
353
|
textFormat?: {
|
|
338
354
|
format: "isoDate";
|
|
339
355
|
};
|
|
@@ -364,6 +380,7 @@ Selector/assertion compatibility is part of the public contract:
|
|
|
364
380
|
| `text` | all supported selector targets |
|
|
365
381
|
| `textOccurrenceCount` | all supported selector targets |
|
|
366
382
|
| `textLength` | all supported selector targets |
|
|
383
|
+
| `sourceLength` | `document` |
|
|
367
384
|
| `textFormat` | all supported selector targets |
|
|
368
385
|
| `frontmatterRequired` | `document` |
|
|
369
386
|
|
|
@@ -442,6 +459,17 @@ integers, `min` must be less than or equal to `max` when both are present, and
|
|
|
442
459
|
evaluation uses JavaScript string `.length` for each selected target's
|
|
443
460
|
normalized text.
|
|
444
461
|
|
|
462
|
+
For v2 profiles, `sourceLength` must include `min`, `max`, or both with the same
|
|
463
|
+
non-negative integer and ordered-range rules. It is compatible only with a
|
|
464
|
+
`document` selector and evaluates the complete `sourceText` supplied to
|
|
465
|
+
`validateWithProfile`, including frontmatter, Markdown syntax, whitespace, line
|
|
466
|
+
endings, and surrogate pairs, using JavaScript string `.length` (UTF-16 code
|
|
467
|
+
units). The CLI and `validateDocumentSet` supply the exact Markdown input they
|
|
468
|
+
read. When an evaluated `sourceLength` assertion has no complete source
|
|
469
|
+
context, validation fails closed with
|
|
470
|
+
`profile.validation.sourceUnavailable`; normalized document text and source
|
|
471
|
+
ranges are never used as fallbacks.
|
|
472
|
+
|
|
445
473
|
For v2 profiles, `textFormat` is admitted as a flat-rule schema and internal
|
|
446
474
|
compiled-plan assertion. `textFormat.format` must be exactly `"isoDate"`;
|
|
447
475
|
custom formats, locale options, regex-like formats, profile-supplied patterns,
|
|
@@ -470,9 +498,12 @@ rather than fabricated when unavailable.
|
|
|
470
498
|
|
|
471
499
|
Rule-level `when` uses the existing validation diagnostic codes. When
|
|
472
500
|
applicability does not match, those diagnostics are cloned into
|
|
473
|
-
`ruleResults[].when.diagnostics`; they are not promoted into top-level
|
|
501
|
+
`ruleResults[].when.diagnostics`; they are not normally promoted into top-level
|
|
474
502
|
`diagnostics`, so a skipped rule with a nested error-severity applicability
|
|
475
|
-
diagnostic can still leave the aggregate `valid` value `true`.
|
|
503
|
+
diagnostic can still leave the aggregate `valid` value `true`. The
|
|
504
|
+
`profile.validation.sourceUnavailable` safety diagnostic is the exception: it
|
|
505
|
+
is promoted with error severity so unavailable raw-source context cannot yield
|
|
506
|
+
an unproven pass.
|
|
476
507
|
|
|
477
508
|
| Code | Severity source | Emitted when |
|
|
478
509
|
| --- | --- | --- |
|
|
@@ -498,6 +529,7 @@ diagnostic can still leave the aggregate `valid` value `true`.
|
|
|
498
529
|
| `profile.validation.referenceMissing` | Rule severity | A source ID is absent from a required target section. |
|
|
499
530
|
| `profile.validation.sectionMissing` | Rule severity | A required section heading is absent. |
|
|
500
531
|
| `profile.validation.sectionOrder` | Rule severity | A strict required-section order cannot be satisfied. |
|
|
532
|
+
| `profile.validation.sourceUnavailable` | `error` | An evaluated `sourceLength` assertion cannot access the complete original Markdown source. |
|
|
501
533
|
| `profile.validation.tableColumnCoverageIdMissing` | Rule severity | A source ID is absent from the configured target table column. |
|
|
502
534
|
| `profile.validation.tableColumnCoverageTargetColumnMissing` | Rule severity | The configured target table column cannot be resolved. |
|
|
503
535
|
| `profile.validation.tableColumnCoverageTargetSectionMissing` | Rule severity | The configured target section cannot be resolved. |
|
|
@@ -599,6 +631,7 @@ interface DeclarativeValidationEvidence<
|
|
|
599
631
|
profileHash: string;
|
|
600
632
|
engineVersion: string;
|
|
601
633
|
runtimeVersion: string;
|
|
634
|
+
sourceLength?: number;
|
|
602
635
|
ruleResults: readonly RuleResult[];
|
|
603
636
|
diagnostics: readonly MarkdownDiagnostic[];
|
|
604
637
|
}
|
|
@@ -613,10 +646,18 @@ diagnostics array. Evidence does not serialize compiled rule plans, selector
|
|
|
613
646
|
target records, assertion-specific ID count evidence, or assertion-specific
|
|
614
647
|
table-column coverage evidence.
|
|
615
648
|
|
|
649
|
+
When a v2 profile uses `sourceLength` and complete source context is available,
|
|
650
|
+
evidence exposes the measured UTF-16 code-unit count as `sourceLength`.
|
|
651
|
+
Profiles that do not use the assertion omit this field and preserve their
|
|
652
|
+
existing evidence serialization.
|
|
653
|
+
|
|
616
654
|
`inputHash` is a lowercase hexadecimal SHA-256 digest of the stable JSON
|
|
617
655
|
serialization of the supplied normalized `EngineDocument` after omitting only
|
|
618
656
|
the top-level `document.path` field. Structural target paths remain part of the
|
|
619
|
-
canonical input.
|
|
657
|
+
canonical input. For a profile using `sourceLength`, the canonical input is an
|
|
658
|
+
object containing that normalized document plus the exposed `sourceLength`
|
|
659
|
+
measurement, so otherwise equivalent normalized documents with different raw
|
|
660
|
+
source lengths produce different input hashes.
|
|
620
661
|
|
|
621
662
|
`profileHash` is a lowercase hexadecimal SHA-256 digest of the stable JSON
|
|
622
663
|
serialization of the resolved `ValidationProfile` after applying the resolved
|
|
@@ -624,12 +665,14 @@ serialization of the resolved `ValidationProfile` after applying the resolved
|
|
|
624
665
|
`documentVersion` and an explicit matching `documentVersion` therefore produce
|
|
625
666
|
the same profile hash for the same document version and rules.
|
|
626
667
|
|
|
627
|
-
`engineVersion` records the package version that produced the evidence.
|
|
628
|
-
|
|
668
|
+
`engineVersion` records the package version that produced the evidence. This
|
|
669
|
+
matches the package metadata version even though `documentVersion` remains
|
|
629
670
|
`"1.0.0"`.
|
|
630
671
|
|
|
631
|
-
Raw Markdown
|
|
632
|
-
`includeEvidence` itself are not part of either evidence hash.
|
|
672
|
+
Raw Markdown content, raw YAML bytes, YAML comments, caller file paths, and
|
|
673
|
+
`includeEvidence` itself are not part of either evidence hash. Only the numeric
|
|
674
|
+
raw-source length measurement is added to `inputHash`, and only for profiles
|
|
675
|
+
that use `sourceLength`.
|
|
633
676
|
|
|
634
677
|
## CLI Behavior
|
|
635
678
|
|
|
@@ -750,6 +793,18 @@ rules:
|
|
|
750
793
|
format: isoDate
|
|
751
794
|
```
|
|
752
795
|
|
|
796
|
+
```yaml
|
|
797
|
+
# v2 source budget: bounds the complete original Markdown input.
|
|
798
|
+
syntaxVersion: markdown-engine.validation@v2
|
|
799
|
+
rules:
|
|
800
|
+
- id: document.source-budget
|
|
801
|
+
select:
|
|
802
|
+
target: document
|
|
803
|
+
assert:
|
|
804
|
+
sourceLength:
|
|
805
|
+
max: 12000
|
|
806
|
+
```
|
|
807
|
+
|
|
753
808
|
The v1 profile above continues to emit the v1 validation-result shape. V2
|
|
754
809
|
profiles emit syntax-versioned v2 result metadata with
|
|
755
810
|
`evaluatedRuleCount` and `skippedRuleCount`; v2 rule results include `status`
|
|
@@ -773,8 +828,9 @@ Migration notes:
|
|
|
773
828
|
skipped-rule `when` diagnostics. Aggregate validity is still determined from
|
|
774
829
|
top-level diagnostics.
|
|
775
830
|
- Consumers that compare evidence hashes must normalize expectations around
|
|
776
|
-
resolved `documentVersion`, default rule severity, stable key order,
|
|
777
|
-
exclusion of only top-level `document.path
|
|
831
|
+
resolved `documentVersion`, default rule severity, stable key order,
|
|
832
|
+
exclusion of only top-level `document.path`, and conditional inclusion of the
|
|
833
|
+
numeric `sourceLength` measurement in `inputHash`.
|
|
778
834
|
- Regex-like matching, JavaScript predicates, plugins, semantic scoring, and
|
|
779
835
|
profile-specific rules belong outside this package unless a future contract
|
|
780
836
|
explicitly expands the engine boundary.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jasonbelmonti/markdown-engine",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.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:
|
|
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-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.
|
|
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.
|
|
4
|
+
VERSION="3.2.0"
|
|
5
5
|
PACKAGE="@jasonbelmonti/markdown-engine"
|
|
6
|
-
EXPECTED_SHA256="
|
|
6
|
+
EXPECTED_SHA256="5033d08160fcd3f44b11498dc29d01db73d7aff2a55eb3257fd9a1c14e29c3f6"
|
|
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}"
|