@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
@@ -7622,6 +7622,7 @@ function sourceSliceProperty(sourceSlice2) {
7622
7622
  }
7623
7623
 
7624
7624
  // src/declarative-validation/assertions/diagnostics.ts
7625
+ var SOURCE_UNAVAILABLE_DIAGNOSTIC_CODE = "profile.validation.sourceUnavailable";
7625
7626
  function noAlternativeMatchedDiagnostic(rule) {
7626
7627
  return {
7627
7628
  code: "profile.validation.noAlternativeMatched",
@@ -7650,6 +7651,23 @@ function emptySelectionDiagnostic(rule, assertionIndex) {
7650
7651
  }
7651
7652
  );
7652
7653
  }
7654
+ function sourceUnavailableDiagnostic(rule, assertionIndex) {
7655
+ return {
7656
+ diagnostic: {
7657
+ code: SOURCE_UNAVAILABLE_DIAGNOSTIC_CODE,
7658
+ ruleId: rule.ruleId,
7659
+ message: "Complete Markdown source is required to evaluate sourceLength.",
7660
+ severity: "error"
7661
+ },
7662
+ assertionIndex,
7663
+ targetOrder: 0,
7664
+ targetKey: "document:source",
7665
+ diagnosticOrder: 0
7666
+ };
7667
+ }
7668
+ function isSourceUnavailableDiagnostic(diagnostic) {
7669
+ return diagnostic.code === SOURCE_UNAVAILABLE_DIAGNOSTIC_CODE;
7670
+ }
7653
7671
  function validationDiagnostic(code3, message, rule, options) {
7654
7672
  const sourceRange = options.sourceRange ?? targetSourceRange(options.target);
7655
7673
  return {
@@ -9460,6 +9478,79 @@ function sectionHeadingSourceRange(document3, section) {
9460
9478
  return section === void 0 ? void 0 : documentQueries.sourceSlice(document3, section.headingTarget)?.range;
9461
9479
  }
9462
9480
 
9481
+ // src/declarative-validation/assertions/selection-count.ts
9482
+ function evaluateSelectionCount(assertion, context) {
9483
+ const actualCount = context.selection.targets.length;
9484
+ if (isCountWithinBounds(actualCount, assertion)) {
9485
+ return [];
9486
+ }
9487
+ const firstExcessTargetOrder = assertion.max;
9488
+ const firstExcessTarget = firstExcessTargetOrder === void 0 ? void 0 : context.selection.targets[firstExcessTargetOrder];
9489
+ return [
9490
+ validationDiagnostic(
9491
+ "profile.validation.assertionFailed",
9492
+ `Rule selector target count must be ${selectionCountRequirement(assertion)}; found ${actualCount}.`,
9493
+ context.rule,
9494
+ {
9495
+ assertionIndex: context.assertionIndex,
9496
+ ...firstExcessTarget !== void 0 && firstExcessTargetOrder !== void 0 ? { target: firstExcessTarget, targetOrder: firstExcessTargetOrder } : { targetKey: "selection:count" }
9497
+ }
9498
+ )
9499
+ ];
9500
+ }
9501
+ function isCountWithinBounds(actualCount, assertion) {
9502
+ return (assertion.min === void 0 || actualCount >= assertion.min) && (assertion.max === void 0 || actualCount <= assertion.max);
9503
+ }
9504
+ function selectionCountRequirement(assertion) {
9505
+ if (assertion.min !== void 0 && assertion.max !== void 0) {
9506
+ return `between ${assertion.min} and ${assertion.max}`;
9507
+ }
9508
+ if (assertion.min !== void 0) {
9509
+ return `at least ${assertion.min}`;
9510
+ }
9511
+ if (assertion.max !== void 0) {
9512
+ return `at most ${assertion.max}`;
9513
+ }
9514
+ return "within configured bounds";
9515
+ }
9516
+
9517
+ // src/declarative-validation/assertions/source-length.ts
9518
+ function evaluateSourceLength(assertion, context) {
9519
+ if (context.sourceText === void 0) {
9520
+ return [sourceUnavailableDiagnostic(context.rule, context.assertionIndex)];
9521
+ }
9522
+ const actualLength = context.sourceText.length;
9523
+ if (isLengthWithinBounds(actualLength, assertion)) {
9524
+ return [];
9525
+ }
9526
+ return [
9527
+ validationDiagnostic(
9528
+ "profile.validation.assertionFailed",
9529
+ `Document source length must be ${sourceLengthRequirement(assertion)}; found ${actualLength}.`,
9530
+ context.rule,
9531
+ {
9532
+ assertionIndex: context.assertionIndex,
9533
+ targetKey: "document:source"
9534
+ }
9535
+ )
9536
+ ];
9537
+ }
9538
+ function isLengthWithinBounds(actualLength, assertion) {
9539
+ return (assertion.min === void 0 || actualLength >= assertion.min) && (assertion.max === void 0 || actualLength <= assertion.max);
9540
+ }
9541
+ function sourceLengthRequirement(assertion) {
9542
+ if (assertion.min !== void 0 && assertion.max !== void 0) {
9543
+ return `between ${assertion.min} and ${assertion.max}`;
9544
+ }
9545
+ if (assertion.min !== void 0) {
9546
+ return `at least ${assertion.min}`;
9547
+ }
9548
+ if (assertion.max !== void 0) {
9549
+ return `at most ${assertion.max}`;
9550
+ }
9551
+ return "within configured bounds";
9552
+ }
9553
+
9463
9554
  // src/declarative-validation/assertions/table-column-coverage.ts
9464
9555
  function evaluateTableColumnCoverage(assertion, context) {
9465
9556
  const options = idTokenOptions(assertion);
@@ -9791,7 +9882,7 @@ function evaluateTextLength(assertion, context) {
9791
9882
  }
9792
9883
  function evaluateTextLengthTarget(assertion, context, target, targetOrder) {
9793
9884
  const actualLength = target.text.length;
9794
- if (isLengthWithinBounds(actualLength, assertion)) {
9885
+ if (isLengthWithinBounds2(actualLength, assertion)) {
9795
9886
  return [];
9796
9887
  }
9797
9888
  return [
@@ -9807,7 +9898,7 @@ function evaluateTextLengthTarget(assertion, context, target, targetOrder) {
9807
9898
  )
9808
9899
  ];
9809
9900
  }
9810
- function isLengthWithinBounds(actualLength, assertion) {
9901
+ function isLengthWithinBounds2(actualLength, assertion) {
9811
9902
  return (assertion.min === void 0 || actualLength >= assertion.min) && (assertion.max === void 0 || actualLength <= assertion.max);
9812
9903
  }
9813
9904
  function textLengthMessage(targetKind, actualLength, assertion) {
@@ -9858,12 +9949,13 @@ function evaluateTextOccurrenceCountTarget(assertion, context, target, targetOrd
9858
9949
  }
9859
9950
 
9860
9951
  // src/declarative-validation/assertions/evaluator.ts
9861
- function evaluateCompiledDeclarativeRule(rule, selection) {
9952
+ function evaluateCompiledDeclarativeRule(rule, selection, runtimeContext = {}) {
9862
9953
  const evaluatedDiagnostics = rule.assertions.flatMap(
9863
9954
  (assertion, assertionIndex) => evaluateAssertion(assertion, {
9864
9955
  rule,
9865
9956
  selection,
9866
- assertionIndex
9957
+ assertionIndex,
9958
+ ...runtimeContext.sourceText !== void 0 ? { sourceText: runtimeContext.sourceText } : {}
9867
9959
  })
9868
9960
  );
9869
9961
  const diagnostics = sortAssertionDiagnostics(evaluatedDiagnostics);
@@ -9879,12 +9971,16 @@ function evaluateAssertion(assertion, context) {
9879
9971
  return evaluateExists(context);
9880
9972
  case "sectionsRequired":
9881
9973
  return evaluateSectionsRequired(assertion, context);
9974
+ case "selectionCount":
9975
+ return evaluateSelectionCount(assertion, context);
9882
9976
  case "text":
9883
9977
  return evaluateText(assertion, context);
9884
9978
  case "textOccurrenceCount":
9885
9979
  return evaluateTextOccurrenceCount(assertion, context);
9886
9980
  case "textLength":
9887
9981
  return evaluateTextLength(assertion, context);
9982
+ case "sourceLength":
9983
+ return evaluateSourceLength(assertion, context);
9888
9984
  case "textFormat":
9889
9985
  return evaluateTextFormat(assertion, context);
9890
9986
  case "frontmatterRequired":
@@ -9903,14 +9999,15 @@ function evaluateAssertion(assertion, context) {
9903
9999
  }
9904
10000
 
9905
10001
  // src/declarative-validation/applicability/classifier.ts
9906
- function classifyCompiledDeclarativeRuleApplicability(rule, document3) {
10002
+ function classifyCompiledDeclarativeRuleApplicability(rule, document3, runtimeContext = {}) {
9907
10003
  const applicability = compiledApplicabilityFromRule(rule);
9908
10004
  if (applicability === void 0) {
9909
10005
  return { status: "notConfigured" };
9910
10006
  }
9911
10007
  const result = evaluateCompiledDeclarativeRule(
9912
10008
  applicabilityRuleFromPlan(rule, applicability),
9913
- resolveDeclarativeSelector(document3, applicability.selector)
10009
+ resolveDeclarativeSelector(document3, applicability.selector),
10010
+ runtimeContext
9914
10011
  );
9915
10012
  if (result.diagnostics.length === 0) {
9916
10013
  return {
@@ -9942,11 +10039,21 @@ function applicabilityRuleFromPlan(rule, applicability) {
9942
10039
  }
9943
10040
 
9944
10041
  // src/declarative-validation/assertions/group-evaluator.ts
9945
- function evaluateCompiledDeclarativeAnyOfRule(rule, document3) {
9946
- const branches = evaluateCompiledDeclarativeBranches(rule.branches, document3);
10042
+ function evaluateCompiledDeclarativeAnyOfRule(rule, document3, runtimeContext = {}) {
10043
+ const branches = evaluateCompiledDeclarativeBranches(
10044
+ rule.branches,
10045
+ document3,
10046
+ runtimeContext
10047
+ );
10048
+ const sourceUnavailable = sourceUnavailableDiagnostics(branches);
9947
10049
  const selectedBranch = branches.find((branch) => branch.status === "passed");
9948
- const passed = selectedBranch !== void 0;
9949
- const diagnostics = passed ? [] : [noAlternativeMatchedDiagnostic(rule)];
10050
+ const passed = selectedBranch !== void 0 && sourceUnavailable.length === 0;
10051
+ let diagnostics = [];
10052
+ if (sourceUnavailable.length > 0) {
10053
+ diagnostics = sourceUnavailable;
10054
+ } else if (!passed) {
10055
+ diagnostics = [noAlternativeMatchedDiagnostic(rule)];
10056
+ }
9950
10057
  return {
9951
10058
  ruleId: rule.ruleId,
9952
10059
  status: passed ? "passed" : "failed",
@@ -9954,15 +10061,25 @@ function evaluateCompiledDeclarativeAnyOfRule(rule, document3) {
9954
10061
  diagnostics,
9955
10062
  evaluation: {
9956
10063
  kind: "anyOf",
9957
- ...selectedBranch !== void 0 ? { selectedBranch: branchReferenceFromResult(selectedBranch) } : {},
10064
+ ...passed && selectedBranch !== void 0 ? { selectedBranch: branchReferenceFromResult(selectedBranch) } : {},
9958
10065
  branches
9959
10066
  }
9960
10067
  };
9961
10068
  }
9962
- function evaluateCompiledDeclarativeAllOfRule(rule, document3) {
9963
- const branches = evaluateCompiledDeclarativeBranches(rule.branches, document3);
9964
- const failed = branches.some((branch) => branch.status === "failed");
9965
- const diagnostics = failed ? [groupRequirementFailedDiagnostic(rule)] : [];
10069
+ function evaluateCompiledDeclarativeAllOfRule(rule, document3, runtimeContext = {}) {
10070
+ const branches = evaluateCompiledDeclarativeBranches(
10071
+ rule.branches,
10072
+ document3,
10073
+ runtimeContext
10074
+ );
10075
+ const sourceUnavailable = sourceUnavailableDiagnostics(branches);
10076
+ const failed = sourceUnavailable.length > 0 || branches.some((branch) => branch.status === "failed");
10077
+ let diagnostics = [];
10078
+ if (sourceUnavailable.length > 0) {
10079
+ diagnostics = sourceUnavailable;
10080
+ } else if (failed) {
10081
+ diagnostics = [groupRequirementFailedDiagnostic(rule)];
10082
+ }
9966
10083
  const status = failed ? "failed" : "passed";
9967
10084
  return {
9968
10085
  ruleId: rule.ruleId,
@@ -9975,15 +10092,16 @@ function evaluateCompiledDeclarativeAllOfRule(rule, document3) {
9975
10092
  }
9976
10093
  };
9977
10094
  }
9978
- function evaluateCompiledDeclarativeBranches(branches, document3) {
10095
+ function evaluateCompiledDeclarativeBranches(branches, document3, runtimeContext) {
9979
10096
  return branches.map(
9980
- (branch) => evaluateCompiledDeclarativeBranch(branch, document3)
10097
+ (branch) => evaluateCompiledDeclarativeBranch(branch, document3, runtimeContext)
9981
10098
  );
9982
10099
  }
9983
- function evaluateCompiledDeclarativeBranch(branch, document3) {
10100
+ function evaluateCompiledDeclarativeBranch(branch, document3, runtimeContext) {
9984
10101
  const result = evaluateCompiledDeclarativeRule(
9985
10102
  branch,
9986
- resolveDeclarativeSelector(document3, branch.selector)
10103
+ resolveDeclarativeSelector(document3, branch.selector),
10104
+ runtimeContext
9987
10105
  );
9988
10106
  return {
9989
10107
  branchIndex: branch.branchIndex,
@@ -9992,6 +10110,11 @@ function evaluateCompiledDeclarativeBranch(branch, document3) {
9992
10110
  diagnostics: result.diagnostics
9993
10111
  };
9994
10112
  }
10113
+ function sourceUnavailableDiagnostics(branches) {
10114
+ return branches.flatMap(
10115
+ (branch) => branch.diagnostics.filter(isSourceUnavailableDiagnostic)
10116
+ );
10117
+ }
9995
10118
  function branchReferenceFromResult(branch) {
9996
10119
  return {
9997
10120
  branchIndex: branch.branchIndex,
@@ -9999,6 +10122,77 @@ function branchReferenceFromResult(branch) {
9999
10122
  };
10000
10123
  }
10001
10124
 
10125
+ // src/declarative-validation/profile/syntax-version.ts
10126
+ var PROFILE_SYNTAX_VERSION_V1 = "markdown-engine.validation@v1";
10127
+ var PROFILE_SYNTAX_VERSION_V2 = "markdown-engine.validation@v2";
10128
+ var PROFILE_SYNTAX_VERSION = PROFILE_SYNTAX_VERSION_V1;
10129
+ var SUPPORTED_PROFILE_SYNTAX_VERSIONS = [
10130
+ PROFILE_SYNTAX_VERSION_V1,
10131
+ PROFILE_SYNTAX_VERSION_V2
10132
+ ];
10133
+ function isValidationProfileSyntaxVersion(value) {
10134
+ return SUPPORTED_PROFILE_SYNTAX_VERSIONS.some(
10135
+ (syntaxVersion) => value === syntaxVersion
10136
+ );
10137
+ }
10138
+
10139
+ // src/declarative-validation/diagnostics/profile-config-diagnostics.ts
10140
+ var REGEX_LIKE_PROFILE_KEYS = [
10141
+ "matches",
10142
+ "pattern",
10143
+ "regex",
10144
+ "regexp"
10145
+ ];
10146
+ var UNSAFE_PROFILE_KEYS = [
10147
+ "callback",
10148
+ "eval",
10149
+ "execute",
10150
+ "expression",
10151
+ "function",
10152
+ "import",
10153
+ "imports",
10154
+ "plugin",
10155
+ "script"
10156
+ ];
10157
+ var CONFIG_UNSUPPORTED_KEY_PRECEDENCE = /* @__PURE__ */ new Set([
10158
+ ...REGEX_LIKE_PROFILE_KEYS,
10159
+ ...UNSAFE_PROFILE_KEYS
10160
+ ]);
10161
+ function profileDiagnostic(code3, message) {
10162
+ return { code: code3, message, severity: "error" };
10163
+ }
10164
+ function invalidProfileShape(message) {
10165
+ return profileDiagnostic("profile.config.invalidShape", message);
10166
+ }
10167
+ function unsupportedProfileKey(key) {
10168
+ return profileDiagnostic(
10169
+ "profile.config.unsupportedKey",
10170
+ `Unsupported validation profile key "${key}".`
10171
+ );
10172
+ }
10173
+ function unsupportedSyntaxVersion() {
10174
+ return profileDiagnostic(
10175
+ "profile.config.unsupportedSyntaxVersion",
10176
+ `Profile syntaxVersion must be ${quotedList(SUPPORTED_PROFILE_SYNTAX_VERSIONS)}`
10177
+ );
10178
+ }
10179
+ function unsupportedProfileKeys(record, allowedKeys, diagnostics) {
10180
+ for (const key of Object.keys(record)) {
10181
+ if (!allowedKeys.includes(key)) {
10182
+ diagnostics.push(unsupportedProfileKey(key));
10183
+ }
10184
+ }
10185
+ }
10186
+ function hasConfigUnsupportedKeyPrecedence(key) {
10187
+ return CONFIG_UNSUPPORTED_KEY_PRECEDENCE.has(key);
10188
+ }
10189
+ function quotedList(values) {
10190
+ const quotedValues = values.map((value) => `"${value}"`);
10191
+ const finalValue = quotedValues.at(-1) ?? "";
10192
+ const prefix = quotedValues.slice(0, -1).join(", ");
10193
+ return prefix.length === 0 ? `${finalValue}.` : `${prefix} or ${finalValue}.`;
10194
+ }
10195
+
10002
10196
  // src/declarative-validation/profile/data-closure.ts
10003
10197
  import { types as nodeTypes } from "node:util";
10004
10198
  var DATA_CLOSURE_FAILED = /* @__PURE__ */ Symbol("data-closure-failed");
@@ -10190,79 +10384,6 @@ function safePropertyDescriptor(value, key, fieldName, diagnostics, ruleId) {
10190
10384
 
10191
10385
  // src/declarative-validation/profile/direct-profile-diagnostics.ts
10192
10386
  import { types as nodeTypes2 } from "node:util";
10193
-
10194
- // src/declarative-validation/profile/syntax-version.ts
10195
- var PROFILE_SYNTAX_VERSION_V1 = "markdown-engine.validation@v1";
10196
- var PROFILE_SYNTAX_VERSION_V2 = "markdown-engine.validation@v2";
10197
- var PROFILE_SYNTAX_VERSION = PROFILE_SYNTAX_VERSION_V1;
10198
- var SUPPORTED_PROFILE_SYNTAX_VERSIONS = [
10199
- PROFILE_SYNTAX_VERSION_V1,
10200
- PROFILE_SYNTAX_VERSION_V2
10201
- ];
10202
- function isValidationProfileSyntaxVersion(value) {
10203
- return SUPPORTED_PROFILE_SYNTAX_VERSIONS.some(
10204
- (syntaxVersion) => value === syntaxVersion
10205
- );
10206
- }
10207
-
10208
- // src/declarative-validation/diagnostics/profile-config-diagnostics.ts
10209
- var REGEX_LIKE_PROFILE_KEYS = [
10210
- "matches",
10211
- "pattern",
10212
- "regex",
10213
- "regexp"
10214
- ];
10215
- var UNSAFE_PROFILE_KEYS = [
10216
- "callback",
10217
- "eval",
10218
- "execute",
10219
- "expression",
10220
- "function",
10221
- "import",
10222
- "imports",
10223
- "plugin",
10224
- "script"
10225
- ];
10226
- var CONFIG_UNSUPPORTED_KEY_PRECEDENCE = /* @__PURE__ */ new Set([
10227
- ...REGEX_LIKE_PROFILE_KEYS,
10228
- ...UNSAFE_PROFILE_KEYS
10229
- ]);
10230
- function profileDiagnostic(code3, message) {
10231
- return { code: code3, message, severity: "error" };
10232
- }
10233
- function invalidProfileShape(message) {
10234
- return profileDiagnostic("profile.config.invalidShape", message);
10235
- }
10236
- function unsupportedProfileKey(key) {
10237
- return profileDiagnostic(
10238
- "profile.config.unsupportedKey",
10239
- `Unsupported validation profile key "${key}".`
10240
- );
10241
- }
10242
- function unsupportedSyntaxVersion() {
10243
- return profileDiagnostic(
10244
- "profile.config.unsupportedSyntaxVersion",
10245
- `Profile syntaxVersion must be ${quotedList(SUPPORTED_PROFILE_SYNTAX_VERSIONS)}`
10246
- );
10247
- }
10248
- function unsupportedProfileKeys(record, allowedKeys, diagnostics) {
10249
- for (const key of Object.keys(record)) {
10250
- if (!allowedKeys.includes(key)) {
10251
- diagnostics.push(unsupportedProfileKey(key));
10252
- }
10253
- }
10254
- }
10255
- function hasConfigUnsupportedKeyPrecedence(key) {
10256
- return CONFIG_UNSUPPORTED_KEY_PRECEDENCE.has(key);
10257
- }
10258
- function quotedList(values) {
10259
- const quotedValues = values.map((value) => `"${value}"`);
10260
- const finalValue = quotedValues.at(-1) ?? "";
10261
- const prefix = quotedValues.slice(0, -1).join(", ");
10262
- return prefix.length === 0 ? `${finalValue}.` : `${prefix} or ${finalValue}.`;
10263
- }
10264
-
10265
- // src/declarative-validation/profile/direct-profile-diagnostics.ts
10266
10387
  var PROFILE_KEYS = ["syntaxVersion", "documentVersion", "rules"];
10267
10388
  var RULE_KEYS_V1 = ["id", "severity", "select", "assert"];
10268
10389
  var RULE_KEYS_V2 = [...RULE_KEYS_V1, "when", "anyOf", "allOf"];
@@ -10873,38 +10994,6 @@ function pushTextOccurrenceCountDiagnostic(value, ruleId, diagnostics) {
10873
10994
  "textOccurrenceCount.count must be a number."
10874
10995
  );
10875
10996
  }
10876
- function pushTextLengthShapeDiagnostics(assertion, ruleId, diagnostics) {
10877
- let valid = true;
10878
- const min = assertion?.min;
10879
- const max = assertion?.max;
10880
- if (min !== void 0 && !pushTextLengthNumberDiagnostic(
10881
- "textLength.min",
10882
- min,
10883
- ruleId,
10884
- diagnostics
10885
- )) {
10886
- valid = false;
10887
- }
10888
- if (max !== void 0 && !pushTextLengthNumberDiagnostic(
10889
- "textLength.max",
10890
- max,
10891
- ruleId,
10892
- diagnostics
10893
- )) {
10894
- valid = false;
10895
- }
10896
- if (valid && min !== void 0 && max !== void 0 && min > max) {
10897
- diagnostics.push(
10898
- compileDiagnostic(
10899
- "profile.config.invalidShape",
10900
- "textLength.min must be less than or equal to textLength.max.",
10901
- ruleId
10902
- )
10903
- );
10904
- valid = false;
10905
- }
10906
- return valid;
10907
- }
10908
10997
  function pushIdsCountShapeDiagnostics(assertion, ruleId, diagnostics) {
10909
10998
  let valid = true;
10910
10999
  const minCount = assertion?.minCount;
@@ -11125,9 +11214,6 @@ function pushNonEmptyStringDiagnostic(fieldName, value, ruleId, diagnostics) {
11125
11214
  );
11126
11215
  return false;
11127
11216
  }
11128
- function pushTextLengthNumberDiagnostic(fieldName, value, ruleId, diagnostics) {
11129
- return pushNonNegativeIntegerDiagnostic(fieldName, value, ruleId, diagnostics);
11130
- }
11131
11217
  function pushNonNegativeIntegerDiagnostic(fieldName, value, ruleId, diagnostics) {
11132
11218
  if (typeof value !== "number" || !Number.isFinite(value)) {
11133
11219
  diagnostics.push(
@@ -11190,9 +11276,6 @@ function optionalNumber2(key, value) {
11190
11276
  function hasTextPredicate(assertion) {
11191
11277
  return assertion?.contains !== void 0 || assertion?.excludes !== void 0 && assertion.excludes.length > 0;
11192
11278
  }
11193
- function hasTextLengthBound(assertion) {
11194
- return assertion?.min !== void 0 || assertion?.max !== void 0;
11195
- }
11196
11279
 
11197
11280
  // src/declarative-validation/profile/ids-assertion-contract.ts
11198
11281
  var IDS_COUNT_BOUND_KEYS = ["minCount", "maxCount"];
@@ -11225,11 +11308,13 @@ function hasValidIdsCountRange(ids) {
11225
11308
  function selectorAssertionCompatibilityError(assertionName, selector) {
11226
11309
  switch (assertionName) {
11227
11310
  case "exists":
11311
+ case "selectionCount":
11228
11312
  return void 0;
11229
11313
  case "sectionsRequired":
11230
11314
  case "references":
11231
11315
  case "tableColumnCoverage":
11232
11316
  case "frontmatterShape":
11317
+ case "sourceLength":
11233
11318
  return selector.target === "document" ? void 0 : selectorCompatibilityMessage(assertionName, "document");
11234
11319
  case "tableColumnsRequired":
11235
11320
  return selector.target === "table" ? void 0 : selectorCompatibilityMessage(assertionName, "table");
@@ -11243,10 +11328,116 @@ function selectorAssertionCompatibilityError(assertionName, selector) {
11243
11328
  return selector.target === "document" ? void 0 : selectorCompatibilityMessage(assertionName, "document");
11244
11329
  }
11245
11330
  }
11331
+ function pushCompatibilityDiagnostic(assertionName, selector, ruleId, diagnostics) {
11332
+ const message = selectorAssertionCompatibilityError(assertionName, selector);
11333
+ if (message === void 0) {
11334
+ return true;
11335
+ }
11336
+ diagnostics.push(
11337
+ compileDiagnostic(
11338
+ "profile.compile.incompatibleSelectorAssertion",
11339
+ message,
11340
+ ruleId
11341
+ )
11342
+ );
11343
+ return false;
11344
+ }
11246
11345
  function selectorCompatibilityMessage(assertionName, selectorName) {
11247
11346
  return `Assertion "${assertionName}" is compatible only with ${selectorName} selectors.`;
11248
11347
  }
11249
11348
 
11349
+ // src/declarative-validation/compiler/length-assertion-builders.ts
11350
+ function buildSelectionCountAssertion(assertion, selector, ruleId, syntaxVersion, diagnostics) {
11351
+ const bounds = assertion.selectionCount;
11352
+ return bounds === void 0 || syntaxVersion !== PROFILE_SYNTAX_VERSION_V2 ? void 0 : buildLengthAssertion(
11353
+ "selectionCount",
11354
+ bounds,
11355
+ selector,
11356
+ ruleId,
11357
+ diagnostics
11358
+ );
11359
+ }
11360
+ function buildTextLengthAssertion(assertion, selector, ruleId, _syntaxVersion, diagnostics) {
11361
+ const bounds = assertion.textLength;
11362
+ return bounds === void 0 ? void 0 : buildLengthAssertion("textLength", bounds, selector, ruleId, diagnostics);
11363
+ }
11364
+ function buildSourceLengthAssertion(assertion, selector, ruleId, syntaxVersion, diagnostics) {
11365
+ const bounds = assertion.sourceLength;
11366
+ return bounds === void 0 || syntaxVersion !== PROFILE_SYNTAX_VERSION_V2 ? void 0 : buildLengthAssertion(
11367
+ "sourceLength",
11368
+ bounds,
11369
+ selector,
11370
+ ruleId,
11371
+ diagnostics
11372
+ );
11373
+ }
11374
+ function buildLengthAssertion(assertionName, bounds, selector, ruleId, diagnostics) {
11375
+ if (!pushObjectDiagnostic(assertionName, bounds, ruleId, diagnostics) || !pushUnsupportedKeyDiagnostics(bounds, ["min", "max"], diagnostics) || !pushLengthBoundShapeDiagnostics(
11376
+ assertionName,
11377
+ bounds,
11378
+ ruleId,
11379
+ diagnostics
11380
+ )) {
11381
+ return void 0;
11382
+ }
11383
+ if (!hasLengthBound(bounds)) {
11384
+ diagnostics.push(
11385
+ compileDiagnostic(
11386
+ "profile.config.invalidShape",
11387
+ `${assertionName} must include min, max, or both.`,
11388
+ ruleId
11389
+ )
11390
+ );
11391
+ return void 0;
11392
+ }
11393
+ if (!pushCompatibilityDiagnostic(
11394
+ assertionName,
11395
+ selector,
11396
+ ruleId,
11397
+ diagnostics
11398
+ )) {
11399
+ return void 0;
11400
+ }
11401
+ return {
11402
+ kind: assertionName,
11403
+ ...optionalNumber2("min", bounds.min),
11404
+ ...optionalNumber2("max", bounds.max)
11405
+ };
11406
+ }
11407
+ function pushLengthBoundShapeDiagnostics(assertionName, bounds, ruleId, diagnostics) {
11408
+ let valid = true;
11409
+ if (bounds.min !== void 0 && !pushNonNegativeIntegerDiagnostic(
11410
+ `${assertionName}.min`,
11411
+ bounds.min,
11412
+ ruleId,
11413
+ diagnostics
11414
+ )) {
11415
+ valid = false;
11416
+ }
11417
+ if (bounds.max !== void 0 && !pushNonNegativeIntegerDiagnostic(
11418
+ `${assertionName}.max`,
11419
+ bounds.max,
11420
+ ruleId,
11421
+ diagnostics
11422
+ )) {
11423
+ valid = false;
11424
+ }
11425
+ if (valid && bounds.min !== void 0 && bounds.max !== void 0 && bounds.min > bounds.max) {
11426
+ diagnostics.push(
11427
+ compileDiagnostic(
11428
+ "profile.config.invalidShape",
11429
+ `${assertionName}.min must be less than or equal to ${assertionName}.max.`,
11430
+ ruleId
11431
+ )
11432
+ );
11433
+ valid = false;
11434
+ }
11435
+ return valid;
11436
+ }
11437
+ function hasLengthBound(bounds) {
11438
+ return bounds.min !== void 0 || bounds.max !== void 0;
11439
+ }
11440
+
11250
11441
  // src/declarative-validation/compiler/assertion-builders.ts
11251
11442
  var ASSERTION_BUILDERS = [
11252
11443
  buildExistsAssertion,
@@ -11258,7 +11449,9 @@ var ASSERTION_BUILDERS = [
11258
11449
  buildFrontmatterShapeAssertion,
11259
11450
  buildTextAssertion,
11260
11451
  buildTextOccurrenceCountAssertion,
11452
+ buildSelectionCountAssertion,
11261
11453
  buildTextLengthAssertion,
11454
+ buildSourceLengthAssertion,
11262
11455
  buildTextFormatAssertion,
11263
11456
  buildFrontmatterRequiredAssertion
11264
11457
  ];
@@ -11577,32 +11770,6 @@ function buildTextOccurrenceCountAssertion(assertion, selector, ruleId, _syntaxV
11577
11770
  }
11578
11771
  return void 0;
11579
11772
  }
11580
- function buildTextLengthAssertion(assertion, selector, ruleId, _syntaxVersion, diagnostics) {
11581
- if (assertion.textLength === void 0) {
11582
- return void 0;
11583
- }
11584
- if (!pushObjectDiagnostic("textLength", assertion.textLength, ruleId, diagnostics) || !pushUnsupportedKeyDiagnostics(assertion.textLength, ["min", "max"], diagnostics) || !pushTextLengthShapeDiagnostics(assertion.textLength, ruleId, diagnostics)) {
11585
- return void 0;
11586
- }
11587
- if (!hasTextLengthBound(assertion.textLength)) {
11588
- diagnostics.push(
11589
- compileDiagnostic(
11590
- "profile.config.invalidShape",
11591
- "textLength must include min, max, or both.",
11592
- ruleId
11593
- )
11594
- );
11595
- return void 0;
11596
- }
11597
- if (pushCompatibilityDiagnostic("textLength", selector, ruleId, diagnostics)) {
11598
- return {
11599
- kind: "textLength",
11600
- ...optionalNumber2("min", assertion.textLength.min),
11601
- ...optionalNumber2("max", assertion.textLength.max)
11602
- };
11603
- }
11604
- return void 0;
11605
- }
11606
11773
  function buildTextFormatAssertion(assertion, selector, ruleId, syntaxVersion, diagnostics) {
11607
11774
  if (assertion.textFormat === void 0 || syntaxVersion !== PROFILE_SYNTAX_VERSION_V2) {
11608
11775
  return void 0;
@@ -11650,20 +11817,6 @@ function buildFrontmatterRequiredAssertion(assertion, selector, ruleId, _syntaxV
11650
11817
  }
11651
11818
  return void 0;
11652
11819
  }
11653
- function pushCompatibilityDiagnostic(assertionName, selector, ruleId, diagnostics) {
11654
- const message = selectorAssertionCompatibilityError(assertionName, selector);
11655
- if (message !== void 0) {
11656
- diagnostics.push(
11657
- compileDiagnostic(
11658
- "profile.compile.incompatibleSelectorAssertion",
11659
- message,
11660
- ruleId
11661
- )
11662
- );
11663
- return false;
11664
- }
11665
- return true;
11666
- }
11667
11820
 
11668
11821
  // src/declarative-validation/compiler/assertions.ts
11669
11822
  var ASSERTION_KEYS_V1 = [
@@ -11679,6 +11832,8 @@ var ASSERTION_KEYS_V1 = [
11679
11832
  ];
11680
11833
  var ASSERTION_KEYS_V2 = [
11681
11834
  ...ASSERTION_KEYS_V1,
11835
+ "selectionCount",
11836
+ "sourceLength",
11682
11837
  "tableColumnCoverage",
11683
11838
  "frontmatterShape",
11684
11839
  "textFormat"
@@ -11941,6 +12096,12 @@ function compileValidationProfile(profile) {
11941
12096
  ]
11942
12097
  };
11943
12098
  }
12099
+ const syntaxVersion = closedProfile.syntaxVersion;
12100
+ if (!isValidationProfileSyntaxVersion(syntaxVersion)) {
12101
+ return {
12102
+ diagnostics: [...diagnostics, unsupportedSyntaxVersion()]
12103
+ };
12104
+ }
11944
12105
  const profileRules = profileRulesFromValue(closedProfile.rules, diagnostics);
11945
12106
  if (profileRules === void 0) {
11946
12107
  return { diagnostics };
@@ -11975,7 +12136,7 @@ function compileValidationProfile(profile) {
11975
12136
  index2,
11976
12137
  ruleId,
11977
12138
  severity ?? "error",
11978
- profile.syntaxVersion,
12139
+ syntaxVersion,
11979
12140
  diagnostics
11980
12141
  );
11981
12142
  if (compiledRule !== void 0) {
@@ -11983,7 +12144,7 @@ function compileValidationProfile(profile) {
11983
12144
  }
11984
12145
  }
11985
12146
  return diagnostics.length > 0 ? { diagnostics } : {
11986
- plan: compiledPlanFromRules(profile.syntaxVersion, rules),
12147
+ plan: compiledPlanFromRules(syntaxVersion, rules),
11987
12148
  diagnostics
11988
12149
  };
11989
12150
  }
@@ -12363,6 +12524,70 @@ var YAML_MATERIALIZE_OPTIONS = {
12363
12524
  maxAliasCount: 50
12364
12525
  };
12365
12526
 
12527
+ // src/declarative-validation/profile/length-bound-schema.ts
12528
+ function lengthBoundsFromValue(value, assertionName, diagnostics) {
12529
+ if (value === void 0) {
12530
+ return void 0;
12531
+ }
12532
+ if (!isPlainRecord(value)) {
12533
+ diagnostics.push(invalidShape(`${assertionName} must be an object.`));
12534
+ return void 0;
12535
+ }
12536
+ unsupportedKeys(value, ["min", "max"], diagnostics);
12537
+ const diagnosticCountBeforeBounds = diagnostics.length;
12538
+ const bounds = {
12539
+ ...optionalLengthBound(value, assertionName, "min", diagnostics),
12540
+ ...optionalLengthBound(value, assertionName, "max", diagnostics)
12541
+ };
12542
+ if (!hasLengthBound2(bounds)) {
12543
+ if (diagnostics.length === diagnosticCountBeforeBounds) {
12544
+ diagnostics.push(
12545
+ invalidShape(`${assertionName} must include min, max, or both.`)
12546
+ );
12547
+ }
12548
+ return void 0;
12549
+ }
12550
+ if (!hasValidLengthRange(bounds)) {
12551
+ diagnostics.push(
12552
+ invalidShape(
12553
+ `${assertionName}.min must be less than or equal to ${assertionName}.max.`
12554
+ )
12555
+ );
12556
+ return void 0;
12557
+ }
12558
+ return bounds;
12559
+ }
12560
+ function optionalLengthBound(record, assertionName, key, diagnostics) {
12561
+ const value = record[key];
12562
+ if (value === void 0) {
12563
+ return {};
12564
+ }
12565
+ if (!isFiniteNumber(value)) {
12566
+ diagnostics.push(
12567
+ invalidShape(`${assertionName}.${key} must be a number when provided.`)
12568
+ );
12569
+ return {};
12570
+ }
12571
+ if (!isNonNegativeInteger(value)) {
12572
+ diagnostics.push(
12573
+ invalidShape(
12574
+ `${assertionName}.${key} must be a non-negative integer when provided.`
12575
+ )
12576
+ );
12577
+ return {};
12578
+ }
12579
+ return { [key]: value };
12580
+ }
12581
+ function hasLengthBound2(bounds) {
12582
+ return bounds.min !== void 0 || bounds.max !== void 0;
12583
+ }
12584
+ function hasValidLengthRange(bounds) {
12585
+ return bounds.min === void 0 || bounds.max === void 0 || bounds.min <= bounds.max;
12586
+ }
12587
+ function isNonNegativeInteger(value) {
12588
+ return Number.isInteger(value) && value >= 0;
12589
+ }
12590
+
12366
12591
  // src/declarative-validation/profile/assertion-schema.ts
12367
12592
  var SUPPORTED_ASSERTION_KEYS_V1 = [
12368
12593
  "exists",
@@ -12377,6 +12602,8 @@ var SUPPORTED_ASSERTION_KEYS_V1 = [
12377
12602
  ];
12378
12603
  var SUPPORTED_ASSERTION_KEYS_V2 = [
12379
12604
  ...SUPPORTED_ASSERTION_KEYS_V1,
12605
+ "selectionCount",
12606
+ "sourceLength",
12380
12607
  "tableColumnCoverage",
12381
12608
  "frontmatterShape",
12382
12609
  "textFormat"
@@ -12400,6 +12627,8 @@ function assertionFromValue(value, syntaxVersion, diagnostics) {
12400
12627
  ...textAssertionFromValue(value.text, diagnostics),
12401
12628
  ...textOccurrenceCountFromValue(value.textOccurrenceCount, diagnostics),
12402
12629
  ...textLengthFromValue(value.textLength, diagnostics),
12630
+ ...supportsV2AssertionSurface(syntaxVersion) ? selectionCountFromValue(value.selectionCount, diagnostics) : {},
12631
+ ...supportsV2AssertionSurface(syntaxVersion) ? sourceLengthFromValue(value.sourceLength, diagnostics) : {},
12403
12632
  ...frontmatterRequiredFromValue(value.frontmatterRequired, diagnostics),
12404
12633
  ...supportsV2AssertionSurface(syntaxVersion) ? tableColumnCoverageFromValue(value.tableColumnCoverage, diagnostics) : {},
12405
12634
  ...supportsV2AssertionSurface(syntaxVersion) ? frontmatterShapeFromValue2(value.frontmatterShape, diagnostics) : {},
@@ -12743,34 +12972,16 @@ function textOccurrenceCountFromValue(value, diagnostics) {
12743
12972
  };
12744
12973
  }
12745
12974
  function textLengthFromValue(value, diagnostics) {
12746
- if (value === void 0) {
12747
- return {};
12748
- }
12749
- if (!isPlainRecord(value)) {
12750
- diagnostics.push(invalidShape("textLength must be an object."));
12751
- return {};
12752
- }
12753
- unsupportedKeys(value, ["min", "max"], diagnostics);
12754
- const diagnosticCountBeforeBounds = diagnostics.length;
12755
- const textLength = {
12756
- ...optionalTextLengthBound(value, "min", diagnostics),
12757
- ...optionalTextLengthBound(value, "max", diagnostics)
12758
- };
12759
- if (!hasTextLengthBound2(textLength)) {
12760
- if (diagnostics.length === diagnosticCountBeforeBounds) {
12761
- diagnostics.push(
12762
- invalidShape("textLength must include min, max, or both.")
12763
- );
12764
- }
12765
- return {};
12766
- }
12767
- if (!hasValidTextLengthRange(textLength)) {
12768
- diagnostics.push(
12769
- invalidShape("textLength.min must be less than or equal to textLength.max.")
12770
- );
12771
- return {};
12772
- }
12773
- return { textLength };
12975
+ const bounds = lengthBoundsFromValue(value, "textLength", diagnostics);
12976
+ return bounds === void 0 ? {} : { textLength: bounds };
12977
+ }
12978
+ function selectionCountFromValue(value, diagnostics) {
12979
+ const bounds = lengthBoundsFromValue(value, "selectionCount", diagnostics);
12980
+ return bounds === void 0 ? {} : { selectionCount: bounds };
12981
+ }
12982
+ function sourceLengthFromValue(value, diagnostics) {
12983
+ const bounds = lengthBoundsFromValue(value, "sourceLength", diagnostics);
12984
+ return bounds === void 0 ? {} : { sourceLength: bounds };
12774
12985
  }
12775
12986
  function textFormatFromValue(value, diagnostics) {
12776
12987
  if (value === void 0) {
@@ -12848,27 +13059,6 @@ function optionalBoolean2(record, key, diagnostics) {
12848
13059
  (field) => `${field} must be a boolean when provided.`
12849
13060
  );
12850
13061
  }
12851
- function optionalTextLengthBound(record, key, diagnostics) {
12852
- const value = record[key];
12853
- if (value === void 0) {
12854
- return {};
12855
- }
12856
- if (!isFiniteNumber(value)) {
12857
- diagnostics.push(
12858
- invalidShape(`textLength.${key} must be a number when provided.`)
12859
- );
12860
- return {};
12861
- }
12862
- if (!isTextLengthBound(value)) {
12863
- diagnostics.push(
12864
- invalidShape(
12865
- `textLength.${key} must be a non-negative integer when provided.`
12866
- )
12867
- );
12868
- return {};
12869
- }
12870
- return { [key]: value };
12871
- }
12872
13062
  function optionalIdCountBound(record, key, diagnostics) {
12873
13063
  const value = record[key];
12874
13064
  if (value === void 0) {
@@ -12878,7 +13068,7 @@ function optionalIdCountBound(record, key, diagnostics) {
12878
13068
  diagnostics.push(invalidShape(`ids.${key} must be a number when provided.`));
12879
13069
  return {};
12880
13070
  }
12881
- if (!isNonNegativeInteger(value)) {
13071
+ if (!isNonNegativeInteger2(value)) {
12882
13072
  diagnostics.push(
12883
13073
  invalidShape(`ids.${key} must be a non-negative integer when provided.`)
12884
13074
  );
@@ -12897,16 +13087,7 @@ function requiredAssertionString(value, field, diagnostics) {
12897
13087
  function hasTextPredicate2(text5) {
12898
13088
  return text5?.contains !== void 0 || text5?.excludes !== void 0;
12899
13089
  }
12900
- function hasTextLengthBound2(textLength) {
12901
- return textLength?.min !== void 0 || textLength?.max !== void 0;
12902
- }
12903
- function hasValidTextLengthRange(textLength) {
12904
- return textLength?.min === void 0 || textLength.max === void 0 || textLength.min <= textLength.max;
12905
- }
12906
- function isTextLengthBound(value) {
12907
- return isNonNegativeInteger(value);
12908
- }
12909
- function isNonNegativeInteger(value) {
13090
+ function isNonNegativeInteger2(value) {
12910
13091
  return Number.isInteger(value) && value >= 0;
12911
13092
  }
12912
13093
 
@@ -13419,7 +13600,7 @@ function cloneSourceRange2(sourceRange) {
13419
13600
  import { createHash } from "node:crypto";
13420
13601
 
13421
13602
  // src/internal/package-version.ts
13422
- var MARKDOWN_ENGINE_PACKAGE_VERSION = "3.1.1";
13603
+ var MARKDOWN_ENGINE_PACKAGE_VERSION = "3.3.0";
13423
13604
 
13424
13605
  // src/internal/stable-json.ts
13425
13606
  function normalizeStableJsonValue(value) {
@@ -13555,16 +13736,37 @@ function passedFromStatus(status) {
13555
13736
  }
13556
13737
 
13557
13738
  // src/declarative-validation/evidence/index.ts
13558
- function createDeclarativeValidationEvidence(document3, profile, ruleResults, diagnostics) {
13739
+ function createDeclarativeValidationEvidence(document3, profile, ruleResults, diagnostics, sourceText) {
13740
+ const sourceLength = sourceText !== void 0 && profileUsesSourceLength(profile) ? sourceText.length : void 0;
13559
13741
  return {
13560
- inputHash: sha256(stringifyStableJson(documentWithoutPath(document3))),
13742
+ inputHash: sha256(
13743
+ stringifyStableJson(canonicalInput(document3, sourceLength))
13744
+ ),
13561
13745
  profileHash: sha256(stringifyStableJson(resolvedProfile(profile, document3))),
13562
13746
  engineVersion: MARKDOWN_ENGINE_PACKAGE_VERSION,
13563
13747
  runtimeVersion: process.version,
13748
+ ...sourceLength !== void 0 ? { sourceLength } : {},
13564
13749
  ruleResults: cloneRuleResults(ruleResults),
13565
13750
  diagnostics: cloneDiagnostics(diagnostics)
13566
13751
  };
13567
13752
  }
13753
+ function canonicalInput(document3, sourceLength) {
13754
+ const normalizedDocument = documentWithoutPath(document3);
13755
+ return sourceLength === void 0 ? normalizedDocument : { document: normalizedDocument, sourceLength };
13756
+ }
13757
+ function profileUsesSourceLength(profile) {
13758
+ return profile.rules.some(ruleUsesSourceLength);
13759
+ }
13760
+ function ruleUsesSourceLength(rule) {
13761
+ if (rule.when?.assert.sourceLength !== void 0) {
13762
+ return true;
13763
+ }
13764
+ if ("assert" in rule) {
13765
+ return rule.assert.sourceLength !== void 0;
13766
+ }
13767
+ const branches = "anyOf" in rule ? rule.anyOf : rule.allOf;
13768
+ return branches.some((branch) => branch.assert.sourceLength !== void 0);
13769
+ }
13568
13770
  function resolvedProfile(profile, document3) {
13569
13771
  return {
13570
13772
  syntaxVersion: profile.syntaxVersion,
@@ -13646,7 +13848,8 @@ function withEvidence(result, document3, profile, options) {
13646
13848
  document3,
13647
13849
  profile,
13648
13850
  result.ruleResults,
13649
- result.diagnostics
13851
+ result.diagnostics,
13852
+ options.sourceText
13650
13853
  )
13651
13854
  };
13652
13855
  }
@@ -13712,8 +13915,11 @@ function validateWithProfile(document3, profile, options = {}) {
13712
13915
  }
13713
13916
  const compileResult = compileValidationProfile(materializedProfile.profile);
13714
13917
  const compiledRules = compileResult.plan?.rules ?? [];
13918
+ const runtimeContext = options.sourceText === void 0 ? {} : { sourceText: options.sourceText };
13715
13919
  const ruleResults = sortValidationRuleResults(
13716
- compiledRules.flatMap((rule) => evaluateApplicableCompiledRule(document3, rule))
13920
+ compiledRules.flatMap(
13921
+ (rule) => evaluateApplicableCompiledRule(document3, rule, runtimeContext)
13922
+ )
13717
13923
  );
13718
13924
  const diagnostics = [
13719
13925
  ...compileResult.diagnostics,
@@ -13727,32 +13933,56 @@ function validateWithProfile(document3, profile, options = {}) {
13727
13933
  options
13728
13934
  });
13729
13935
  }
13730
- function evaluateApplicableCompiledRule(document3, rule) {
13936
+ function evaluateApplicableCompiledRule(document3, rule, runtimeContext) {
13731
13937
  const applicability = classifyCompiledDeclarativeRuleApplicability(
13732
13938
  rule,
13733
- document3
13939
+ document3,
13940
+ runtimeContext
13734
13941
  );
13735
- return applicability.status === "notMatched" ? [
13736
- createSkippedDeclarativeValidationRuleResult({
13737
- ruleId: rule.ruleId,
13738
- when: applicability.result
13739
- })
13740
- ] : evaluateCompiledRule(document3, rule);
13942
+ if (applicability.status === "notMatched") {
13943
+ if (applicability.result.diagnostics.some(isSourceUnavailableDiagnostic)) {
13944
+ return [sourceUnavailableApplicabilityResult(rule, applicability.result)];
13945
+ }
13946
+ return [
13947
+ createSkippedDeclarativeValidationRuleResult({
13948
+ ruleId: rule.ruleId,
13949
+ when: applicability.result
13950
+ })
13951
+ ];
13952
+ }
13953
+ return evaluateCompiledRule(document3, rule, runtimeContext);
13741
13954
  }
13742
- function evaluateCompiledRule(document3, rule) {
13955
+ function evaluateCompiledRule(document3, rule, runtimeContext) {
13743
13956
  if (isCompiledAnyOfRule(rule)) {
13744
- return [evaluateCompiledDeclarativeAnyOfRule(rule, document3)];
13957
+ return [evaluateCompiledDeclarativeAnyOfRule(rule, document3, runtimeContext)];
13745
13958
  }
13746
13959
  if (isCompiledAllOfRule(rule)) {
13747
- return [evaluateCompiledDeclarativeAllOfRule(rule, document3)];
13960
+ return [evaluateCompiledDeclarativeAllOfRule(rule, document3, runtimeContext)];
13748
13961
  }
13749
13962
  return [
13750
13963
  evaluateCompiledDeclarativeRule(
13751
13964
  rule,
13752
- resolveDeclarativeSelector(document3, rule.selector)
13965
+ resolveDeclarativeSelector(document3, rule.selector),
13966
+ runtimeContext
13753
13967
  )
13754
13968
  ];
13755
13969
  }
13970
+ function sourceUnavailableApplicabilityResult(rule, when) {
13971
+ const diagnostics = when.diagnostics.filter(
13972
+ isSourceUnavailableDiagnostic
13973
+ );
13974
+ return {
13975
+ ruleId: rule.ruleId,
13976
+ status: "failed",
13977
+ passed: false,
13978
+ diagnostics,
13979
+ when,
13980
+ evaluation: {
13981
+ kind: "assertions",
13982
+ diagnostics
13983
+ }
13984
+ };
13985
+ }
13756
13986
  function isCompiledAnyOfRule(rule) {
13757
13987
  return "kind" in rule && rule.kind === "anyOf";
13758
13988
  }
@@ -27212,6 +27442,7 @@ async function runDeclarativeValidationCli(input) {
27212
27442
  documentDiagnosticsResult(
27213
27443
  normalizeResult.document,
27214
27444
  profileResult.profile,
27445
+ markdown.content,
27215
27446
  [
27216
27447
  ...documentDiagnostics,
27217
27448
  ...documentVersionDiagnostics(
@@ -27226,7 +27457,7 @@ async function runDeclarativeValidationCli(input) {
27226
27457
  const validationResult = validateWithProfile(
27227
27458
  normalizeResult.document,
27228
27459
  profileResult.profile,
27229
- { includeEvidence: true }
27460
+ { includeEvidence: true, sourceText: markdown.content }
27230
27461
  );
27231
27462
  const result = mergeDocumentDiagnostics(
27232
27463
  validationResult,
@@ -27258,13 +27489,13 @@ function profileStageResult(diagnostics) {
27258
27489
  ruleResults: []
27259
27490
  };
27260
27491
  }
27261
- function documentDiagnosticsResult(document3, profile, diagnostics) {
27492
+ function documentDiagnosticsResult(document3, profile, sourceText, diagnostics) {
27262
27493
  return createDeclarativeValidationResult({
27263
27494
  document: document3,
27264
27495
  profile,
27265
27496
  ruleResults: [],
27266
27497
  diagnostics,
27267
- options: { includeEvidence: true }
27498
+ options: { includeEvidence: true, sourceText }
27268
27499
  });
27269
27500
  }
27270
27501
  function mergeDocumentDiagnostics(validationResult, documentDiagnostics) {