@jasonbelmonti/markdown-engine 3.6.0 → 3.8.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 +19 -0
- package/README.md +40 -11
- package/dist/cli/declarative-validation.d.ts +3 -9
- package/dist/cli/declarative-validation.d.ts.map +1 -1
- package/dist/cli/declarative-validation.js +6 -16
- package/dist/cli/declarative-validation.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +2 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/validate-args.d.ts +3 -1
- package/dist/cli/validate-args.d.ts.map +1 -1
- package/dist/cli/validate-args.js +45 -92
- package/dist/cli/validate-args.js.map +1 -1
- package/dist/cli/validation-output.d.ts +16 -0
- package/dist/cli/validation-output.d.ts.map +1 -0
- package/dist/cli/validation-output.js +26 -0
- package/dist/cli/validation-output.js.map +1 -0
- package/dist/cli/validation-report.d.ts +8 -0
- package/dist/cli/validation-report.d.ts.map +1 -0
- package/dist/cli/validation-report.js +24 -0
- package/dist/cli/validation-report.js.map +1 -0
- package/dist/cli/validation-summary.d.ts +47 -0
- package/dist/cli/validation-summary.d.ts.map +1 -0
- package/dist/cli/validation-summary.js +55 -0
- package/dist/cli/validation-summary.js.map +1 -0
- 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/table-rows-complete.d.ts +4 -0
- package/dist/declarative-validation/assertions/table-rows-complete.d.ts.map +1 -0
- package/dist/declarative-validation/assertions/table-rows-complete.js +40 -0
- package/dist/declarative-validation/assertions/table-rows-complete.js.map +1 -0
- package/dist/declarative-validation/compiler/assertion-builders.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/assertion-builders.js +2 -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 +2 -0
- package/dist/declarative-validation/compiler/plan.d.ts.map +1 -1
- package/dist/declarative-validation/compiler/table-rows-complete.d.ts +3 -0
- package/dist/declarative-validation/compiler/table-rows-complete.d.ts.map +1 -0
- package/dist/declarative-validation/compiler/table-rows-complete.js +17 -0
- package/dist/declarative-validation/compiler/table-rows-complete.js.map +1 -0
- package/dist/declarative-validation/profile/assertion-schema.d.ts.map +1 -1
- package/dist/declarative-validation/profile/assertion-schema.js +14 -0
- package/dist/declarative-validation/profile/assertion-schema.js.map +1 -1
- package/dist/declarative-validation/profile/index.d.ts +1 -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 +266 -149
- package/docs/contracts/declarative-validation.md +123 -7
- package/fixtures/declarative-validation/examples/table-rows-complete/README.md +65 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/blockquote.md +3 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/complete.md +3 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/consumer-missing.md +50 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/consumer-repaired.md +50 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/excess.md +3 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/explicit-empty.md +3 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/header-only.md +2 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/legacy.yaml +10 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/missing.md +3 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/multiple.md +5 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/oracle.json +85 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/profile.yaml +11 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/shape.yaml +8 -0
- package/fixtures/declarative-validation/examples/table-rows-complete/syntax.md +3 -0
- package/package.json +2 -2
- package/scripts/install-markdown-engine-cli.sh +2 -2
|
@@ -7531,14 +7531,14 @@ function lists(document3, query = {}) {
|
|
|
7531
7531
|
});
|
|
7532
7532
|
}
|
|
7533
7533
|
function links(document3, query = {}) {
|
|
7534
|
-
return (document3.links ?? []).filter((
|
|
7535
|
-
if (query.targetId !== void 0 &&
|
|
7534
|
+
return (document3.links ?? []).filter((link3) => {
|
|
7535
|
+
if (query.targetId !== void 0 && link3.target.id !== query.targetId) {
|
|
7536
7536
|
return false;
|
|
7537
7537
|
}
|
|
7538
|
-
if (query.url !== void 0 &&
|
|
7538
|
+
if (query.url !== void 0 && link3.url !== query.url) {
|
|
7539
7539
|
return false;
|
|
7540
7540
|
}
|
|
7541
|
-
return query.text === void 0 ||
|
|
7541
|
+
return query.text === void 0 || link3.text === query.text;
|
|
7542
7542
|
});
|
|
7543
7543
|
}
|
|
7544
7544
|
function linkReferences(document3, query = {}) {
|
|
@@ -9003,11 +9003,11 @@ function linkTargets(document3, selector) {
|
|
|
9003
9003
|
return documentQueries.links(document3, {
|
|
9004
9004
|
...selector.text !== void 0 ? { text: selector.text } : {},
|
|
9005
9005
|
...selector.url !== void 0 ? { url: selector.url } : {}
|
|
9006
|
-
}).filter((
|
|
9006
|
+
}).filter((link3) => targetMatchesSection(document3, link3.target.id, selector.section)).map((link3) => ({
|
|
9007
9007
|
kind: "link",
|
|
9008
|
-
link:
|
|
9009
|
-
text:
|
|
9010
|
-
...sourceFromTarget(document3,
|
|
9008
|
+
link: link3,
|
|
9009
|
+
text: link3.text,
|
|
9010
|
+
...sourceFromTarget(document3, link3.target)
|
|
9011
9011
|
}));
|
|
9012
9012
|
}
|
|
9013
9013
|
function listTargets(document3, selector) {
|
|
@@ -9751,6 +9751,49 @@ function targetColumnSource(assertion) {
|
|
|
9751
9751
|
};
|
|
9752
9752
|
}
|
|
9753
9753
|
|
|
9754
|
+
// src/declarative-validation/assertions/table-rows-complete.ts
|
|
9755
|
+
function evaluateTableRowsComplete(context) {
|
|
9756
|
+
if (context.selection.targets.length === 0) {
|
|
9757
|
+
return [emptySelectionDiagnostic(context.rule, context.assertionIndex)];
|
|
9758
|
+
}
|
|
9759
|
+
return context.selection.targets.flatMap(
|
|
9760
|
+
(target, targetOrder) => target.kind === "table" ? incompleteRows(target.table, context, targetOrder) : []
|
|
9761
|
+
);
|
|
9762
|
+
}
|
|
9763
|
+
function incompleteRows(table, context, targetOrder) {
|
|
9764
|
+
const expected = columnIndexes(table.cells.filter((cell) => cell.header));
|
|
9765
|
+
const rows = /* @__PURE__ */ new Map();
|
|
9766
|
+
for (const cell of table.cells) {
|
|
9767
|
+
if (!cell.header) {
|
|
9768
|
+
const cells = rows.get(cell.rowIndex) ?? [];
|
|
9769
|
+
cells.push(cell);
|
|
9770
|
+
rows.set(cell.rowIndex, cells);
|
|
9771
|
+
}
|
|
9772
|
+
}
|
|
9773
|
+
return [...rows].sort(([left], [right]) => left - right).flatMap(([rowIndex, cells]) => {
|
|
9774
|
+
const actual = columnIndexes(cells);
|
|
9775
|
+
if (expected.length === actual.length && expected.every((column, i) => column === actual[i])) {
|
|
9776
|
+
return [];
|
|
9777
|
+
}
|
|
9778
|
+
const sourceRange = [...cells].sort((left, right) => left.columnIndex - right.columnIndex).find((cell) => cell.sourceRange !== void 0)?.sourceRange;
|
|
9779
|
+
return [validationDiagnostic(
|
|
9780
|
+
"profile.validation.assertionFailed",
|
|
9781
|
+
`Selected table "${table.target.id}" body row ${rowIndex} must have column positions ${JSON.stringify(expected)}; found ${JSON.stringify(actual)}.`,
|
|
9782
|
+
context.rule,
|
|
9783
|
+
{
|
|
9784
|
+
assertionIndex: context.assertionIndex,
|
|
9785
|
+
targetOrder,
|
|
9786
|
+
targetKey: `table:${table.target.id}:row:${rowIndex}`,
|
|
9787
|
+
diagnosticOrder: rowIndex,
|
|
9788
|
+
...sourceRange === void 0 ? {} : { sourceRange }
|
|
9789
|
+
}
|
|
9790
|
+
)];
|
|
9791
|
+
});
|
|
9792
|
+
}
|
|
9793
|
+
function columnIndexes(cells) {
|
|
9794
|
+
return cells.map((cell) => cell.columnIndex).sort((left, right) => left - right);
|
|
9795
|
+
}
|
|
9796
|
+
|
|
9754
9797
|
// src/declarative-validation/assertions/table-columns-exact.ts
|
|
9755
9798
|
function evaluateTableColumnsExact(assertion, context) {
|
|
9756
9799
|
if (context.selection.targets.length === 0) {
|
|
@@ -10137,6 +10180,8 @@ function evaluateAssertion(assertion, context) {
|
|
|
10137
10180
|
return evaluateFrontmatterRequired(assertion, context);
|
|
10138
10181
|
case "tableColumnsRequired":
|
|
10139
10182
|
return evaluateTableColumnsRequired(assertion, context);
|
|
10183
|
+
case "tableRowsComplete":
|
|
10184
|
+
return evaluateTableRowsComplete(context);
|
|
10140
10185
|
case "tableColumnsExact":
|
|
10141
10186
|
return evaluateTableColumnsExact(assertion, context);
|
|
10142
10187
|
case "ids":
|
|
@@ -11568,6 +11613,7 @@ function selectorAssertionCompatibilityError(assertionName, selector) {
|
|
|
11568
11613
|
return selector.target === "document" ? void 0 : selectorCompatibilityMessage(assertionName, "document");
|
|
11569
11614
|
case "tableColumnsRequired":
|
|
11570
11615
|
case "tableColumnsExact":
|
|
11616
|
+
case "tableRowsComplete":
|
|
11571
11617
|
return selector.target === "table" ? void 0 : selectorCompatibilityMessage(assertionName, "table");
|
|
11572
11618
|
case "ids":
|
|
11573
11619
|
case "text":
|
|
@@ -11689,12 +11735,29 @@ function hasLengthBound(bounds) {
|
|
|
11689
11735
|
return bounds.min !== void 0 || bounds.max !== void 0;
|
|
11690
11736
|
}
|
|
11691
11737
|
|
|
11738
|
+
// src/declarative-validation/compiler/table-rows-complete.ts
|
|
11739
|
+
var buildTableRowsCompleteAssertion = (assertion, selector, ruleId, syntaxVersion, diagnostics) => {
|
|
11740
|
+
if (assertion.tableRowsComplete === void 0 || syntaxVersion !== PROFILE_SYNTAX_VERSION_V2) {
|
|
11741
|
+
return void 0;
|
|
11742
|
+
}
|
|
11743
|
+
if (assertion.tableRowsComplete !== true) {
|
|
11744
|
+
diagnostics.push(compileDiagnostic(
|
|
11745
|
+
"profile.config.invalidShape",
|
|
11746
|
+
"tableRowsComplete must be true.",
|
|
11747
|
+
ruleId
|
|
11748
|
+
));
|
|
11749
|
+
return void 0;
|
|
11750
|
+
}
|
|
11751
|
+
return pushCompatibilityDiagnostic("tableRowsComplete", selector, ruleId, diagnostics) ? { kind: "tableRowsComplete" } : void 0;
|
|
11752
|
+
};
|
|
11753
|
+
|
|
11692
11754
|
// src/declarative-validation/compiler/assertion-builders.ts
|
|
11693
11755
|
var ASSERTION_BUILDERS = [
|
|
11694
11756
|
buildExistsAssertion,
|
|
11695
11757
|
buildSectionsRequiredAssertion,
|
|
11696
11758
|
buildTableColumnsRequiredAssertion,
|
|
11697
11759
|
buildTableColumnsExactAssertion,
|
|
11760
|
+
buildTableRowsCompleteAssertion,
|
|
11698
11761
|
buildIdsAssertion,
|
|
11699
11762
|
buildReferencesAssertion,
|
|
11700
11763
|
buildTableColumnCoverageAssertion,
|
|
@@ -12122,6 +12185,7 @@ var ASSERTION_KEYS_V2 = [
|
|
|
12122
12185
|
"selectionCount",
|
|
12123
12186
|
"sourceLength",
|
|
12124
12187
|
"tableColumnsExact",
|
|
12188
|
+
"tableRowsComplete",
|
|
12125
12189
|
"tableColumnCoverage",
|
|
12126
12190
|
"frontmatterShape",
|
|
12127
12191
|
"textFormat"
|
|
@@ -12893,6 +12957,7 @@ var SUPPORTED_ASSERTION_KEYS_V2 = [
|
|
|
12893
12957
|
"selectionCount",
|
|
12894
12958
|
"sourceLength",
|
|
12895
12959
|
"tableColumnsExact",
|
|
12960
|
+
"tableRowsComplete",
|
|
12896
12961
|
"tableColumnCoverage",
|
|
12897
12962
|
"frontmatterShape",
|
|
12898
12963
|
"textFormat"
|
|
@@ -12919,6 +12984,7 @@ function assertionFromValue(value, syntaxVersion, diagnostics) {
|
|
|
12919
12984
|
...supportsV2AssertionSurface(syntaxVersion) ? selectionCountFromValue(value.selectionCount, diagnostics) : {},
|
|
12920
12985
|
...supportsV2AssertionSurface(syntaxVersion) ? sourceLengthFromValue(value.sourceLength, diagnostics) : {},
|
|
12921
12986
|
...supportsV2AssertionSurface(syntaxVersion) ? tableColumnsExactFromValue(value.tableColumnsExact, diagnostics) : {},
|
|
12987
|
+
...supportsV2AssertionSurface(syntaxVersion) ? tableRowsCompleteFromValue(value.tableRowsComplete, diagnostics) : {},
|
|
12922
12988
|
...frontmatterRequiredFromValue(value.frontmatterRequired, diagnostics),
|
|
12923
12989
|
...supportsV2AssertionSurface(syntaxVersion) ? tableColumnCoverageFromValue(value.tableColumnCoverage, diagnostics) : {},
|
|
12924
12990
|
...supportsV2AssertionSurface(syntaxVersion) ? frontmatterShapeFromValue2(value.frontmatterShape, diagnostics) : {},
|
|
@@ -12974,6 +13040,16 @@ function existsFromValue(value, diagnostics) {
|
|
|
12974
13040
|
}
|
|
12975
13041
|
return { exists: true };
|
|
12976
13042
|
}
|
|
13043
|
+
function tableRowsCompleteFromValue(value, diagnostics) {
|
|
13044
|
+
if (value === void 0) {
|
|
13045
|
+
return {};
|
|
13046
|
+
}
|
|
13047
|
+
if (value !== true) {
|
|
13048
|
+
diagnostics.push(invalidShape("tableRowsComplete must be true."));
|
|
13049
|
+
return {};
|
|
13050
|
+
}
|
|
13051
|
+
return { tableRowsComplete: true };
|
|
13052
|
+
}
|
|
12977
13053
|
function sectionsRequiredFromValue(value, diagnostics) {
|
|
12978
13054
|
if (value === void 0) {
|
|
12979
13055
|
return {};
|
|
@@ -13926,7 +14002,7 @@ function cloneSourceRange2(sourceRange) {
|
|
|
13926
14002
|
import { createHash } from "node:crypto";
|
|
13927
14003
|
|
|
13928
14004
|
// src/internal/package-version.ts
|
|
13929
|
-
var MARKDOWN_ENGINE_PACKAGE_VERSION = "3.
|
|
14005
|
+
var MARKDOWN_ENGINE_PACKAGE_VERSION = "3.8.0";
|
|
13930
14006
|
|
|
13931
14007
|
// src/internal/stable-json.ts
|
|
13932
14008
|
function normalizeStableJsonValue(value) {
|
|
@@ -19740,10 +19816,10 @@ function resolveAll(constructs2, events, context) {
|
|
|
19740
19816
|
const called = [];
|
|
19741
19817
|
let index2 = -1;
|
|
19742
19818
|
while (++index2 < constructs2.length) {
|
|
19743
|
-
const
|
|
19744
|
-
if (
|
|
19745
|
-
events =
|
|
19746
|
-
called.push(
|
|
19819
|
+
const resolve3 = constructs2[index2].resolveAll;
|
|
19820
|
+
if (resolve3 && !called.includes(resolve3)) {
|
|
19821
|
+
events = resolve3(events, context);
|
|
19822
|
+
called.push(resolve3);
|
|
19747
19823
|
}
|
|
19748
19824
|
}
|
|
19749
19825
|
return events;
|
|
@@ -24607,7 +24683,7 @@ function compiler(options) {
|
|
|
24607
24683
|
transforms: [],
|
|
24608
24684
|
canContainEols: ["emphasis", "fragment", "heading", "paragraph", "strong"],
|
|
24609
24685
|
enter: {
|
|
24610
|
-
autolink: opener(
|
|
24686
|
+
autolink: opener(link3),
|
|
24611
24687
|
autolinkProtocol: onenterdata,
|
|
24612
24688
|
autolinkEmail: onenterdata,
|
|
24613
24689
|
atxHeading: opener(heading2),
|
|
@@ -24635,7 +24711,7 @@ function compiler(options) {
|
|
|
24635
24711
|
htmlTextData: onenterdata,
|
|
24636
24712
|
image: opener(image2),
|
|
24637
24713
|
label: buffer,
|
|
24638
|
-
link: opener(
|
|
24714
|
+
link: opener(link3),
|
|
24639
24715
|
listItem: opener(listItem2),
|
|
24640
24716
|
listItemValue: onenterlistitemvalue,
|
|
24641
24717
|
listOrdered: opener(list3, onenterlistordered),
|
|
@@ -25187,7 +25263,7 @@ function compiler(options) {
|
|
|
25187
25263
|
alt: null
|
|
25188
25264
|
};
|
|
25189
25265
|
}
|
|
25190
|
-
function
|
|
25266
|
+
function link3() {
|
|
25191
25267
|
return {
|
|
25192
25268
|
type: "link",
|
|
25193
25269
|
title: null,
|
|
@@ -25688,9 +25764,9 @@ var VFile = class {
|
|
|
25688
25764
|
* @returns {undefined}
|
|
25689
25765
|
* Nothing.
|
|
25690
25766
|
*/
|
|
25691
|
-
set dirname(
|
|
25767
|
+
set dirname(dirname2) {
|
|
25692
25768
|
assertPath(this.basename, "dirname");
|
|
25693
|
-
this.path = default2.join(
|
|
25769
|
+
this.path = default2.join(dirname2 || "", this.basename);
|
|
25694
25770
|
}
|
|
25695
25771
|
/**
|
|
25696
25772
|
* Get the extname (including dot) (example: `'.js'`).
|
|
@@ -26289,7 +26365,7 @@ var Processor = class _Processor extends CallableInstance {
|
|
|
26289
26365
|
assertParser("process", this.parser || this.Parser);
|
|
26290
26366
|
assertCompiler("process", this.compiler || this.Compiler);
|
|
26291
26367
|
return done ? executor(void 0, done) : new Promise(executor);
|
|
26292
|
-
function executor(
|
|
26368
|
+
function executor(resolve3, reject) {
|
|
26293
26369
|
const realFile = vfile(file);
|
|
26294
26370
|
const parseTree = (
|
|
26295
26371
|
/** @type {HeadTree extends undefined ? Node : HeadTree} */
|
|
@@ -26320,8 +26396,8 @@ var Processor = class _Processor extends CallableInstance {
|
|
|
26320
26396
|
function realDone(error, file2) {
|
|
26321
26397
|
if (error || !file2) {
|
|
26322
26398
|
reject(error);
|
|
26323
|
-
} else if (
|
|
26324
|
-
|
|
26399
|
+
} else if (resolve3) {
|
|
26400
|
+
resolve3(file2);
|
|
26325
26401
|
} else {
|
|
26326
26402
|
ok(done, "`done` is defined if `resolve` is not");
|
|
26327
26403
|
done(void 0, file2);
|
|
@@ -26423,7 +26499,7 @@ var Processor = class _Processor extends CallableInstance {
|
|
|
26423
26499
|
file = void 0;
|
|
26424
26500
|
}
|
|
26425
26501
|
return done ? executor(void 0, done) : new Promise(executor);
|
|
26426
|
-
function executor(
|
|
26502
|
+
function executor(resolve3, reject) {
|
|
26427
26503
|
ok(
|
|
26428
26504
|
typeof file !== "function",
|
|
26429
26505
|
"`file` can\u2019t be a `done` anymore, we checked"
|
|
@@ -26437,8 +26513,8 @@ var Processor = class _Processor extends CallableInstance {
|
|
|
26437
26513
|
);
|
|
26438
26514
|
if (error) {
|
|
26439
26515
|
reject(error);
|
|
26440
|
-
} else if (
|
|
26441
|
-
|
|
26516
|
+
} else if (resolve3) {
|
|
26517
|
+
resolve3(resultingTree);
|
|
26442
26518
|
} else {
|
|
26443
26519
|
ok(done, "`done` is defined if `resolve` is not");
|
|
26444
26520
|
done(void 0, resultingTree, file2);
|
|
@@ -27449,13 +27525,7 @@ function compatibilityModeForDocumentVersion(documentVersion) {
|
|
|
27449
27525
|
}
|
|
27450
27526
|
|
|
27451
27527
|
// src/cli/validate-args.ts
|
|
27452
|
-
var
|
|
27453
|
-
var fileAssignmentPrefix = `${fileFlag}=`;
|
|
27454
|
-
var profileFlag = "--profile";
|
|
27455
|
-
var profileAssignmentPrefix = `${profileFlag}=`;
|
|
27456
|
-
var formatFlag = "--format";
|
|
27457
|
-
var formatAssignmentPrefix = `${formatFlag}=`;
|
|
27458
|
-
var validateCliUsage = `Usage: markdown-engine validate --file <markdown-file> --profile <profile-file> [--format json]
|
|
27528
|
+
var validateCliUsage = `Usage: markdown-engine validate --file <markdown-file> --profile <profile-file> [--format json] [--output full|summary] [--report-file <new-file>]
|
|
27459
27529
|
|
|
27460
27530
|
Runs declarative validation for one Markdown file and one validation profile.
|
|
27461
27531
|
|
|
@@ -27463,117 +27533,76 @@ Options:
|
|
|
27463
27533
|
--file <markdown-file> Markdown file to validate.
|
|
27464
27534
|
--profile <profile-file> Declarative validation profile to apply.
|
|
27465
27535
|
--format json Output JSON. This is the default and only supported format.
|
|
27536
|
+
--output full|summary Full JSON (default) or a compact validation summary.
|
|
27537
|
+
--report-file <new-file> Save full JSON; required for summary. Never overwrites.
|
|
27466
27538
|
-h, --help Show this help message.
|
|
27467
27539
|
|
|
27540
|
+
Summary includes at most 10 top-level diagnostics, errors first, with explicit
|
|
27541
|
+
omission/truncation counts. The report's parent directory must already exist.
|
|
27542
|
+
|
|
27468
27543
|
Exit status:
|
|
27469
27544
|
0 Validation completed with no error diagnostics.
|
|
27470
27545
|
1 Profile/config/compile or validation diagnostics failed.
|
|
27471
|
-
2 Usage, unsupported format, unknown args, or file read error.
|
|
27546
|
+
2 Usage, unsupported format, unknown args, or file read/write error.
|
|
27472
27547
|
`;
|
|
27473
27548
|
function parseValidateCliArgs(args) {
|
|
27474
|
-
const
|
|
27475
|
-
|
|
27476
|
-
|
|
27549
|
+
const values = {
|
|
27550
|
+
"--file": [],
|
|
27551
|
+
"--profile": [],
|
|
27552
|
+
"--format": [],
|
|
27553
|
+
"--output": [],
|
|
27554
|
+
"--report-file": []
|
|
27555
|
+
};
|
|
27477
27556
|
for (let index2 = 0; index2 < args.length; index2 += 1) {
|
|
27478
27557
|
const arg = args[index2];
|
|
27479
27558
|
if (arg === "-h" || arg === "--help") {
|
|
27480
27559
|
return { kind: "help", usage: validateCliUsage };
|
|
27481
27560
|
}
|
|
27482
|
-
|
|
27483
|
-
|
|
27484
|
-
|
|
27485
|
-
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27489
|
-
|
|
27490
|
-
|
|
27491
|
-
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
|
|
27496
|
-
|
|
27497
|
-
|
|
27498
|
-
|
|
27499
|
-
|
|
27500
|
-
|
|
27501
|
-
|
|
27502
|
-
|
|
27503
|
-
|
|
27504
|
-
|
|
27505
|
-
|
|
27506
|
-
|
|
27507
|
-
|
|
27508
|
-
|
|
27509
|
-
|
|
27510
|
-
|
|
27511
|
-
|
|
27512
|
-
|
|
27513
|
-
|
|
27514
|
-
|
|
27515
|
-
|
|
27516
|
-
|
|
27517
|
-
|
|
27518
|
-
|
|
27519
|
-
}
|
|
27520
|
-
format = parsedFormat.format;
|
|
27521
|
-
index2 += 1;
|
|
27522
|
-
continue;
|
|
27523
|
-
}
|
|
27524
|
-
if (arg?.startsWith(formatAssignmentPrefix) === true) {
|
|
27525
|
-
if (format !== void 0) {
|
|
27526
|
-
return validateError("Expected at most one --format selector.");
|
|
27527
|
-
}
|
|
27528
|
-
const parsedFormat = parseDeclarativeOutputFormat(
|
|
27529
|
-
arg.slice(formatAssignmentPrefix.length)
|
|
27530
|
-
);
|
|
27531
|
-
if (parsedFormat.kind === "error") {
|
|
27532
|
-
return validateError(parsedFormat.message);
|
|
27533
|
-
}
|
|
27534
|
-
format = parsedFormat.format;
|
|
27535
|
-
continue;
|
|
27536
|
-
}
|
|
27537
|
-
return validateError(`Unknown argument: ${arg ?? ""}`);
|
|
27538
|
-
}
|
|
27539
|
-
if (filePaths.length === 0) {
|
|
27540
|
-
return validateError("Expected exactly one --file target.");
|
|
27541
|
-
}
|
|
27542
|
-
if (filePaths.length > 1) {
|
|
27543
|
-
return validateError("Expected one Markdown file target, received multiple.");
|
|
27544
|
-
}
|
|
27545
|
-
if (profilePaths.length === 0) {
|
|
27546
|
-
return validateError("Expected exactly one --profile target.");
|
|
27547
|
-
}
|
|
27548
|
-
if (profilePaths.length > 1) {
|
|
27549
|
-
return validateError("Expected one profile file target, received multiple.");
|
|
27550
|
-
}
|
|
27551
|
-
const [filePath] = filePaths;
|
|
27552
|
-
const [profilePath] = profilePaths;
|
|
27553
|
-
if (filePath === void 0 || filePath.trim() === "") {
|
|
27554
|
-
return validateError("File path cannot be empty.");
|
|
27555
|
-
}
|
|
27556
|
-
if (profilePath === void 0 || profilePath.trim() === "") {
|
|
27557
|
-
return validateError("Profile path cannot be empty.");
|
|
27561
|
+
const equals = arg.indexOf("=");
|
|
27562
|
+
const flag = equals === -1 ? arg : arg.slice(0, equals);
|
|
27563
|
+
if (!Object.hasOwn(values, flag)) return validateError(`Unknown argument: ${arg}`);
|
|
27564
|
+
const entries = values[flag];
|
|
27565
|
+
if (flag !== "--file" && flag !== "--profile" && entries.length > 0) {
|
|
27566
|
+
return validateError(`Expected at most one ${flag} selector.`);
|
|
27567
|
+
}
|
|
27568
|
+
const value = equals === -1 ? args[index2 + 1] : arg.slice(equals + 1);
|
|
27569
|
+
if (value === void 0 || equals === -1 && value.startsWith("-")) {
|
|
27570
|
+
return validateError(`Missing value for ${flag}.`);
|
|
27571
|
+
}
|
|
27572
|
+
if (flag === "--format" && value !== "json") {
|
|
27573
|
+
return validateError(`Unsupported validation output format: ${value}.`);
|
|
27574
|
+
}
|
|
27575
|
+
if (flag === "--output" && value !== "full" && value !== "summary") {
|
|
27576
|
+
return validateError(`Unsupported validation output mode: ${value}.`);
|
|
27577
|
+
}
|
|
27578
|
+
entries.push(value);
|
|
27579
|
+
if (equals === -1) index2 += 1;
|
|
27580
|
+
}
|
|
27581
|
+
const files = values["--file"];
|
|
27582
|
+
const profiles = values["--profile"];
|
|
27583
|
+
if (files.length === 0) return validateError("Expected exactly one --file target.");
|
|
27584
|
+
if (files.length > 1) return validateError("Expected one Markdown file target, received multiple.");
|
|
27585
|
+
if (profiles.length === 0) return validateError("Expected exactly one --profile target.");
|
|
27586
|
+
if (profiles.length > 1) return validateError("Expected one profile file target, received multiple.");
|
|
27587
|
+
const filePath = files[0];
|
|
27588
|
+
const profilePath = profiles[0];
|
|
27589
|
+
if (filePath.trim() === "") return validateError("File path cannot be empty.");
|
|
27590
|
+
if (profilePath.trim() === "") return validateError("Profile path cannot be empty.");
|
|
27591
|
+
const output = values["--output"][0] ?? "full";
|
|
27592
|
+
const reportFile = values["--report-file"][0];
|
|
27593
|
+
if (reportFile !== void 0 && reportFile.trim() === "") {
|
|
27594
|
+
return validateError("Report file path cannot be empty.");
|
|
27595
|
+
}
|
|
27596
|
+
if (output === "summary" && reportFile === void 0) {
|
|
27597
|
+
return validateError("--output summary requires --report-file to retain the full result.");
|
|
27558
27598
|
}
|
|
27559
27599
|
return {
|
|
27560
27600
|
kind: "validate",
|
|
27561
27601
|
filePath,
|
|
27562
|
-
|
|
27563
|
-
|
|
27564
|
-
|
|
27565
|
-
}
|
|
27566
|
-
function readRequiredFlagValue(arg, args, index2) {
|
|
27567
|
-
const value = args[index2 + 1];
|
|
27568
|
-
if (value === void 0 || value.startsWith("-")) {
|
|
27569
|
-
return { kind: "error", message: `Missing value for ${arg}.` };
|
|
27570
|
-
}
|
|
27571
|
-
return { kind: "ok", value };
|
|
27572
|
-
}
|
|
27573
|
-
function parseDeclarativeOutputFormat(value) {
|
|
27574
|
-
return value === "json" ? { kind: "ok", format: value } : {
|
|
27575
|
-
kind: "error",
|
|
27576
|
-
message: `Unsupported validation output format: ${value}.`
|
|
27602
|
+
profilePath,
|
|
27603
|
+
format: "json",
|
|
27604
|
+
output,
|
|
27605
|
+
...reportFile !== void 0 ? { reportFile } : {}
|
|
27577
27606
|
};
|
|
27578
27607
|
}
|
|
27579
27608
|
function validateError(message) {
|
|
@@ -27585,8 +27614,8 @@ var documentVersionFlag = "--document-version";
|
|
|
27585
27614
|
var documentVersionAssignmentPrefix = `${documentVersionFlag}=`;
|
|
27586
27615
|
var duplicateDocumentVersionMessage = "Expected at most one --document-version selector.";
|
|
27587
27616
|
var validateCommand = "validate";
|
|
27588
|
-
var
|
|
27589
|
-
var
|
|
27617
|
+
var fileFlag = "--file";
|
|
27618
|
+
var fileAssignmentPrefix = `${fileFlag}=`;
|
|
27590
27619
|
var pathFlag = "--path";
|
|
27591
27620
|
var pathAssignmentPrefix = `${pathFlag}=`;
|
|
27592
27621
|
var normalizeCliUsage = `Usage: markdown-engine [--document-version <version>] (--file <markdown-file> | --path <markdown-file>)
|
|
@@ -27616,7 +27645,7 @@ function parseNormalizeCliArgs(args) {
|
|
|
27616
27645
|
if (arg === "-h" || arg === "--help") {
|
|
27617
27646
|
return { kind: "help", usage: cliUsage };
|
|
27618
27647
|
}
|
|
27619
|
-
if (arg ===
|
|
27648
|
+
if (arg === fileFlag || arg === pathFlag) {
|
|
27620
27649
|
const value = args[index2 + 1];
|
|
27621
27650
|
if (value === void 0 || value.startsWith("-")) {
|
|
27622
27651
|
return normalizeError(`Missing value for ${arg}.`);
|
|
@@ -27643,8 +27672,8 @@ function parseNormalizeCliArgs(args) {
|
|
|
27643
27672
|
}
|
|
27644
27673
|
continue;
|
|
27645
27674
|
}
|
|
27646
|
-
if (arg?.startsWith(
|
|
27647
|
-
targets.push(arg.slice(
|
|
27675
|
+
if (arg?.startsWith(fileAssignmentPrefix) === true) {
|
|
27676
|
+
targets.push(arg.slice(fileAssignmentPrefix.length));
|
|
27648
27677
|
continue;
|
|
27649
27678
|
}
|
|
27650
27679
|
if (arg?.startsWith(pathAssignmentPrefix) === true) {
|
|
@@ -27731,6 +27760,99 @@ function normalizeMarkdown(input) {
|
|
|
27731
27760
|
});
|
|
27732
27761
|
}
|
|
27733
27762
|
|
|
27763
|
+
// src/cli/validation-report.ts
|
|
27764
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
27765
|
+
import { link as link2, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
27766
|
+
import { dirname, join, resolve as resolve2 } from "node:path";
|
|
27767
|
+
async function saveValidationReport(cwd, reportFile, content3) {
|
|
27768
|
+
const path2 = resolve2(cwd, reportFile);
|
|
27769
|
+
const temporaryDirectory = await mkdtemp(join(dirname(path2), ".markdown-engine-report-"));
|
|
27770
|
+
try {
|
|
27771
|
+
const temporaryFile = join(temporaryDirectory, "report.json");
|
|
27772
|
+
await writeFile(temporaryFile, content3, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
27773
|
+
await link2(temporaryFile, path2);
|
|
27774
|
+
} finally {
|
|
27775
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
27776
|
+
}
|
|
27777
|
+
return {
|
|
27778
|
+
path: path2,
|
|
27779
|
+
sha256: createHash2("sha256").update(content3, "utf8").digest("hex"),
|
|
27780
|
+
bytes: Buffer.byteLength(content3, "utf8")
|
|
27781
|
+
};
|
|
27782
|
+
}
|
|
27783
|
+
|
|
27784
|
+
// src/cli/validation-summary.ts
|
|
27785
|
+
var diagnosticLimit = 10;
|
|
27786
|
+
var severityOrder = { error: 0, warning: 1, info: 2 };
|
|
27787
|
+
function createValidationSummary(result, exitCode, report) {
|
|
27788
|
+
const diagnostics = [...result.diagnostics].sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]).slice(0, diagnosticLimit).map(compactDiagnostic);
|
|
27789
|
+
const counts = { total: result.diagnostics.length, error: 0, warning: 0, info: 0 };
|
|
27790
|
+
for (const diagnostic of result.diagnostics) counts[diagnostic.severity] += 1;
|
|
27791
|
+
const evidence = result.evidence;
|
|
27792
|
+
return {
|
|
27793
|
+
schemaVersion: "markdown-engine.validation-summary.v1",
|
|
27794
|
+
valid: result.valid,
|
|
27795
|
+
stage: "stage" in result ? result.stage : "validation",
|
|
27796
|
+
exitCode,
|
|
27797
|
+
engineVersion: MARKDOWN_ENGINE_PACKAGE_VERSION,
|
|
27798
|
+
runtimeVersion: process.version,
|
|
27799
|
+
...result.profile !== void 0 ? { profile: result.profile } : {},
|
|
27800
|
+
...evidence !== void 0 ? {
|
|
27801
|
+
evidence: {
|
|
27802
|
+
inputHash: evidence.inputHash,
|
|
27803
|
+
profileHash: evidence.profileHash,
|
|
27804
|
+
engineVersion: evidence.engineVersion,
|
|
27805
|
+
runtimeVersion: evidence.runtimeVersion,
|
|
27806
|
+
...evidence.sourceLength !== void 0 ? { sourceLength: evidence.sourceLength } : {}
|
|
27807
|
+
}
|
|
27808
|
+
} : {},
|
|
27809
|
+
diagnosticCounts: counts,
|
|
27810
|
+
diagnostics,
|
|
27811
|
+
diagnosticsOmitted: counts.total - diagnostics.length,
|
|
27812
|
+
diagnosticsTruncated: diagnostics.filter((d) => d.truncatedFields.length > 0).length,
|
|
27813
|
+
report
|
|
27814
|
+
};
|
|
27815
|
+
}
|
|
27816
|
+
function compactDiagnostic(diagnostic) {
|
|
27817
|
+
const truncatedFields = [];
|
|
27818
|
+
const bound = (field, value, max) => {
|
|
27819
|
+
if (value.length <= max) return value;
|
|
27820
|
+
truncatedFields.push(field);
|
|
27821
|
+
return `${value.slice(0, max - 1)}\u2026`;
|
|
27822
|
+
};
|
|
27823
|
+
return {
|
|
27824
|
+
code: bound("code", diagnostic.code, 128),
|
|
27825
|
+
message: bound("message", diagnostic.message, 512),
|
|
27826
|
+
severity: diagnostic.severity,
|
|
27827
|
+
...diagnostic.ruleId !== void 0 ? { ruleId: bound("ruleId", diagnostic.ruleId, 128) } : {},
|
|
27828
|
+
...diagnostic.sourceRange !== void 0 ? { sourceRange: diagnostic.sourceRange } : {},
|
|
27829
|
+
truncatedFields
|
|
27830
|
+
};
|
|
27831
|
+
}
|
|
27832
|
+
|
|
27833
|
+
// src/cli/validation-output.ts
|
|
27834
|
+
async function outputValidationResult(result, exitCode, options) {
|
|
27835
|
+
const output = JSON.stringify(normalizeStableJsonValue(result), null, 2) ?? "null";
|
|
27836
|
+
try {
|
|
27837
|
+
const report = options.reportFile === void 0 ? void 0 : await saveValidationReport(options.cwd, options.reportFile, `${output}
|
|
27838
|
+
`);
|
|
27839
|
+
if (options.output === "summary") {
|
|
27840
|
+
if (report === void 0) throw new Error("--output summary requires --report-file.");
|
|
27841
|
+
return {
|
|
27842
|
+
kind: "output",
|
|
27843
|
+
exitCode,
|
|
27844
|
+
output: JSON.stringify(normalizeStableJsonValue(createValidationSummary(result, exitCode, report)))
|
|
27845
|
+
};
|
|
27846
|
+
}
|
|
27847
|
+
return { kind: "output", exitCode, output };
|
|
27848
|
+
} catch (error) {
|
|
27849
|
+
return {
|
|
27850
|
+
kind: "fileError",
|
|
27851
|
+
message: `Unable to save validation report "${options.reportFile ?? ""}": ${error instanceof Error ? error.message : String(error)}`
|
|
27852
|
+
};
|
|
27853
|
+
}
|
|
27854
|
+
}
|
|
27855
|
+
|
|
27734
27856
|
// src/cli/declarative-validation.ts
|
|
27735
27857
|
async function runDeclarativeValidationCli(input) {
|
|
27736
27858
|
const profileText = await readValidationFile(input.profilePath, input.cwd);
|
|
@@ -27741,13 +27863,14 @@ async function runDeclarativeValidationCli(input) {
|
|
|
27741
27863
|
path: input.profilePath
|
|
27742
27864
|
});
|
|
27743
27865
|
if (profileResult.profile === void 0 || hasErrorDiagnostic(profileResult.diagnostics)) {
|
|
27744
|
-
return
|
|
27866
|
+
return outputValidationResult(profileStageResult(profileResult.diagnostics), 1, input);
|
|
27745
27867
|
}
|
|
27746
27868
|
const compileDiagnostics = compileProfileForCli(profileResult.profile);
|
|
27747
27869
|
if (hasErrorDiagnostic(compileDiagnostics)) {
|
|
27748
|
-
return
|
|
27870
|
+
return outputValidationResult(
|
|
27749
27871
|
profileStageResult([...profileResult.diagnostics, ...compileDiagnostics]),
|
|
27750
|
-
1
|
|
27872
|
+
1,
|
|
27873
|
+
input
|
|
27751
27874
|
);
|
|
27752
27875
|
}
|
|
27753
27876
|
const markdown = await readValidationFile(input.filePath, input.cwd);
|
|
@@ -27764,7 +27887,7 @@ async function runDeclarativeValidationCli(input) {
|
|
|
27764
27887
|
...normalizeResult.diagnostics
|
|
27765
27888
|
];
|
|
27766
27889
|
if (hasErrorDiagnostic(normalizeResult.diagnostics)) {
|
|
27767
|
-
return
|
|
27890
|
+
return outputValidationResult(
|
|
27768
27891
|
documentDiagnosticsResult(
|
|
27769
27892
|
normalizeResult.document,
|
|
27770
27893
|
profileResult.profile,
|
|
@@ -27777,7 +27900,8 @@ async function runDeclarativeValidationCli(input) {
|
|
|
27777
27900
|
)
|
|
27778
27901
|
]
|
|
27779
27902
|
),
|
|
27780
|
-
1
|
|
27903
|
+
1,
|
|
27904
|
+
input
|
|
27781
27905
|
);
|
|
27782
27906
|
}
|
|
27783
27907
|
const validationResult = validateWithProfile(
|
|
@@ -27789,9 +27913,10 @@ async function runDeclarativeValidationCli(input) {
|
|
|
27789
27913
|
validationResult,
|
|
27790
27914
|
documentDiagnostics
|
|
27791
27915
|
);
|
|
27792
|
-
return
|
|
27916
|
+
return outputValidationResult(
|
|
27793
27917
|
result,
|
|
27794
|
-
hasErrorDiagnostic(result.diagnostics) ? 1 : 0
|
|
27918
|
+
hasErrorDiagnostic(result.diagnostics) ? 1 : 0,
|
|
27919
|
+
input
|
|
27795
27920
|
);
|
|
27796
27921
|
}
|
|
27797
27922
|
function compileProfileForCli(profile) {
|
|
@@ -27844,16 +27969,6 @@ function mergeDocumentDiagnostics(validationResult, documentDiagnostics) {
|
|
|
27844
27969
|
} : {}
|
|
27845
27970
|
};
|
|
27846
27971
|
}
|
|
27847
|
-
function outputResult(result, exitCode) {
|
|
27848
|
-
return {
|
|
27849
|
-
kind: "output",
|
|
27850
|
-
exitCode,
|
|
27851
|
-
output: serializeDeclarativeValidationCliJsonResult(result)
|
|
27852
|
-
};
|
|
27853
|
-
}
|
|
27854
|
-
function serializeDeclarativeValidationCliJsonResult(result) {
|
|
27855
|
-
return JSON.stringify(normalizeStableJsonValue(result), null, 2) ?? "null";
|
|
27856
|
-
}
|
|
27857
27972
|
async function readValidationFile(path2, cwd) {
|
|
27858
27973
|
try {
|
|
27859
27974
|
return {
|
|
@@ -27886,7 +28001,9 @@ ${argsResult.usage}`);
|
|
|
27886
28001
|
cwd: input.cwd,
|
|
27887
28002
|
filePath: argsResult.filePath,
|
|
27888
28003
|
format: argsResult.format,
|
|
27889
|
-
profilePath: argsResult.profilePath
|
|
28004
|
+
profilePath: argsResult.profilePath,
|
|
28005
|
+
output: argsResult.output,
|
|
28006
|
+
...argsResult.reportFile !== void 0 ? { reportFile: argsResult.reportFile } : {}
|
|
27890
28007
|
});
|
|
27891
28008
|
if (validationResult.kind === "fileError") {
|
|
27892
28009
|
input.stderr.write(`${validationResult.message}
|