flex-md 4.5.3 → 4.5.5
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/dist/__tests__/diagnostics.test.js +47 -45
- package/dist/__tests__/ofs.test.js +30 -28
- package/dist/__tests__/structural.test.js +21 -19
- package/dist/__tests__/validate.test.js +29 -27
- package/dist/cli/index.js +15 -13
- package/dist/detect/json/detectIntent.js +4 -1
- package/dist/detect/json/detectMarkdown.js +35 -29
- package/dist/detect/json/detectPresence.js +6 -2
- package/dist/detect/json/index.js +31 -10
- package/dist/detect/json/types.js +2 -1
- package/dist/extract/extract.js +14 -11
- package/dist/extract/types.js +2 -1
- package/dist/index.js +67 -22
- package/dist/logger.js +6 -3
- package/dist/md/match.js +4 -1
- package/dist/md/normalize.js +4 -1
- package/dist/md/outline.js +8 -4
- package/dist/md/parse.js +20 -11
- package/dist/ofs/adapter.js +49 -45
- package/dist/ofs/enricher.js +8 -3
- package/dist/ofs/infer.js +7 -4
- package/dist/ofs/issuesEnvelope.js +10 -5
- package/dist/ofs/memory.js +10 -6
- package/dist/ofs/parser.js +8 -4
- package/dist/ofs/stringify.js +4 -1
- package/dist/pipeline/enforce.js +15 -12
- package/dist/pipeline/kind.js +6 -3
- package/dist/pipeline/repair.js +11 -8
- package/dist/strictness/container.js +4 -1
- package/dist/strictness/processor.js +10 -7
- package/dist/strictness/types.js +4 -1
- package/dist/tokens/auto-fix.js +4 -1
- package/dist/tokens/cognitive-cost.js +10 -6
- package/dist/tokens/compliance.js +8 -4
- package/dist/tokens/confidence.js +9 -6
- package/dist/tokens/estimator.js +23 -18
- package/dist/tokens/improvements.js +16 -12
- package/dist/tokens/index.js +33 -16
- package/dist/tokens/parser.js +7 -4
- package/dist/tokens/patterns.js +5 -2
- package/dist/tokens/smart-report.js +14 -10
- package/dist/tokens/spec-estimator.js +11 -8
- package/dist/tokens/types.js +2 -1
- package/dist/tokens/validator.js +6 -3
- package/dist/types.js +2 -1
- package/dist/validate/compliance.js +6 -2
- package/dist/validate/connection.js +8 -5
- package/dist/validate/types.js +2 -1
- package/dist/validate/validate.js +19 -16
- package/package.json +3 -3
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectJsonContainers = detectJsonContainers;
|
|
4
|
+
exports.detectJsonPresence = detectJsonPresence;
|
|
1
5
|
const RX_JSON_FENCE = /```json\s*\n([\s\S]*?)\n```/gi;
|
|
2
6
|
const RX_JSON_MARKER = /(BEGIN_JSON|BEGIN\s+JSON)\s*\n([\s\S]*?)\n(END_JSON|END\s+JSON)/gi;
|
|
3
7
|
// Very conservative raw JSON: must be only whitespace + object/array + whitespace
|
|
4
8
|
const RX_RAW_JSON = /^\s*(\{[\s\S]*\}|\[[\s\S]*\])\s*$/;
|
|
5
9
|
// Inline candidate finder
|
|
6
10
|
const RX_INLINE_CANDIDATE = /(\{|\[)/g;
|
|
7
|
-
|
|
11
|
+
function detectJsonContainers(md) {
|
|
8
12
|
const fences = [];
|
|
9
13
|
const markers = [];
|
|
10
14
|
RX_JSON_FENCE.lastIndex = 0;
|
|
@@ -33,7 +37,7 @@ export function detectJsonContainers(md) {
|
|
|
33
37
|
markers,
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
|
-
|
|
40
|
+
function detectJsonPresence(text, opts) {
|
|
37
41
|
const spans = [];
|
|
38
42
|
const kinds = new Set();
|
|
39
43
|
// 1) fenced json blocks
|
|
@@ -1,13 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.detectJsonPresence = exports.detectJsonContainers = exports.detectJsonIntent = void 0;
|
|
18
|
+
exports.detectJsonAll = detectJsonAll;
|
|
19
|
+
const detectIntent_js_1 = require("./detectIntent.js");
|
|
20
|
+
const detectPresence_js_1 = require("./detectPresence.js");
|
|
21
|
+
__exportStar(require("./types.js"), exports);
|
|
22
|
+
var detectIntent_js_2 = require("./detectIntent.js");
|
|
23
|
+
Object.defineProperty(exports, "detectJsonIntent", { enumerable: true, get: function () { return detectIntent_js_2.detectJsonIntent; } });
|
|
24
|
+
var detectPresence_js_2 = require("./detectPresence.js");
|
|
25
|
+
Object.defineProperty(exports, "detectJsonContainers", { enumerable: true, get: function () { return detectPresence_js_2.detectJsonContainers; } });
|
|
26
|
+
Object.defineProperty(exports, "detectJsonPresence", { enumerable: true, get: function () { return detectPresence_js_2.detectJsonPresence; } });
|
|
27
|
+
__exportStar(require("./detectMarkdown.js"), exports);
|
|
28
|
+
function detectJsonAll(textOrMd, opts) {
|
|
8
29
|
return {
|
|
9
|
-
intent: detectJsonIntent(textOrMd),
|
|
10
|
-
containers: detectJsonContainers(textOrMd),
|
|
11
|
-
presence: detectJsonPresence(textOrMd, { parse: !!opts?.parseJson }),
|
|
30
|
+
intent: (0, detectIntent_js_1.detectJsonIntent)(textOrMd),
|
|
31
|
+
containers: (0, detectPresence_js_1.detectJsonContainers)(textOrMd),
|
|
32
|
+
presence: (0, detectPresence_js_1.detectJsonPresence)(textOrMd, { parse: !!opts?.parseJson }),
|
|
12
33
|
};
|
|
13
34
|
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/extract/extract.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractFromMarkdown = extractFromMarkdown;
|
|
4
|
+
const parse_js_1 = require("../md/parse.js");
|
|
2
5
|
/**
|
|
3
6
|
* Extracts sections, lists, and tables from Markdown based on the OFS.
|
|
4
7
|
*/
|
|
5
|
-
|
|
8
|
+
function extractFromMarkdown(md, spec) {
|
|
6
9
|
// 0. Robustness: check for fenced block that might contain the target content
|
|
7
10
|
// Highly relevant for LLM responses where the model occasionally wraps everything in a container
|
|
8
11
|
// even if not strictly asked, or if the user provided unframed content but we have L2+ expectations elsewhere.
|
|
@@ -12,28 +15,28 @@ export function extractFromMarkdown(md, spec) {
|
|
|
12
15
|
if (matches.length === 1) {
|
|
13
16
|
const content = matches[0][1];
|
|
14
17
|
// If the content inside the fence has more required sections than outside, use it
|
|
15
|
-
const parsedOutside = parseHeadingsAndSections(md);
|
|
16
|
-
const parsedInside = parseHeadingsAndSections(content);
|
|
17
|
-
const specNorms = new Set(spec.sections.map(s => normalizeName(s.name)));
|
|
18
|
-
const countOutside = parsedOutside.filter(p => specNorms.has(normalizeName(p.heading.name))).length;
|
|
19
|
-
const countInside = parsedInside.filter(p => specNorms.has(normalizeName(p.heading.name))).length;
|
|
18
|
+
const parsedOutside = (0, parse_js_1.parseHeadingsAndSections)(md);
|
|
19
|
+
const parsedInside = (0, parse_js_1.parseHeadingsAndSections)(content);
|
|
20
|
+
const specNorms = new Set(spec.sections.map(s => (0, parse_js_1.normalizeName)(s.name)));
|
|
21
|
+
const countOutside = parsedOutside.filter(p => specNorms.has((0, parse_js_1.normalizeName)(p.heading.name))).length;
|
|
22
|
+
const countInside = parsedInside.filter(p => specNorms.has((0, parse_js_1.normalizeName)(p.heading.name))).length;
|
|
20
23
|
if (countInside >= countOutside && countInside > 0) {
|
|
21
24
|
workingContent = content;
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
const bulletNames = spec.sections.map(s => s.name);
|
|
25
|
-
const parsed = parseHeadingsAndSections(workingContent, { bulletNames });
|
|
28
|
+
const parsed = (0, parse_js_1.parseHeadingsAndSections)(workingContent, { bulletNames });
|
|
26
29
|
const sectionsByName = {};
|
|
27
30
|
const tables = [];
|
|
28
|
-
const specMap = new Map(spec.sections.map(s => [normalizeName(s.name), s]));
|
|
31
|
+
const specMap = new Map(spec.sections.map(s => [(0, parse_js_1.normalizeName)(s.name), s]));
|
|
29
32
|
for (const p of parsed) {
|
|
30
|
-
const norm = normalizeName(p.heading.name);
|
|
33
|
+
const norm = (0, parse_js_1.normalizeName)(p.heading.name);
|
|
31
34
|
const sSpec = specMap.get(norm);
|
|
32
35
|
if (sSpec) {
|
|
33
36
|
const body = p.body.trim();
|
|
34
37
|
let list;
|
|
35
38
|
if (sSpec.kind === "list" || sSpec.kind === "ordered_list") {
|
|
36
|
-
const bullets = extractBullets(body);
|
|
39
|
+
const bullets = (0, parse_js_1.extractBullets)(body);
|
|
37
40
|
if (bullets.length > 0) {
|
|
38
41
|
list = {
|
|
39
42
|
kind: "list",
|
package/dist/extract/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.jsonToMarkdown = exports.Schema = exports.MarkdownParser = exports.JSONTransformer = exports.enforceFlexMd = exports.repairToMarkdownLevel = exports.detectResponseKind = exports.buildIssuesEnvelopeAuto = exports.buildIssuesEnvelope = exports.parseIssuesEnvelope = exports.processResponseMarkdown = exports.extractFromMarkdown = exports.checkConnection = exports.hasFlexMdContract = exports.checkCompliance = exports.validateMarkdownAgainstOfs = exports.enrichInstructionsWithFlexMd = exports.enrichInstructions = exports.buildMarkdownGuidance = exports.stringifyOutputFormatSpec = exports.recall = exports.remember = exports.transformWithOfs = exports.ofsToSchema = exports.validateFormat = exports.parseOutputFormatSpec = exports.buildOutline = exports.logger = void 0;
|
|
1
18
|
// Core SFMD Types
|
|
2
|
-
|
|
3
|
-
|
|
19
|
+
__exportStar(require("./types.js"), exports);
|
|
20
|
+
__exportStar(require("./strictness/types.js"), exports);
|
|
4
21
|
// Logging
|
|
5
|
-
|
|
22
|
+
var logger_js_1 = require("./logger.js");
|
|
23
|
+
Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_js_1.logger; } });
|
|
6
24
|
// Shared MD Parsing
|
|
7
|
-
|
|
8
|
-
|
|
25
|
+
__exportStar(require("./md/parse.js"), exports);
|
|
26
|
+
var outline_js_1 = require("./md/outline.js");
|
|
27
|
+
Object.defineProperty(exports, "buildOutline", { enumerable: true, get: function () { return outline_js_1.buildOutline; } });
|
|
9
28
|
// Output Format Spec (OFS)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
29
|
+
var parser_js_1 = require("./ofs/parser.js");
|
|
30
|
+
Object.defineProperty(exports, "parseOutputFormatSpec", { enumerable: true, get: function () { return parser_js_1.parseOutputFormatSpec; } });
|
|
31
|
+
Object.defineProperty(exports, "validateFormat", { enumerable: true, get: function () { return parser_js_1.validateFormat; } });
|
|
32
|
+
var adapter_js_1 = require("./ofs/adapter.js");
|
|
33
|
+
Object.defineProperty(exports, "ofsToSchema", { enumerable: true, get: function () { return adapter_js_1.ofsToSchema; } });
|
|
34
|
+
Object.defineProperty(exports, "transformWithOfs", { enumerable: true, get: function () { return adapter_js_1.transformWithOfs; } });
|
|
35
|
+
var memory_js_1 = require("./ofs/memory.js");
|
|
36
|
+
Object.defineProperty(exports, "remember", { enumerable: true, get: function () { return memory_js_1.remember; } });
|
|
37
|
+
Object.defineProperty(exports, "recall", { enumerable: true, get: function () { return memory_js_1.recall; } });
|
|
38
|
+
var stringify_js_1 = require("./ofs/stringify.js");
|
|
39
|
+
Object.defineProperty(exports, "stringifyOutputFormatSpec", { enumerable: true, get: function () { return stringify_js_1.stringifyOutputFormatSpec; } });
|
|
40
|
+
var enricher_js_1 = require("./ofs/enricher.js");
|
|
41
|
+
Object.defineProperty(exports, "buildMarkdownGuidance", { enumerable: true, get: function () { return enricher_js_1.buildMarkdownGuidance; } });
|
|
42
|
+
Object.defineProperty(exports, "enrichInstructions", { enumerable: true, get: function () { return enricher_js_1.enrichInstructions; } });
|
|
43
|
+
Object.defineProperty(exports, "enrichInstructionsWithFlexMd", { enumerable: true, get: function () { return enricher_js_1.enrichInstructionsWithFlexMd; } });
|
|
15
44
|
// Validation & Extraction
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
45
|
+
var validate_js_1 = require("./validate/validate.js");
|
|
46
|
+
Object.defineProperty(exports, "validateMarkdownAgainstOfs", { enumerable: true, get: function () { return validate_js_1.validateMarkdownAgainstOfs; } });
|
|
47
|
+
var compliance_js_1 = require("./validate/compliance.js");
|
|
48
|
+
Object.defineProperty(exports, "checkCompliance", { enumerable: true, get: function () { return compliance_js_1.checkCompliance; } });
|
|
49
|
+
Object.defineProperty(exports, "hasFlexMdContract", { enumerable: true, get: function () { return compliance_js_1.hasFlexMdContract; } });
|
|
50
|
+
var connection_js_1 = require("./validate/connection.js");
|
|
51
|
+
Object.defineProperty(exports, "checkConnection", { enumerable: true, get: function () { return connection_js_1.checkConnection; } });
|
|
52
|
+
var extract_js_1 = require("./extract/extract.js");
|
|
53
|
+
Object.defineProperty(exports, "extractFromMarkdown", { enumerable: true, get: function () { return extract_js_1.extractFromMarkdown; } });
|
|
20
54
|
// Processor & Fallback
|
|
21
|
-
|
|
22
|
-
|
|
55
|
+
var processor_js_1 = require("./strictness/processor.js");
|
|
56
|
+
Object.defineProperty(exports, "processResponseMarkdown", { enumerable: true, get: function () { return processor_js_1.processResponseMarkdown; } });
|
|
57
|
+
var issuesEnvelope_js_1 = require("./ofs/issuesEnvelope.js");
|
|
58
|
+
Object.defineProperty(exports, "parseIssuesEnvelope", { enumerable: true, get: function () { return issuesEnvelope_js_1.parseIssuesEnvelope; } });
|
|
59
|
+
Object.defineProperty(exports, "buildIssuesEnvelope", { enumerable: true, get: function () { return issuesEnvelope_js_1.buildIssuesEnvelope; } });
|
|
60
|
+
Object.defineProperty(exports, "buildIssuesEnvelopeAuto", { enumerable: true, get: function () { return issuesEnvelope_js_1.buildIssuesEnvelopeAuto; } });
|
|
23
61
|
// Pipeline
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
62
|
+
var kind_js_1 = require("./pipeline/kind.js");
|
|
63
|
+
Object.defineProperty(exports, "detectResponseKind", { enumerable: true, get: function () { return kind_js_1.detectResponseKind; } });
|
|
64
|
+
var repair_js_1 = require("./pipeline/repair.js");
|
|
65
|
+
Object.defineProperty(exports, "repairToMarkdownLevel", { enumerable: true, get: function () { return repair_js_1.repairToMarkdownLevel; } });
|
|
66
|
+
var enforce_js_1 = require("./pipeline/enforce.js");
|
|
67
|
+
Object.defineProperty(exports, "enforceFlexMd", { enumerable: true, get: function () { return enforce_js_1.enforceFlexMd; } });
|
|
27
68
|
// JSON Detection
|
|
28
|
-
|
|
69
|
+
__exportStar(require("./detect/json/index.js"), exports);
|
|
29
70
|
// Token Estimation
|
|
30
|
-
|
|
71
|
+
__exportStar(require("./tokens/index.js"), exports);
|
|
31
72
|
// NX-MD-Parser Integration (Structured MD -> JSON)
|
|
32
|
-
|
|
73
|
+
var nx_md_parser_1 = require("nx-md-parser");
|
|
74
|
+
Object.defineProperty(exports, "JSONTransformer", { enumerable: true, get: function () { return nx_md_parser_1.JSONTransformer; } });
|
|
75
|
+
Object.defineProperty(exports, "MarkdownParser", { enumerable: true, get: function () { return nx_md_parser_1.MarkdownParser; } });
|
|
76
|
+
Object.defineProperty(exports, "Schema", { enumerable: true, get: function () { return nx_md_parser_1.Schema; } });
|
|
77
|
+
Object.defineProperty(exports, "jsonToMarkdown", { enumerable: true, get: function () { return nx_md_parser_1.jsonToMarkdown; } });
|
package/dist/logger.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.threshold = exports.logger = void 0;
|
|
4
|
+
const micro_logs_1 = require("micro-logs");
|
|
2
5
|
// Get DEBUG_LEVEL from environment, default to 'info'
|
|
3
6
|
const debugLevel = process.env.DEBUG_LEVEL || 'info';
|
|
4
7
|
// Map string levels to micro-logs levels
|
|
@@ -11,9 +14,9 @@ const levelMapping = {
|
|
|
11
14
|
};
|
|
12
15
|
// Default to 'info' if invalid level provided
|
|
13
16
|
const threshold = levelMapping[debugLevel.toLowerCase()] || 'info';
|
|
14
|
-
|
|
17
|
+
exports.threshold = threshold;
|
|
18
|
+
exports.logger = new micro_logs_1.Logger({
|
|
15
19
|
packageName: 'flex-md',
|
|
16
20
|
envPrefix: 'FLEX_MD',
|
|
17
21
|
debugNamespace: 'flex-md:*'
|
|
18
22
|
});
|
|
19
|
-
export { threshold };
|
package/dist/md/match.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.matchSections = matchSections;
|
|
1
4
|
/**
|
|
2
5
|
* Matches sections from the outline against required section names.
|
|
3
6
|
* Supports merging multiple nodes of the same name and selecting highest-level matches.
|
|
4
7
|
*/
|
|
5
|
-
|
|
8
|
+
function matchSections(outline, sectionNames, strategy = "merge") {
|
|
6
9
|
const normalizedTargets = new Map(sectionNames.map(n => [norm(n), n]));
|
|
7
10
|
const found = new Map();
|
|
8
11
|
walk(outline.nodes, (node) => {
|
package/dist/md/normalize.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeMarkdownInput = normalizeMarkdownInput;
|
|
1
4
|
/**
|
|
2
5
|
* Centralized normalization for Markdown input.
|
|
3
6
|
* Handles common LLM output artifacts like literal \n.
|
|
4
7
|
*/
|
|
5
|
-
|
|
8
|
+
function normalizeMarkdownInput(md) {
|
|
6
9
|
if (!md)
|
|
7
10
|
return "";
|
|
8
11
|
// Handle literal \n common in LLM outputs delivered via JSON
|
package/dist/md/outline.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildOutline = buildOutline;
|
|
4
|
+
exports.slugify = slugify;
|
|
5
|
+
const parse_js_1 = require("./parse.js");
|
|
2
6
|
/**
|
|
3
7
|
* Builds a nested tree of headings (outline) from Markdown text.
|
|
4
8
|
*/
|
|
5
|
-
|
|
6
|
-
const sections = parseHeadingsAndSections(md);
|
|
9
|
+
function buildOutline(md) {
|
|
10
|
+
const sections = (0, parse_js_1.parseHeadingsAndSections)(md);
|
|
7
11
|
const roots = [];
|
|
8
12
|
const stack = [];
|
|
9
13
|
for (const s of sections) {
|
|
@@ -35,7 +39,7 @@ export function buildOutline(md) {
|
|
|
35
39
|
/**
|
|
36
40
|
* Slugifies a string into an internal key.
|
|
37
41
|
*/
|
|
38
|
-
|
|
42
|
+
function slugify(text) {
|
|
39
43
|
return text
|
|
40
44
|
.toLowerCase()
|
|
41
45
|
.trim()
|
package/dist/md/parse.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeName = normalizeName;
|
|
4
|
+
exports.extractFencedBlocks = extractFencedBlocks;
|
|
5
|
+
exports.parseHeadingsAndSections = parseHeadingsAndSections;
|
|
6
|
+
exports.extractBullets = extractBullets;
|
|
7
|
+
exports.parseMarkdownTable = parseMarkdownTable;
|
|
8
|
+
exports.isIssuesEnvelopeCheck = isIssuesEnvelopeCheck;
|
|
9
|
+
exports.markdownToJson = markdownToJson;
|
|
10
|
+
const nx_helpers_1 = require("nx-helpers");
|
|
11
|
+
const normalize_js_1 = require("./normalize.js");
|
|
12
|
+
function normalizeName(s) {
|
|
4
13
|
return s.trim().replace(/\s+/g, " ").toLowerCase();
|
|
5
14
|
}
|
|
6
|
-
|
|
15
|
+
function extractFencedBlocks(text) {
|
|
7
16
|
const rx = /```(\w+)?\s*\n([\s\S]*?)\n```/g;
|
|
8
17
|
const blocks = [];
|
|
9
18
|
let m;
|
|
@@ -29,7 +38,7 @@ export function extractFencedBlocks(text) {
|
|
|
29
38
|
}
|
|
30
39
|
return blocks;
|
|
31
40
|
}
|
|
32
|
-
|
|
41
|
+
function parseHeadingsAndSections(md, options = {}) {
|
|
33
42
|
// Standard headings #... and alternative ===key.
|
|
34
43
|
// Also optionally allow "- Section" if specified in bulletNames.
|
|
35
44
|
const rx = /^((?:#{1,6})[ \t]+(.+?)[ \t]*|===(.+?)[ \t]*|([-*+])[ \t]+(.+?)[ \t]*)$/gm;
|
|
@@ -104,7 +113,7 @@ function nextLineIndex(text, idx) {
|
|
|
104
113
|
const n = text.indexOf("\n", idx);
|
|
105
114
|
return n === -1 ? text.length : n + 1;
|
|
106
115
|
}
|
|
107
|
-
|
|
116
|
+
function extractBullets(body) {
|
|
108
117
|
const lines = body.split(/\r?\n/);
|
|
109
118
|
const out = [];
|
|
110
119
|
for (const line of lines) {
|
|
@@ -114,7 +123,7 @@ export function extractBullets(body) {
|
|
|
114
123
|
}
|
|
115
124
|
return out;
|
|
116
125
|
}
|
|
117
|
-
|
|
126
|
+
function parseMarkdownTable(body, columns) {
|
|
118
127
|
const lines = body.split(/\r?\n/).map(l => l.trim()).filter(l => l.startsWith("|"));
|
|
119
128
|
if (lines.length < 2)
|
|
120
129
|
return [];
|
|
@@ -137,7 +146,7 @@ export function parseMarkdownTable(body, columns) {
|
|
|
137
146
|
}
|
|
138
147
|
return results;
|
|
139
148
|
}
|
|
140
|
-
|
|
149
|
+
function isIssuesEnvelopeCheck(md) {
|
|
141
150
|
const parsed = parseHeadingsAndSections(md);
|
|
142
151
|
const want = ["status", "issues", "expected", "found", "how to fix"].map(normalizeName);
|
|
143
152
|
const got = new Set(parsed.map(s => s.heading.norm));
|
|
@@ -156,9 +165,9 @@ export function isIssuesEnvelopeCheck(md) {
|
|
|
156
165
|
}
|
|
157
166
|
return { isIssuesEnvelope: ok, sections };
|
|
158
167
|
}
|
|
159
|
-
|
|
168
|
+
function markdownToJson(md) {
|
|
160
169
|
// Robustly handle both actual newlines and literal \n (common in LLM JSON outputs)
|
|
161
|
-
const normalizedMd = normalizeMarkdownInput(md);
|
|
170
|
+
const normalizedMd = (0, normalize_js_1.normalizeMarkdownInput)(md);
|
|
162
171
|
// Collect all bullet names that look like headers ("- Name")
|
|
163
172
|
// We look for patterns like "- Name\n" at the start of lines, ensuring it's not a sub-bullet.
|
|
164
173
|
const bulletNames = [];
|
|
@@ -171,7 +180,7 @@ export function markdownToJson(md) {
|
|
|
171
180
|
const sections = parseHeadingsAndSections(normalizedMd, { bulletNames });
|
|
172
181
|
const result = {};
|
|
173
182
|
for (const sec of sections) {
|
|
174
|
-
const key = toCamelCase(sec.heading.name);
|
|
183
|
+
const key = (0, nx_helpers_1.toCamelCase)(sec.heading.name);
|
|
175
184
|
const body = sec.body.trim();
|
|
176
185
|
// 1. Try to detect list
|
|
177
186
|
const bullets = extractBullets(body);
|
package/dist/ofs/adapter.js
CHANGED
|
@@ -1,38 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ofsToSchema = ofsToSchema;
|
|
4
|
+
exports.transformWithOfs = transformWithOfs;
|
|
5
|
+
const nx_md_parser_1 = require("nx-md-parser");
|
|
6
|
+
const memory_js_1 = require("./memory.js");
|
|
7
|
+
const parse_js_1 = require("../md/parse.js");
|
|
8
|
+
const normalize_js_1 = require("../md/normalize.js");
|
|
9
|
+
const nx_helpers_1 = require("nx-helpers");
|
|
10
|
+
const nx_json_parser_1 = require("nx-json-parser");
|
|
11
|
+
const logger_js_1 = require("../logger.js");
|
|
8
12
|
/**
|
|
9
13
|
* Converts a Flex-MD OutputFormatSpec to an nx-md-parser Schema.
|
|
10
14
|
*/
|
|
11
|
-
|
|
15
|
+
function ofsToSchema(spec) {
|
|
12
16
|
const properties = {};
|
|
13
17
|
for (const section of spec.sections) {
|
|
14
18
|
let type;
|
|
15
19
|
switch (section.kind) {
|
|
16
20
|
case "list":
|
|
17
21
|
case "ordered_list":
|
|
18
|
-
type = Schema.array(Schema.string());
|
|
22
|
+
type = nx_md_parser_1.Schema.array(nx_md_parser_1.Schema.string());
|
|
19
23
|
break;
|
|
20
24
|
case "table":
|
|
21
25
|
case "ordered_table":
|
|
22
26
|
if (section.columns && section.columns.length > 0) {
|
|
23
27
|
const rowProps = {};
|
|
24
28
|
for (const col of section.columns) {
|
|
25
|
-
rowProps[col] = Schema.string();
|
|
29
|
+
rowProps[col] = nx_md_parser_1.Schema.string();
|
|
26
30
|
}
|
|
27
|
-
type = Schema.array(Schema.object(rowProps));
|
|
31
|
+
type = nx_md_parser_1.Schema.array(nx_md_parser_1.Schema.object(rowProps));
|
|
28
32
|
}
|
|
29
33
|
else {
|
|
30
|
-
type = Schema.string();
|
|
34
|
+
type = nx_md_parser_1.Schema.string();
|
|
31
35
|
}
|
|
32
36
|
break;
|
|
33
37
|
case "text":
|
|
34
38
|
default:
|
|
35
|
-
type = Schema.string();
|
|
39
|
+
type = nx_md_parser_1.Schema.string();
|
|
36
40
|
break;
|
|
37
41
|
}
|
|
38
42
|
properties[section.name] = type;
|
|
@@ -42,39 +46,39 @@ export function ofsToSchema(spec) {
|
|
|
42
46
|
const tableKey = table.columns.join("_");
|
|
43
47
|
const rowProps = {};
|
|
44
48
|
for (const col of table.columns) {
|
|
45
|
-
rowProps[col] = Schema.string();
|
|
49
|
+
rowProps[col] = nx_md_parser_1.Schema.string();
|
|
46
50
|
}
|
|
47
|
-
properties[tableKey] = Schema.array(Schema.object(rowProps));
|
|
51
|
+
properties[tableKey] = nx_md_parser_1.Schema.array(nx_md_parser_1.Schema.object(rowProps));
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
|
-
return Schema.object(properties);
|
|
54
|
+
return nx_md_parser_1.Schema.object(properties);
|
|
51
55
|
}
|
|
52
56
|
/**
|
|
53
57
|
* Transforms markdown text using a Flex-MD OutputFormatSpec or a recallId.
|
|
54
58
|
* If no spec is provided, it attempts to infer it from the markdown (autospecs).
|
|
55
59
|
*/
|
|
56
|
-
|
|
57
|
-
logger.info("Starting Flex-MD transformation", {
|
|
60
|
+
function transformWithOfs(md, specOrRecallId) {
|
|
61
|
+
logger_js_1.logger.info("Starting Flex-MD transformation", {
|
|
58
62
|
inputLength: md.length,
|
|
59
63
|
hasSpec: !!specOrRecallId,
|
|
60
64
|
specType: specOrRecallId ? typeof specOrRecallId : 'none'
|
|
61
65
|
});
|
|
62
66
|
// 0. Normalize input (handle literal \n common in LLM outputs)
|
|
63
|
-
const normalizedMd = normalizeMarkdownInput(md);
|
|
64
|
-
logger.debug("Input normalization", {
|
|
67
|
+
const normalizedMd = (0, normalize_js_1.normalizeMarkdownInput)(md);
|
|
68
|
+
logger_js_1.logger.debug("Input normalization", {
|
|
65
69
|
originalLength: md.length,
|
|
66
70
|
normalizedLength: normalizedMd.length,
|
|
67
71
|
changed: md !== normalizedMd
|
|
68
72
|
});
|
|
69
73
|
// 1. Automatic parsing (Dual-Response) using nx-json-parser
|
|
70
|
-
logger.debug("Starting automatic parsing with nx-json-parser");
|
|
71
|
-
const parsedOutput =
|
|
72
|
-
logger.debug("Automatic parsing completed", {
|
|
74
|
+
logger_js_1.logger.debug("Starting automatic parsing with nx-json-parser");
|
|
75
|
+
const parsedOutput = (0, nx_json_parser_1.markdownToJson)(normalizedMd);
|
|
76
|
+
logger_js_1.logger.debug("Automatic parsing completed", {
|
|
73
77
|
parsedKeys: Object.keys(parsedOutput),
|
|
74
78
|
parsedKeyCount: Object.keys(parsedOutput).length
|
|
75
79
|
});
|
|
76
80
|
if (!specOrRecallId) {
|
|
77
|
-
logger.info("No spec provided, returning parsed output only");
|
|
81
|
+
logger_js_1.logger.info("No spec provided, returning parsed output only");
|
|
78
82
|
return {
|
|
79
83
|
parsedOutput,
|
|
80
84
|
contractOutput: null,
|
|
@@ -85,10 +89,10 @@ export function transformWithOfs(md, specOrRecallId) {
|
|
|
85
89
|
}
|
|
86
90
|
let spec;
|
|
87
91
|
if (typeof specOrRecallId === "string") {
|
|
88
|
-
logger.debug("Recalling spec from memory", { recallId: specOrRecallId });
|
|
89
|
-
const recalled = recall(specOrRecallId);
|
|
92
|
+
logger_js_1.logger.debug("Recalling spec from memory", { recallId: specOrRecallId });
|
|
93
|
+
const recalled = (0, memory_js_1.recall)(specOrRecallId);
|
|
90
94
|
if (!recalled) {
|
|
91
|
-
logger.warn("Recall ID not found", { recallId: specOrRecallId });
|
|
95
|
+
logger_js_1.logger.warn("Recall ID not found", { recallId: specOrRecallId });
|
|
92
96
|
return {
|
|
93
97
|
parsedOutput,
|
|
94
98
|
contractOutput: null,
|
|
@@ -98,35 +102,35 @@ export function transformWithOfs(md, specOrRecallId) {
|
|
|
98
102
|
};
|
|
99
103
|
}
|
|
100
104
|
spec = recalled;
|
|
101
|
-
logger.debug("Spec recalled successfully", {
|
|
105
|
+
logger_js_1.logger.debug("Spec recalled successfully", {
|
|
102
106
|
sectionCount: spec.sections.length,
|
|
103
107
|
sectionNames: spec.sections.map(s => s.name)
|
|
104
108
|
});
|
|
105
109
|
}
|
|
106
110
|
else {
|
|
107
111
|
spec = specOrRecallId;
|
|
108
|
-
logger.debug("Using provided spec directly", {
|
|
112
|
+
logger_js_1.logger.debug("Using provided spec directly", {
|
|
109
113
|
sectionCount: spec.sections.length,
|
|
110
114
|
sectionNames: spec.sections.map(s => s.name)
|
|
111
115
|
});
|
|
112
116
|
}
|
|
113
117
|
// 2. Parse sections using Flex-MD parser for the contract mapping
|
|
114
118
|
const bulletNames = spec.sections.map(s => s.name);
|
|
115
|
-
logger.debug("Starting section parsing", {
|
|
119
|
+
logger_js_1.logger.debug("Starting section parsing", {
|
|
116
120
|
expectedSections: bulletNames,
|
|
117
121
|
sectionCount: bulletNames.length
|
|
118
122
|
});
|
|
119
123
|
// Note: We use the local headings parser to find the specific sections defined in the spec
|
|
120
|
-
const parsedSections = parseHeadingsAndSections(normalizedMd, { bulletNames });
|
|
121
|
-
logger.debug("Section parsing completed", {
|
|
124
|
+
const parsedSections = (0, parse_js_1.parseHeadingsAndSections)(normalizedMd, { bulletNames });
|
|
125
|
+
logger_js_1.logger.debug("Section parsing completed", {
|
|
122
126
|
foundSections: parsedSections.map(s => s.heading.name),
|
|
123
127
|
foundCount: parsedSections.length
|
|
124
128
|
});
|
|
125
129
|
const parsedObj = {};
|
|
126
130
|
for (const sectionSpec of spec.sections) {
|
|
127
|
-
const normName = normalizeName(sectionSpec.name);
|
|
128
|
-
const found = parsedSections.find(s => normalizeName(s.heading.name) === normName);
|
|
129
|
-
logger.verbose(`Processing section "${sectionSpec.name}"`, {
|
|
131
|
+
const normName = (0, parse_js_1.normalizeName)(sectionSpec.name);
|
|
132
|
+
const found = parsedSections.find(s => (0, parse_js_1.normalizeName)(s.heading.name) === normName);
|
|
133
|
+
logger_js_1.logger.verbose(`Processing section "${sectionSpec.name}"`, {
|
|
130
134
|
normalizedName: normName,
|
|
131
135
|
found: !!found,
|
|
132
136
|
kind: sectionSpec.kind,
|
|
@@ -137,47 +141,47 @@ export function transformWithOfs(md, specOrRecallId) {
|
|
|
137
141
|
switch (sectionSpec.kind) {
|
|
138
142
|
case "list":
|
|
139
143
|
case "ordered_list":
|
|
140
|
-
value = extractBullets(found.body);
|
|
141
|
-
logger.debug(`Extracted bullets for "${sectionSpec.name}"`, {
|
|
144
|
+
value = (0, parse_js_1.extractBullets)(found.body);
|
|
145
|
+
logger_js_1.logger.debug(`Extracted bullets for "${sectionSpec.name}"`, {
|
|
142
146
|
bulletCount: Array.isArray(value) ? value.length : 'unknown'
|
|
143
147
|
});
|
|
144
148
|
break;
|
|
145
149
|
case "table":
|
|
146
150
|
case "ordered_table":
|
|
147
151
|
if (sectionSpec.columns) {
|
|
148
|
-
value = parseMarkdownTable(found.body, sectionSpec.columns);
|
|
149
|
-
logger.debug(`Parsed table for "${sectionSpec.name}"`, {
|
|
152
|
+
value = (0, parse_js_1.parseMarkdownTable)(found.body, sectionSpec.columns);
|
|
153
|
+
logger_js_1.logger.debug(`Parsed table for "${sectionSpec.name}"`, {
|
|
150
154
|
columns: sectionSpec.columns,
|
|
151
155
|
rowCount: Array.isArray(value) ? value.length : 'unknown'
|
|
152
156
|
});
|
|
153
157
|
}
|
|
154
158
|
else {
|
|
155
159
|
value = found.body.trim();
|
|
156
|
-
logger.debug(`Using raw body for table "${sectionSpec.name}" (no columns specified)`);
|
|
160
|
+
logger_js_1.logger.debug(`Using raw body for table "${sectionSpec.name}" (no columns specified)`);
|
|
157
161
|
}
|
|
158
162
|
break;
|
|
159
163
|
default:
|
|
160
164
|
value = found.body.trim();
|
|
161
|
-
logger.debug(`Using trimmed body for "${sectionSpec.name}"`);
|
|
165
|
+
logger_js_1.logger.debug(`Using trimmed body for "${sectionSpec.name}"`);
|
|
162
166
|
break;
|
|
163
167
|
}
|
|
164
168
|
parsedObj[sectionSpec.name] = value;
|
|
165
169
|
}
|
|
166
170
|
else {
|
|
167
|
-
logger.warn(`Section "${sectionSpec.name}" not found in markdown`);
|
|
171
|
+
logger_js_1.logger.warn(`Section "${sectionSpec.name}" not found in markdown`);
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
|
-
logger.debug("Contract parsing completed", {
|
|
174
|
+
logger_js_1.logger.debug("Contract parsing completed", {
|
|
171
175
|
parsedKeys: Object.keys(parsedObj),
|
|
172
176
|
parsedKeyCount: Object.keys(parsedObj).length
|
|
173
177
|
});
|
|
174
178
|
// 3. Transform using nx-md-parser (latest v2.2.0) for schema validation and fixing
|
|
175
179
|
const schema = ofsToSchema(spec);
|
|
176
|
-
const transformer = new JSONTransformer(schema);
|
|
180
|
+
const transformer = new nx_md_parser_1.JSONTransformer(schema);
|
|
177
181
|
const transformResult = transformer.transform(parsedObj);
|
|
178
182
|
// 4. Compare parsed results with contract results
|
|
179
183
|
const autoKeys = Object.keys(parsedOutput).sort();
|
|
180
|
-
const contractKeys = transformResult.result ? Object.keys(transformResult.result).map(k => toCamelCase(k)).sort() : [];
|
|
184
|
+
const contractKeys = transformResult.result ? Object.keys(transformResult.result).map(k => (0, nx_helpers_1.toCamelCase)(k)).sort() : [];
|
|
181
185
|
const isSame = autoKeys.length > 0 &&
|
|
182
186
|
autoKeys.every(k => contractKeys.includes(k)) &&
|
|
183
187
|
contractKeys.length === autoKeys.length;
|