@jasonbelmonti/markdown-engine 3.3.0 → 3.5.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 +18 -0
- package/README.md +11 -10
- package/dist/declarative-validation/assertions/evaluator.d.ts.map +1 -1
- package/dist/declarative-validation/assertions/evaluator.js +3 -0
- package/dist/declarative-validation/assertions/evaluator.js.map +1 -1
- package/dist/declarative-validation/assertions/frontmatter-shape.js +45 -5
- package/dist/declarative-validation/assertions/frontmatter-shape.js.map +1 -1
- package/dist/declarative-validation/assertions/table-columns-exact.d.ts +9 -0
- package/dist/declarative-validation/assertions/table-columns-exact.d.ts.map +1 -0
- package/dist/declarative-validation/assertions/table-columns-exact.js +44 -0
- package/dist/declarative-validation/assertions/table-columns-exact.js.map +1 -0
- package/dist/declarative-validation/compiler/assertion-builders.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/assertion-builders.js +18 -0
- package/dist/declarative-validation/compiler/assertion-builders.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.map +1 -1
- package/dist/declarative-validation/compiler/compatibility.js +1 -0
- package/dist/declarative-validation/compiler/compatibility.js.map +1 -1
- package/dist/declarative-validation/compiler/plan.d.ts +3 -0
- package/dist/declarative-validation/compiler/plan.d.ts.map +1 -1
- package/dist/declarative-validation/profile/assertion-schema.d.ts.map +1 -1
- package/dist/declarative-validation/profile/assertion-schema.js +20 -0
- package/dist/declarative-validation/profile/assertion-schema.js.map +1 -1
- package/dist/declarative-validation/profile/frontmatter-shape-schema.js +52 -7
- package/dist/declarative-validation/profile/frontmatter-shape-schema.js.map +1 -1
- package/dist/declarative-validation/profile/index.d.ts +17 -0
- package/dist/declarative-validation/profile/index.d.ts.map +1 -1
- package/dist/internal/package-version.d.ts +1 -1
- package/dist/internal/package-version.js +1 -1
- package/dist-bundled/markdown-engine-cli.mjs +501 -287
- package/docs/contracts/declarative-validation.md +71 -11
- package/package.json +2 -2
- package/scripts/install-markdown-engine-cli.sh +2 -2
|
@@ -1,10 +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-08-
|
|
4
|
+
Last updated: 2026-08-15
|
|
5
5
|
Current v2 surface: flat-rule result/evidence shell, generic selector
|
|
6
6
|
`selectionCount` bounds, document `sourceLength` schema and runtime
|
|
7
|
-
measurement, ID count-bound schema and
|
|
7
|
+
measurement, exact normalized table-header `tableColumnsExact` assertions, ID count-bound schema and
|
|
8
8
|
runtime evaluator contract, plus `tableColumnCoverage` schema, compiled-plan,
|
|
9
9
|
and runtime evaluator contract, `frontmatterShape` schema, compiled-plan, and
|
|
10
10
|
runtime evaluator contract, `textFormat` schema, compiled-plan, and runtime
|
|
@@ -106,7 +106,8 @@ runtime evaluator layers, admits `tableColumnCoverage` at the schema, internal
|
|
|
106
106
|
compiled-plan, and
|
|
107
107
|
runtime evaluator layers, admits `frontmatterShape` at the schema, internal
|
|
108
108
|
compiled-plan, and runtime evaluator layers, admits `textFormat` at the schema,
|
|
109
|
-
internal compiled-plan, and runtime evaluator layers, admits
|
|
109
|
+
internal compiled-plan, and runtime evaluator layers, admits `tableColumnsExact`
|
|
110
|
+
at the schema, internal compiled-plan, and runtime evaluator layers, admits non-recursive
|
|
110
111
|
grouped rules at the schema, compiled-plan, and runtime evaluator layers, and
|
|
111
112
|
admits optional rule-level `when` at the schema, internal compiled-plan, and
|
|
112
113
|
matcher layers.
|
|
@@ -236,7 +237,7 @@ emit `profile.config.invalidShape`.
|
|
|
236
237
|
Rule-level `when` is allowed only on v2 rules. Branch-level `when` remains
|
|
237
238
|
unsupported. V1 profiles preserve the original flat rule authoring contract;
|
|
238
239
|
grouped `anyOf` / `allOf`, ID count bounds, `tableColumnCoverage`,
|
|
239
|
-
`frontmatterShape`, `textFormat`, and rule-level `when` are v2 additions.
|
|
240
|
+
`tableColumnsExact`, `frontmatterShape`, `textFormat`, and rule-level `when` are v2 additions.
|
|
240
241
|
|
|
241
242
|
Profile values must be JSON-safe data properties after YAML materialization.
|
|
242
243
|
Functions, accessors, proxies, cyclic structures, sparse arrays, `undefined`
|
|
@@ -307,6 +308,9 @@ interface DeclarativeAssertion {
|
|
|
307
308
|
tableColumnsRequired?: {
|
|
308
309
|
columns: readonly string[];
|
|
309
310
|
};
|
|
311
|
+
tableColumnsExact?: {
|
|
312
|
+
columns: readonly string[];
|
|
313
|
+
};
|
|
310
314
|
ids?: {
|
|
311
315
|
prefix?: string;
|
|
312
316
|
unique?: boolean;
|
|
@@ -339,6 +343,9 @@ interface DeclarativeAssertion {
|
|
|
339
343
|
required?: true;
|
|
340
344
|
valueType?: "string" | "number" | "boolean" | "array" | "object" | "null";
|
|
341
345
|
nonEmpty?: true;
|
|
346
|
+
equals?: string;
|
|
347
|
+
nonBlank?: true;
|
|
348
|
+
forbidden?: true;
|
|
342
349
|
}[];
|
|
343
350
|
};
|
|
344
351
|
text?: {
|
|
@@ -381,6 +388,7 @@ Selector/assertion compatibility is part of the public contract:
|
|
|
381
388
|
| `selectionCount` | all supported selector targets |
|
|
382
389
|
| `sectionsRequired` | `document` |
|
|
383
390
|
| `tableColumnsRequired` | `table` |
|
|
391
|
+
| `tableColumnsExact` | `table` |
|
|
384
392
|
| `ids` | all supported selector targets |
|
|
385
393
|
| `references` | `document` |
|
|
386
394
|
| `tableColumnCoverage` | `document` |
|
|
@@ -409,6 +417,19 @@ result with `profile.validation.emptySelection`. Maximum-bound failures use the
|
|
|
409
417
|
first excess selected target as source evidence when available. Minimum-bound
|
|
410
418
|
failures at zero omit source location rather than fabricating one.
|
|
411
419
|
|
|
420
|
+
For v2 profiles, `tableColumnsExact` requires a non-empty `columns` array of
|
|
421
|
+
non-empty strings and is compatible only with a `table` selector. It compares
|
|
422
|
+
the complete normalized header sequence from the selected `EngineTable` exactly:
|
|
423
|
+
count, order, text, and duplicate occurrences must all match. Additional
|
|
424
|
+
columns before, between, or after configured columns, and missing, reordered,
|
|
425
|
+
renamed, or duplicated columns fail with
|
|
426
|
+
`profile.validation.assertionFailed`. The deterministic diagnostic includes the
|
|
427
|
+
expected and actual header sequences. When an actual header first mismatches or
|
|
428
|
+
is excess, its header-cell source range is attached when available; otherwise
|
|
429
|
+
the normal selected-table source evidence is retained. This assertion does not
|
|
430
|
+
change the ordered-subsequence behavior of `tableColumnsRequired` or table
|
|
431
|
+
selector `header` / `tableHeader` matching.
|
|
432
|
+
|
|
412
433
|
`sectionsRequired.order` defaults to `none`. `strict` checks that configured
|
|
413
434
|
headings appear as an ordered subsequence in the normalized section tree
|
|
414
435
|
flattened in source order.
|
|
@@ -446,12 +467,17 @@ selector because frontmatter is document metadata. `presence` is optional and
|
|
|
446
467
|
must be exactly `"required"` or `"forbidden"` when provided. `fields` is an
|
|
447
468
|
optional non-empty array of field constraints. Each field constraint has a
|
|
448
469
|
required non-empty `field` name and must include at least one effective
|
|
449
|
-
constraint: `required: true`, `valueType`,
|
|
450
|
-
|
|
470
|
+
constraint: `required: true`, `valueType`, `nonEmpty: true`, `equals`,
|
|
471
|
+
`nonBlank: true`, or `forbidden: true`. Field names within one
|
|
472
|
+
`frontmatterShape.fields` array must be unique. `valueType` must be
|
|
451
473
|
one of `"string"`, `"number"`, `"boolean"`, `"array"`, `"object"`, or `"null"`.
|
|
452
|
-
`nonEmpty: true`
|
|
453
|
-
`valueType` must be `"string"`. `
|
|
454
|
-
|
|
474
|
+
`nonEmpty: true`, `equals`, and `nonBlank: true` are string predicates; when
|
|
475
|
+
any is combined with `valueType`, `valueType` must be `"string"`. `equals`
|
|
476
|
+
accepts any string, including the empty string, and compares it exactly.
|
|
477
|
+
`nonBlank: true` requires a string whose JavaScript `trim()` result is non-empty.
|
|
478
|
+
`forbidden: true` requires the named field to be absent and cannot be combined
|
|
479
|
+
with `required`, `valueType`, `nonEmpty`, `equals`, or `nonBlank`.
|
|
480
|
+
`presence: "forbidden"` cannot be combined with `fields`.
|
|
455
481
|
|
|
456
482
|
Runtime evaluation treats frontmatter as present when
|
|
457
483
|
`document.frontmatter !== undefined`. `presence: "required"` fails absent
|
|
@@ -468,6 +494,16 @@ requires a present field value to be a non-empty string and emits
|
|
|
468
494
|
`profile.validation.frontmatterFieldEmpty` when that predicate fails. When
|
|
469
495
|
`valueType: "string"` and `nonEmpty: true` are combined, a non-string value
|
|
470
496
|
emits the type-mismatch diagnostic without a duplicate empty-string diagnostic.
|
|
497
|
+
`equals` compares present strings exactly without coercion and emits
|
|
498
|
+
`profile.validation.frontmatterFieldValueMismatch` on mismatch. `nonBlank: true`
|
|
499
|
+
uses JavaScript `trim()` without coercion and emits
|
|
500
|
+
`profile.validation.frontmatterFieldBlank` when its field is not a non-blank
|
|
501
|
+
string. `forbidden: true` emits `profile.validation.frontmatterFieldForbidden`
|
|
502
|
+
when the named field is present, regardless of value. When `valueType: "string"`
|
|
503
|
+
is combined with `equals` or `nonBlank`, a non-string value emits only
|
|
504
|
+
`profile.validation.frontmatterFieldTypeMismatch` rather than an additional
|
|
505
|
+
string-predicate diagnostic. Diagnostic messages do not include frontmatter
|
|
506
|
+
values.
|
|
471
507
|
|
|
472
508
|
`text` must include `contains` or a non-empty `excludes` array.
|
|
473
509
|
`textOccurrenceCount.count` is a finite number and counts non-overlapping
|
|
@@ -501,7 +537,8 @@ profile-supplied regular expressions, call `Date.parse`, perform locale
|
|
|
501
537
|
parsing, or implement date ordering.
|
|
502
538
|
|
|
503
539
|
Empty selector results produce `profile.validation.emptySelection` for exists,
|
|
504
|
-
table, ID, reference, text, occurrence, text-length,
|
|
540
|
+
table, ID, reference, text, occurrence, text-length, text-format, and
|
|
541
|
+
tableColumnsExact assertions.
|
|
505
542
|
`selectionCount` instead evaluates the empty selection as zero. Document-scoped
|
|
506
543
|
required-section, required-frontmatter, and frontmatter-shape assertions
|
|
507
544
|
evaluate against the document.
|
|
@@ -536,12 +573,15 @@ an unproven pass.
|
|
|
536
573
|
| `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. |
|
|
537
574
|
| `profile.compile.incompatibleSelectorAssertion` | `error` | A supported selector target is paired with an incompatible supported assertion. |
|
|
538
575
|
| `profile.validation.emptySelection` | Rule severity | A rule cannot evaluate because its selector matches no applicable target. |
|
|
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. |
|
|
576
|
+
| `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 table-header mismatches, exact occurrence-count mismatches, text-length bound failures, and text-format `isoDate` failures. |
|
|
540
577
|
| `profile.validation.duplicateId` | Rule severity | An `ids.unique` assertion finds repeated IDs. |
|
|
541
578
|
| `profile.validation.frontmatterForbidden` | Rule severity | A `frontmatterShape` assertion with `presence: "forbidden"` finds present frontmatter. |
|
|
579
|
+
| `profile.validation.frontmatterFieldBlank` | Rule severity | A frontmatter field configured with `nonBlank: true` is not a non-blank string. |
|
|
542
580
|
| `profile.validation.frontmatterFieldEmpty` | Rule severity | A frontmatter field configured with `nonEmpty: true` is not a non-empty string. |
|
|
581
|
+
| `profile.validation.frontmatterFieldForbidden` | Rule severity | A frontmatter field configured with `forbidden: true` is present. |
|
|
543
582
|
| `profile.validation.frontmatterFieldMissing` | Rule severity | A required frontmatter field is absent. |
|
|
544
583
|
| `profile.validation.frontmatterFieldTypeMismatch` | Rule severity | A frontmatter field value does not match the configured `frontmatterShape.fields[].valueType` without coercion. |
|
|
584
|
+
| `profile.validation.frontmatterFieldValueMismatch` | Rule severity | A frontmatter field configured with `equals` does not exactly match the configured string without coercion. |
|
|
545
585
|
| `profile.validation.frontmatterMissing` | Rule severity | A `frontmatterShape` assertion with `presence: "required"` finds absent frontmatter. |
|
|
546
586
|
| `profile.validation.idCountTooHigh` | Rule severity | Unique ID count after filtering is higher than `ids.maxCount`. |
|
|
547
587
|
| `profile.validation.idCountTooLow` | Rule severity | Unique ID count after filtering is lower than `ids.minCount`. |
|
|
@@ -956,6 +996,26 @@ rules:
|
|
|
956
996
|
max: 1
|
|
957
997
|
```
|
|
958
998
|
|
|
999
|
+
V2 exact table-column profile:
|
|
1000
|
+
|
|
1001
|
+
```yaml
|
|
1002
|
+
syntaxVersion: markdown-engine.validation@v2
|
|
1003
|
+
rules:
|
|
1004
|
+
- id: task-control.columns
|
|
1005
|
+
select:
|
|
1006
|
+
target: table
|
|
1007
|
+
assert:
|
|
1008
|
+
tableColumnsExact:
|
|
1009
|
+
columns:
|
|
1010
|
+
- Contract state
|
|
1011
|
+
- Execution route
|
|
1012
|
+
- State rationale
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
The assertion compares the complete normalized header sequence. It is stricter
|
|
1016
|
+
than `tableColumnsRequired`, which continues to accept ordered-subsequence
|
|
1017
|
+
matches with unrelated columns before, between, or after required names.
|
|
1018
|
+
|
|
959
1019
|
### OKF v0.1 Hard-Validation Profile Composition
|
|
960
1020
|
|
|
961
1021
|
`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.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Deterministic Markdown parsing and validation engine package.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"test:validation:profile": "npm run build && vitest run tests/declarative-validation-profile.test.ts \"--exclude=.worktrees/**\"",
|
|
72
72
|
"test:validation:compiler": "npm run build && vitest run tests/declarative-validation-compiler.test.ts \"--exclude=.worktrees/**\"",
|
|
73
73
|
"test:validation:selectors": "npm run build && vitest run tests/declarative-validation-selectors.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
|
+
"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-table-columns-exact.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/**\"",
|
|
75
75
|
"test:validation:diagnostics": "npm run build && vitest run tests/declarative-validation-diagnostics.test.ts \"--exclude=.worktrees/**\"",
|
|
76
76
|
"test:validation:cli": "npm run build && vitest run tests/declarative-validation-cli.test.ts \"--exclude=.worktrees/**\"",
|
|
77
77
|
"test:validation:examples": "npm run build && vitest run tests/declarative-validation-examples.test.ts \"--exclude=.worktrees/**\"",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
2
|
set -eu
|
|
3
3
|
|
|
4
|
-
VERSION="3.
|
|
4
|
+
VERSION="3.5.0"
|
|
5
5
|
PACKAGE="@jasonbelmonti/markdown-engine"
|
|
6
|
-
EXPECTED_SHA256="
|
|
6
|
+
EXPECTED_SHA256="4a4e9ae7d9ff4797c96a7483555bcba7cbec5852d330c6c50dc0ef8fb2e5d933"
|
|
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}"
|