flex-md 4.7.2 → 4.7.4
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/README.md +1 -1
- package/dist/__tests__/diagnostics.test.js +45 -47
- package/dist/__tests__/ofs.test.js +28 -30
- package/dist/__tests__/structural.test.js +19 -21
- package/dist/__tests__/validate.test.js +27 -29
- package/dist/cli/index.js +13 -15
- package/dist/detect/json/detectIntent.js +1 -4
- package/dist/detect/json/detectMarkdown.js +29 -35
- package/dist/detect/json/detectPresence.js +2 -6
- package/dist/detect/json/index.js +10 -31
- package/dist/detect/json/types.js +1 -2
- package/dist/extract/extract.js +11 -14
- package/dist/extract/types.js +1 -2
- package/dist/index.js +22 -69
- package/dist/logger.js +3 -6
- package/dist/md/match.js +1 -4
- package/dist/md/normalize.js +1 -4
- package/dist/md/outline.js +4 -8
- package/dist/md/parse.js +11 -20
- package/dist/ofs/adapter.js +45 -49
- package/dist/ofs/enricher.js +3 -8
- package/dist/ofs/infer.js +4 -7
- package/dist/ofs/issuesEnvelope.js +5 -10
- package/dist/ofs/memory.js +6 -10
- package/dist/ofs/parser.js +7 -13
- package/dist/ofs/stringify.js +1 -4
- package/dist/pipeline/enforce.js +12 -15
- package/dist/pipeline/kind.js +3 -6
- package/dist/pipeline/repair.js +8 -11
- package/dist/strictness/container.js +1 -4
- package/dist/strictness/processor.js +7 -10
- package/dist/strictness/types.js +1 -4
- package/dist/tokens/auto-fix.js +1 -4
- package/dist/tokens/cognitive-cost.js +6 -10
- package/dist/tokens/compliance.js +4 -8
- package/dist/tokens/confidence.js +6 -9
- package/dist/tokens/estimator.js +20 -26
- package/dist/tokens/improvements.js +12 -16
- package/dist/tokens/index.js +22 -40
- package/dist/tokens/parser.js +4 -7
- package/dist/tokens/patterns.js +2 -5
- package/dist/tokens/runtime-estimator.js +9 -12
- package/dist/tokens/smart-report.js +10 -14
- package/dist/tokens/spec-estimator.js +10 -15
- package/dist/tokens/types.js +1 -2
- package/dist/tokens/validator.js +3 -6
- package/dist/types.js +1 -2
- package/dist/validate/compliance.js +4 -8
- package/dist/validate/connection.js +5 -8
- package/dist/validate/types.js +1 -2
- package/dist/validate/validate.js +16 -19
- package/dist-cjs/__tests__/diagnostics.test.cjs +61 -0
- package/dist-cjs/__tests__/ofs.test.cjs +53 -0
- package/dist-cjs/__tests__/structural.test.cjs +30 -0
- package/dist-cjs/__tests__/validate.test.cjs +110 -0
- package/dist-cjs/cli/index.cjs +110 -0
- package/dist-cjs/detect/json/detectIntent.cjs +82 -0
- package/dist-cjs/detect/json/detectMarkdown.cjs +304 -0
- package/dist-cjs/detect/json/detectPresence.cjs +195 -0
- package/dist-cjs/detect/json/index.cjs +34 -0
- package/dist-cjs/detect/json/types.cjs +2 -0
- package/dist-cjs/extract/extract.cjs +72 -0
- package/dist-cjs/extract/types.cjs +2 -0
- package/dist-cjs/flex-md-loader.cjs +102 -0
- package/dist-cjs/index.cjs +79 -0
- package/dist-cjs/logger.cjs +22 -0
- package/dist-cjs/md/match.cjs +47 -0
- package/dist-cjs/md/normalize.cjs +13 -0
- package/dist-cjs/md/outline.cjs +49 -0
- package/dist-cjs/md/parse.cjs +199 -0
- package/dist-cjs/ofs/adapter.cjs +195 -0
- package/dist-cjs/ofs/enricher.cjs +151 -0
- package/dist-cjs/ofs/infer.cjs +63 -0
- package/dist-cjs/ofs/issuesEnvelope.cjs +76 -0
- package/dist-cjs/ofs/memory.cjs +26 -0
- package/dist-cjs/ofs/parser.cjs +373 -0
- package/dist-cjs/ofs/stringify.cjs +45 -0
- package/dist-cjs/pipeline/enforce.cjs +49 -0
- package/dist-cjs/pipeline/kind.cjs +30 -0
- package/dist-cjs/pipeline/repair.cjs +115 -0
- package/dist-cjs/strictness/container.cjs +49 -0
- package/dist-cjs/strictness/processor.cjs +32 -0
- package/dist-cjs/strictness/types.cjs +109 -0
- package/dist-cjs/tokens/auto-fix.cjs +59 -0
- package/dist-cjs/tokens/cognitive-cost.cjs +209 -0
- package/dist-cjs/tokens/compliance.cjs +74 -0
- package/dist-cjs/tokens/confidence.cjs +335 -0
- package/dist-cjs/tokens/estimator.cjs +157 -0
- package/dist-cjs/tokens/improvements.cjs +701 -0
- package/dist-cjs/tokens/index.cjs +74 -0
- package/dist-cjs/tokens/parser.cjs +100 -0
- package/dist-cjs/tokens/patterns.cjs +23 -0
- package/dist-cjs/tokens/runtime-estimator.cjs +74 -0
- package/dist-cjs/tokens/smart-report.cjs +191 -0
- package/dist-cjs/tokens/spec-estimator.cjs +125 -0
- package/dist-cjs/tokens/types.cjs +2 -0
- package/dist-cjs/tokens/validator.cjs +62 -0
- package/dist-cjs/types.cjs +2 -0
- package/dist-cjs/validate/compliance.cjs +103 -0
- package/dist-cjs/validate/connection.cjs +47 -0
- package/dist-cjs/validate/types.cjs +2 -0
- package/dist-cjs/validate/validate.cjs +319 -0
- package/docs/consumption.md +1 -1
- package/package.json +14 -8
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectJsonContainers = detectJsonContainers;
|
|
4
|
+
exports.detectJsonPresence = detectJsonPresence;
|
|
5
|
+
const RX_JSON_FENCE = /```json\s*\n([\s\S]*?)\n```/gi;
|
|
6
|
+
const RX_JSON_MARKER = /(BEGIN_JSON|BEGIN\s+JSON)\s*\n([\s\S]*?)\n(END_JSON|END\s+JSON)/gi;
|
|
7
|
+
// Very conservative raw JSON: must be only whitespace + object/array + whitespace
|
|
8
|
+
const RX_RAW_JSON = /^\s*(\{[\s\S]*\}|\[[\s\S]*\])\s*$/;
|
|
9
|
+
// Inline candidate finder
|
|
10
|
+
const RX_INLINE_CANDIDATE = /(\{|\[)/g;
|
|
11
|
+
function detectJsonContainers(md) {
|
|
12
|
+
const fences = [];
|
|
13
|
+
const markers = [];
|
|
14
|
+
RX_JSON_FENCE.lastIndex = 0;
|
|
15
|
+
RX_JSON_MARKER.lastIndex = 0;
|
|
16
|
+
let m;
|
|
17
|
+
while ((m = RX_JSON_FENCE.exec(md)) !== null) {
|
|
18
|
+
fences.push({
|
|
19
|
+
start: m.index,
|
|
20
|
+
end: m.index + m[0].length,
|
|
21
|
+
kind: "fence",
|
|
22
|
+
snippet: preview(m[0]),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
while ((m = RX_JSON_MARKER.exec(md)) !== null) {
|
|
26
|
+
markers.push({
|
|
27
|
+
start: m.index,
|
|
28
|
+
end: m.index + m[0].length,
|
|
29
|
+
kind: "marker",
|
|
30
|
+
snippet: preview(m[0]),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
hasJsonFence: fences.length > 0,
|
|
35
|
+
hasJsonMarkers: markers.length > 0,
|
|
36
|
+
fences,
|
|
37
|
+
markers,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function detectJsonPresence(text, opts) {
|
|
41
|
+
const spans = [];
|
|
42
|
+
const kinds = new Set();
|
|
43
|
+
// 1) fenced json blocks
|
|
44
|
+
let m;
|
|
45
|
+
RX_JSON_FENCE.lastIndex = 0;
|
|
46
|
+
while ((m = RX_JSON_FENCE.exec(text)) !== null) {
|
|
47
|
+
kinds.add("fenced_json");
|
|
48
|
+
spans.push({
|
|
49
|
+
start: m.index,
|
|
50
|
+
end: m.index + m[0].length,
|
|
51
|
+
kind: "fence",
|
|
52
|
+
snippet: preview(m[0]),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// 2) BEGIN_JSON / END_JSON
|
|
56
|
+
RX_JSON_MARKER.lastIndex = 0;
|
|
57
|
+
while ((m = RX_JSON_MARKER.exec(text)) !== null) {
|
|
58
|
+
kinds.add("fenced_json");
|
|
59
|
+
spans.push({
|
|
60
|
+
start: m.index,
|
|
61
|
+
end: m.index + m[0].length,
|
|
62
|
+
kind: "marker",
|
|
63
|
+
snippet: preview(m[0]),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// 3) raw json (standalone)
|
|
67
|
+
if (RX_RAW_JSON.test(text) && looksLikeJson(text)) {
|
|
68
|
+
kinds.add("raw_json");
|
|
69
|
+
spans.push({ start: 0, end: text.length, kind: "raw", snippet: preview(text) });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// 4) inline json-ish occurrences (best effort)
|
|
73
|
+
const inlineSpans = findInlineJsonishSpans(text);
|
|
74
|
+
if (inlineSpans.length) {
|
|
75
|
+
kinds.add("inline_json");
|
|
76
|
+
for (const s of inlineSpans)
|
|
77
|
+
spans.push(s);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const present = kinds.size > 0;
|
|
81
|
+
// Optional parse
|
|
82
|
+
const parse = !!opts?.parse;
|
|
83
|
+
if (!parse || !present) {
|
|
84
|
+
return { present, kinds: Array.from(kinds), spans };
|
|
85
|
+
}
|
|
86
|
+
const maxParses = opts?.maxParses ?? 3;
|
|
87
|
+
const parsedValues = [];
|
|
88
|
+
const errors = [];
|
|
89
|
+
const parseCandidates = spans
|
|
90
|
+
.map((s, i) => ({ s, i }))
|
|
91
|
+
.filter(x => x.s.kind === "fence" || x.s.kind === "raw" || x.s.kind === "inline")
|
|
92
|
+
.slice(0, maxParses);
|
|
93
|
+
for (const { s, i } of parseCandidates) {
|
|
94
|
+
const content = extractJsonText(text, s);
|
|
95
|
+
try {
|
|
96
|
+
parsedValues.push(JSON.parse(content));
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
errors.push({ spanIndex: i, message: String(e?.message ?? e) });
|
|
100
|
+
if (looksLikeJson(content))
|
|
101
|
+
kinds.add("json_like");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
present,
|
|
106
|
+
kinds: Array.from(kinds),
|
|
107
|
+
spans,
|
|
108
|
+
parsed: {
|
|
109
|
+
ok: errors.length === 0 && parsedValues.length > 0,
|
|
110
|
+
values: parsedValues,
|
|
111
|
+
errors: errors.length ? errors : undefined,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function extractJsonText(full, span) {
|
|
116
|
+
const slice = full.slice(span.start, span.end);
|
|
117
|
+
if (span.kind === "fence") {
|
|
118
|
+
const m = slice.match(/^```json\s*\n([\s\S]*?)\n```$/i);
|
|
119
|
+
if (m)
|
|
120
|
+
return m[1] ?? "";
|
|
121
|
+
}
|
|
122
|
+
if (span.kind === "marker") {
|
|
123
|
+
const m = slice.match(/(BEGIN_JSON|BEGIN\s+JSON)\s*\n([\s\S]*?)\n(END_JSON|END\s+JSON)/i);
|
|
124
|
+
if (m)
|
|
125
|
+
return m[2] ?? "";
|
|
126
|
+
}
|
|
127
|
+
return slice;
|
|
128
|
+
}
|
|
129
|
+
function looksLikeJson(s) {
|
|
130
|
+
const t = s.trim();
|
|
131
|
+
if (!t)
|
|
132
|
+
return false;
|
|
133
|
+
if ((t.startsWith("{") && t.endsWith("}")) || (t.startsWith("[") && t.endsWith("]")))
|
|
134
|
+
return true;
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
function findInlineJsonishSpans(text) {
|
|
138
|
+
const spans = [];
|
|
139
|
+
const maxLen = 5000;
|
|
140
|
+
const masked = maskNonJsonCodeFences(text);
|
|
141
|
+
let m;
|
|
142
|
+
RX_INLINE_CANDIDATE.lastIndex = 0;
|
|
143
|
+
while ((m = RX_INLINE_CANDIDATE.exec(masked)) !== null) {
|
|
144
|
+
const start = m.index;
|
|
145
|
+
const open = masked[start];
|
|
146
|
+
const close = open === "{" ? "}" : "]";
|
|
147
|
+
let depth = 0;
|
|
148
|
+
let end = -1;
|
|
149
|
+
for (let i = start; i < Math.min(masked.length, start + maxLen); i++) {
|
|
150
|
+
const ch = masked[i];
|
|
151
|
+
if (ch === open)
|
|
152
|
+
depth++;
|
|
153
|
+
else if (ch === close) {
|
|
154
|
+
depth--;
|
|
155
|
+
if (depth === 0) {
|
|
156
|
+
end = i + 1;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (end > start) {
|
|
162
|
+
const snippet = text.slice(start, Math.min(end, start + 300));
|
|
163
|
+
if (snippet.trim().length >= 5) {
|
|
164
|
+
spans.push({ start, end, kind: "inline", snippet: preview(text.slice(start, end)) });
|
|
165
|
+
}
|
|
166
|
+
RX_INLINE_CANDIDATE.lastIndex = end;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return squashOverlaps(spans);
|
|
170
|
+
}
|
|
171
|
+
function maskNonJsonCodeFences(text) {
|
|
172
|
+
const rx = /```(\w+)?\s*\n([\s\S]*?)\n```/g;
|
|
173
|
+
return text.replace(rx, (full, lang) => {
|
|
174
|
+
const l = String(lang ?? "").toLowerCase();
|
|
175
|
+
if (l === "json")
|
|
176
|
+
return full;
|
|
177
|
+
return " ".repeat(full.length);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function squashOverlaps(spans) {
|
|
181
|
+
spans.sort((a, b) => a.start - b.start || (b.end - b.start) - (a.end - a.start));
|
|
182
|
+
const out = [];
|
|
183
|
+
let last = null;
|
|
184
|
+
for (const s of spans) {
|
|
185
|
+
if (!last || s.start >= last.end) {
|
|
186
|
+
out.push(s);
|
|
187
|
+
last = s;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
function preview(s, n = 160) {
|
|
193
|
+
const t = s.replace(/\s+/g, " ").trim();
|
|
194
|
+
return t.length > n ? t.slice(0, n - 1) + "…" : t;
|
|
195
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
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.cjs");
|
|
20
|
+
const detectPresence_js_1 = require("./detectPresence.cjs");
|
|
21
|
+
__exportStar(require("./types.cjs"), exports);
|
|
22
|
+
var detectIntent_js_2 = require("./detectIntent.cjs");
|
|
23
|
+
Object.defineProperty(exports, "detectJsonIntent", { enumerable: true, get: function () { return detectIntent_js_2.detectJsonIntent; } });
|
|
24
|
+
var detectPresence_js_2 = require("./detectPresence.cjs");
|
|
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.cjs"), exports);
|
|
28
|
+
function detectJsonAll(textOrMd, opts) {
|
|
29
|
+
return {
|
|
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 }),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractFromMarkdown = extractFromMarkdown;
|
|
4
|
+
const parse_js_1 = require("../md/parse.cjs");
|
|
5
|
+
/**
|
|
6
|
+
* Extracts sections, lists, and tables from Markdown based on the OFS.
|
|
7
|
+
*/
|
|
8
|
+
function extractFromMarkdown(md, spec) {
|
|
9
|
+
// 0. Robustness: check for fenced block that might contain the target content
|
|
10
|
+
// Highly relevant for LLM responses where the model occasionally wraps everything in a container
|
|
11
|
+
// even if not strictly asked, or if the user provided unframed content but we have L2+ expectations elsewhere.
|
|
12
|
+
const rxFence = /```(?:markdown|flexmd)?\s*\n([\s\S]*?)\n```/gi;
|
|
13
|
+
const matches = Array.from(md.matchAll(rxFence));
|
|
14
|
+
let workingContent = md;
|
|
15
|
+
if (matches.length === 1) {
|
|
16
|
+
const content = matches[0][1];
|
|
17
|
+
// If the content inside the fence has more required sections than outside, use it
|
|
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;
|
|
23
|
+
if (countInside >= countOutside && countInside > 0) {
|
|
24
|
+
workingContent = content;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const bulletNames = spec.sections.map(s => s.name);
|
|
28
|
+
const parsed = (0, parse_js_1.parseHeadingsAndSections)(workingContent, { bulletNames });
|
|
29
|
+
const sectionsByName = {};
|
|
30
|
+
const tables = [];
|
|
31
|
+
const specMap = new Map(spec.sections.map(s => [(0, parse_js_1.normalizeName)(s.name), s]));
|
|
32
|
+
for (const p of parsed) {
|
|
33
|
+
const norm = (0, parse_js_1.normalizeName)(p.heading.name);
|
|
34
|
+
const sSpec = specMap.get(norm);
|
|
35
|
+
if (sSpec) {
|
|
36
|
+
const body = p.body.trim();
|
|
37
|
+
let list;
|
|
38
|
+
if (sSpec.kind === "list" || sSpec.kind === "ordered_list") {
|
|
39
|
+
const bullets = (0, parse_js_1.extractBullets)(body);
|
|
40
|
+
if (bullets.length > 0) {
|
|
41
|
+
list = {
|
|
42
|
+
kind: "list",
|
|
43
|
+
ordered: sSpec.kind === "ordered_list",
|
|
44
|
+
items: bullets.map(b => ({ text: b, children: [] }))
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Merge if duplicate heading (standard policy for extraction)
|
|
49
|
+
if (sectionsByName[sSpec.name]) {
|
|
50
|
+
sectionsByName[sSpec.name].md += "\n\n" + body;
|
|
51
|
+
if (list && sectionsByName[sSpec.name].list) {
|
|
52
|
+
sectionsByName[sSpec.name].list.items.push(...list.items);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
sectionsByName[sSpec.name] = {
|
|
57
|
+
nodeKey: norm,
|
|
58
|
+
nodeLevel: p.heading.level,
|
|
59
|
+
md: body,
|
|
60
|
+
list
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Table extraction logic (simplified for now)
|
|
66
|
+
// In a full impl, we'd search section bodies for tables.
|
|
67
|
+
return {
|
|
68
|
+
outline: { type: "md_outline", nodes: [] }, // Simplified outline
|
|
69
|
+
sectionsByName,
|
|
70
|
+
tables
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Flex-MD Loader - ES Module Compatible Dynamic Import
|
|
4
|
+
*
|
|
5
|
+
* This module provides ES module compatible dynamic loading of the flex-md library,
|
|
6
|
+
* handling the case where dependencies might use require() in ES module environments.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.extractJsonFromFlexMd = extractJsonFromFlexMd;
|
|
10
|
+
exports.extractWithOfs = extractWithOfs;
|
|
11
|
+
exports.loadFlexMd = loadFlexMd;
|
|
12
|
+
/**
|
|
13
|
+
* Dynamically loads the flex-md library with ES module compatibility.
|
|
14
|
+
* Handles both ES module and CommonJS loading patterns.
|
|
15
|
+
*/
|
|
16
|
+
async function loadFlexMd() {
|
|
17
|
+
try {
|
|
18
|
+
// First, try direct ES module import (preferred for modern environments)
|
|
19
|
+
const flexMdModule = await Promise.resolve().then(() => require('flex-md'));
|
|
20
|
+
return flexMdModule;
|
|
21
|
+
}
|
|
22
|
+
catch (esError) {
|
|
23
|
+
try {
|
|
24
|
+
// Fallback: Use Node.js createRequire for CommonJS compatibility
|
|
25
|
+
// This handles cases where flex-md or its dependencies use require()
|
|
26
|
+
const { createRequire } = await Promise.resolve().then(() => require('module'));
|
|
27
|
+
const require = createRequire(import.meta.url);
|
|
28
|
+
const flexMdModule = require('flex-md');
|
|
29
|
+
return flexMdModule;
|
|
30
|
+
}
|
|
31
|
+
catch (cjsError) {
|
|
32
|
+
// If both fail, try the dynamic Function approach as last resort
|
|
33
|
+
try {
|
|
34
|
+
const importFunc = new Function('specifier', 'return import(specifier)');
|
|
35
|
+
const flexMdModule = await importFunc('flex-md');
|
|
36
|
+
return flexMdModule;
|
|
37
|
+
}
|
|
38
|
+
catch (dynamicError) {
|
|
39
|
+
throw new Error(`flex-md import failed: ES module error: ${esError instanceof Error ? esError.message : String(esError)}, ` +
|
|
40
|
+
`CommonJS fallback error: ${cjsError instanceof Error ? cjsError.message : String(cjsError)}, ` +
|
|
41
|
+
`Dynamic import error: ${dynamicError instanceof Error ? dynamicError.message : String(dynamicError)}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extracts structured JSON from markdown content using flex-md.
|
|
48
|
+
*
|
|
49
|
+
* @param content - The markdown content to parse
|
|
50
|
+
* @param spec - Optional Output Format Specification
|
|
51
|
+
* @param options - Extraction options
|
|
52
|
+
* @returns Promise resolving to extraction result
|
|
53
|
+
*/
|
|
54
|
+
async function extractJsonFromFlexMd(content, spec, options = {}) {
|
|
55
|
+
try {
|
|
56
|
+
// Load flex-md library with compatibility handling
|
|
57
|
+
const flexMd = await loadFlexMd();
|
|
58
|
+
// Use the markdownToJson function for basic structured extraction
|
|
59
|
+
// This handles markdown with sections like # Short answer, # Full answer, etc.
|
|
60
|
+
const json = flexMd.markdownToJson(content);
|
|
61
|
+
return {
|
|
62
|
+
json,
|
|
63
|
+
success: true
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.warn('Flex-md extraction failed - flex-md library compatibility issue');
|
|
68
|
+
console.warn('Error:', error instanceof Error ? error.message : String(error));
|
|
69
|
+
console.warn('Issue: flex-md uses require() in ES module context - needs fixing in flex-md-loader.ts');
|
|
70
|
+
return {
|
|
71
|
+
json: { rawText: content },
|
|
72
|
+
success: false,
|
|
73
|
+
error: error instanceof Error ? error.message : 'Unknown extraction error'
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Alternative extraction using transformWithOfs if a spec is provided.
|
|
79
|
+
* This provides more structured extraction when an Output Format Spec is available.
|
|
80
|
+
*/
|
|
81
|
+
async function extractWithOfs(content, spec, options = {}) {
|
|
82
|
+
try {
|
|
83
|
+
const flexMd = await loadFlexMd();
|
|
84
|
+
// If spec is provided, use the more advanced transformWithOfs
|
|
85
|
+
if (spec && flexMd.transformWithOfs) {
|
|
86
|
+
const result = flexMd.transformWithOfs(content, spec);
|
|
87
|
+
return {
|
|
88
|
+
json: result,
|
|
89
|
+
success: true
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Fallback to basic markdownToJson
|
|
94
|
+
return extractJsonFromFlexMd(content, spec, options);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.warn('Flex-md OFS extraction failed:', error instanceof Error ? error.message : String(error));
|
|
99
|
+
// Fallback to basic extraction
|
|
100
|
+
return extractJsonFromFlexMd(content, spec, options);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
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.parseFormatSpecs = exports.parseInputFormatSpec = exports.parseOutputFormatSpec = exports.buildOutline = exports.logger = void 0;
|
|
18
|
+
// Core SFMD Types
|
|
19
|
+
__exportStar(require("./types.cjs"), exports);
|
|
20
|
+
__exportStar(require("./strictness/types.cjs"), exports);
|
|
21
|
+
// Logging
|
|
22
|
+
var logger_js_1 = require("./logger.cjs");
|
|
23
|
+
Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_js_1.logger; } });
|
|
24
|
+
// Shared MD Parsing
|
|
25
|
+
__exportStar(require("./md/parse.cjs"), exports);
|
|
26
|
+
var outline_js_1 = require("./md/outline.cjs");
|
|
27
|
+
Object.defineProperty(exports, "buildOutline", { enumerable: true, get: function () { return outline_js_1.buildOutline; } });
|
|
28
|
+
// Output Format Spec (OFS)
|
|
29
|
+
var parser_js_1 = require("./ofs/parser.cjs");
|
|
30
|
+
Object.defineProperty(exports, "parseOutputFormatSpec", { enumerable: true, get: function () { return parser_js_1.parseOutputFormatSpec; } });
|
|
31
|
+
Object.defineProperty(exports, "parseInputFormatSpec", { enumerable: true, get: function () { return parser_js_1.parseInputFormatSpec; } });
|
|
32
|
+
Object.defineProperty(exports, "parseFormatSpecs", { enumerable: true, get: function () { return parser_js_1.parseFormatSpecs; } });
|
|
33
|
+
Object.defineProperty(exports, "validateFormat", { enumerable: true, get: function () { return parser_js_1.validateFormat; } });
|
|
34
|
+
var adapter_js_1 = require("./ofs/adapter.cjs");
|
|
35
|
+
Object.defineProperty(exports, "ofsToSchema", { enumerable: true, get: function () { return adapter_js_1.ofsToSchema; } });
|
|
36
|
+
Object.defineProperty(exports, "transformWithOfs", { enumerable: true, get: function () { return adapter_js_1.transformWithOfs; } });
|
|
37
|
+
var memory_js_1 = require("./ofs/memory.cjs");
|
|
38
|
+
Object.defineProperty(exports, "remember", { enumerable: true, get: function () { return memory_js_1.remember; } });
|
|
39
|
+
Object.defineProperty(exports, "recall", { enumerable: true, get: function () { return memory_js_1.recall; } });
|
|
40
|
+
var stringify_js_1 = require("./ofs/stringify.cjs");
|
|
41
|
+
Object.defineProperty(exports, "stringifyOutputFormatSpec", { enumerable: true, get: function () { return stringify_js_1.stringifyOutputFormatSpec; } });
|
|
42
|
+
var enricher_js_1 = require("./ofs/enricher.cjs");
|
|
43
|
+
Object.defineProperty(exports, "buildMarkdownGuidance", { enumerable: true, get: function () { return enricher_js_1.buildMarkdownGuidance; } });
|
|
44
|
+
Object.defineProperty(exports, "enrichInstructions", { enumerable: true, get: function () { return enricher_js_1.enrichInstructions; } });
|
|
45
|
+
Object.defineProperty(exports, "enrichInstructionsWithFlexMd", { enumerable: true, get: function () { return enricher_js_1.enrichInstructionsWithFlexMd; } });
|
|
46
|
+
// Validation & Extraction
|
|
47
|
+
var validate_js_1 = require("./validate/validate.cjs");
|
|
48
|
+
Object.defineProperty(exports, "validateMarkdownAgainstOfs", { enumerable: true, get: function () { return validate_js_1.validateMarkdownAgainstOfs; } });
|
|
49
|
+
var compliance_js_1 = require("./validate/compliance.cjs");
|
|
50
|
+
Object.defineProperty(exports, "checkCompliance", { enumerable: true, get: function () { return compliance_js_1.checkCompliance; } });
|
|
51
|
+
Object.defineProperty(exports, "hasFlexMdContract", { enumerable: true, get: function () { return compliance_js_1.hasFlexMdContract; } });
|
|
52
|
+
var connection_js_1 = require("./validate/connection.cjs");
|
|
53
|
+
Object.defineProperty(exports, "checkConnection", { enumerable: true, get: function () { return connection_js_1.checkConnection; } });
|
|
54
|
+
var extract_js_1 = require("./extract/extract.cjs");
|
|
55
|
+
Object.defineProperty(exports, "extractFromMarkdown", { enumerable: true, get: function () { return extract_js_1.extractFromMarkdown; } });
|
|
56
|
+
// Processor & Fallback
|
|
57
|
+
var processor_js_1 = require("./strictness/processor.cjs");
|
|
58
|
+
Object.defineProperty(exports, "processResponseMarkdown", { enumerable: true, get: function () { return processor_js_1.processResponseMarkdown; } });
|
|
59
|
+
var issuesEnvelope_js_1 = require("./ofs/issuesEnvelope.cjs");
|
|
60
|
+
Object.defineProperty(exports, "parseIssuesEnvelope", { enumerable: true, get: function () { return issuesEnvelope_js_1.parseIssuesEnvelope; } });
|
|
61
|
+
Object.defineProperty(exports, "buildIssuesEnvelope", { enumerable: true, get: function () { return issuesEnvelope_js_1.buildIssuesEnvelope; } });
|
|
62
|
+
Object.defineProperty(exports, "buildIssuesEnvelopeAuto", { enumerable: true, get: function () { return issuesEnvelope_js_1.buildIssuesEnvelopeAuto; } });
|
|
63
|
+
// Pipeline
|
|
64
|
+
var kind_js_1 = require("./pipeline/kind.cjs");
|
|
65
|
+
Object.defineProperty(exports, "detectResponseKind", { enumerable: true, get: function () { return kind_js_1.detectResponseKind; } });
|
|
66
|
+
var repair_js_1 = require("./pipeline/repair.cjs");
|
|
67
|
+
Object.defineProperty(exports, "repairToMarkdownLevel", { enumerable: true, get: function () { return repair_js_1.repairToMarkdownLevel; } });
|
|
68
|
+
var enforce_js_1 = require("./pipeline/enforce.cjs");
|
|
69
|
+
Object.defineProperty(exports, "enforceFlexMd", { enumerable: true, get: function () { return enforce_js_1.enforceFlexMd; } });
|
|
70
|
+
// JSON Detection
|
|
71
|
+
__exportStar(require("./detect/json/index.cjs"), exports);
|
|
72
|
+
// Token Estimation
|
|
73
|
+
__exportStar(require("./tokens/index.cjs"), exports);
|
|
74
|
+
// NX-MD-Parser Integration (Structured MD -> JSON)
|
|
75
|
+
var nx_md_parser_1 = require("nx-md-parser");
|
|
76
|
+
Object.defineProperty(exports, "JSONTransformer", { enumerable: true, get: function () { return nx_md_parser_1.JSONTransformer; } });
|
|
77
|
+
Object.defineProperty(exports, "MarkdownParser", { enumerable: true, get: function () { return nx_md_parser_1.MarkdownParser; } });
|
|
78
|
+
Object.defineProperty(exports, "Schema", { enumerable: true, get: function () { return nx_md_parser_1.Schema; } });
|
|
79
|
+
Object.defineProperty(exports, "jsonToMarkdown", { enumerable: true, get: function () { return nx_md_parser_1.jsonToMarkdown; } });
|
|
@@ -0,0 +1,22 @@
|
|
|
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");
|
|
5
|
+
// Get DEBUG_LEVEL from environment, default to 'info'
|
|
6
|
+
const debugLevel = process.env.DEBUG_LEVEL || 'info';
|
|
7
|
+
// Map string levels to micro-logs levels
|
|
8
|
+
const levelMapping = {
|
|
9
|
+
'verbose': 'verbose',
|
|
10
|
+
'debug': 'debug',
|
|
11
|
+
'info': 'info',
|
|
12
|
+
'warn': 'warn',
|
|
13
|
+
'error': 'error'
|
|
14
|
+
};
|
|
15
|
+
// Default to 'info' if invalid level provided
|
|
16
|
+
const threshold = levelMapping[debugLevel.toLowerCase()] || 'info';
|
|
17
|
+
exports.threshold = threshold;
|
|
18
|
+
exports.logger = new micro_logs_1.Logger({
|
|
19
|
+
packageName: 'flex-md',
|
|
20
|
+
envPrefix: 'FLEX_MD',
|
|
21
|
+
debugNamespace: 'flex-md:*'
|
|
22
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.matchSections = matchSections;
|
|
4
|
+
/**
|
|
5
|
+
* Matches sections from the outline against required section names.
|
|
6
|
+
* Supports merging multiple nodes of the same name and selecting highest-level matches.
|
|
7
|
+
*/
|
|
8
|
+
function matchSections(outline, sectionNames, strategy = "merge") {
|
|
9
|
+
const normalizedTargets = new Map(sectionNames.map(n => [norm(n), n]));
|
|
10
|
+
const found = new Map();
|
|
11
|
+
walk(outline.nodes, (node) => {
|
|
12
|
+
const k = norm(node.title);
|
|
13
|
+
if (normalizedTargets.has(k)) {
|
|
14
|
+
if (!found.has(k))
|
|
15
|
+
found.set(k, []);
|
|
16
|
+
found.get(k).push(node);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const res = new Map();
|
|
20
|
+
for (const [nk, originalName] of normalizedTargets.entries()) {
|
|
21
|
+
const nodes = found.get(nk) ?? [];
|
|
22
|
+
if (!nodes.length)
|
|
23
|
+
continue;
|
|
24
|
+
// choose highest-level (smallest level number)
|
|
25
|
+
const minLevel = Math.min(...nodes.map(n => n.level));
|
|
26
|
+
const top = nodes.filter(n => n.level === minLevel);
|
|
27
|
+
let chosen;
|
|
28
|
+
if (strategy === "first") {
|
|
29
|
+
chosen = [top[0]];
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
chosen = top; // merge same-level matches
|
|
33
|
+
}
|
|
34
|
+
const merged = chosen.map(n => n.content_md).join("\n").trimEnd() + "\n";
|
|
35
|
+
res.set(originalName, { name: originalName, nodes, chosen, mergedContent: merged });
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
39
|
+
function walk(nodes, fn) {
|
|
40
|
+
for (const n of nodes) {
|
|
41
|
+
fn(n);
|
|
42
|
+
walk(n.children, fn);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function norm(s) {
|
|
46
|
+
return s.trim().replace(/[:\-–—]\s*$/, "").trim().toLowerCase();
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeMarkdownInput = normalizeMarkdownInput;
|
|
4
|
+
/**
|
|
5
|
+
* Centralized normalization for Markdown input.
|
|
6
|
+
* Handles common LLM output artifacts like literal \n.
|
|
7
|
+
*/
|
|
8
|
+
function normalizeMarkdownInput(md) {
|
|
9
|
+
if (!md)
|
|
10
|
+
return "";
|
|
11
|
+
// Handle literal \n common in LLM outputs delivered via JSON
|
|
12
|
+
return md.replace(/\\n/g, "\n");
|
|
13
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
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.cjs");
|
|
6
|
+
/**
|
|
7
|
+
* Builds a nested tree of headings (outline) from Markdown text.
|
|
8
|
+
*/
|
|
9
|
+
function buildOutline(md) {
|
|
10
|
+
const sections = (0, parse_js_1.parseHeadingsAndSections)(md);
|
|
11
|
+
const roots = [];
|
|
12
|
+
const stack = [];
|
|
13
|
+
for (const s of sections) {
|
|
14
|
+
const h = s.heading;
|
|
15
|
+
const node = {
|
|
16
|
+
title: h.name,
|
|
17
|
+
level: h.level,
|
|
18
|
+
key: h.norm,
|
|
19
|
+
content_md: s.body,
|
|
20
|
+
children: []
|
|
21
|
+
};
|
|
22
|
+
// Pop from stack until we find a parent (level < node.level)
|
|
23
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= node.level) {
|
|
24
|
+
stack.pop();
|
|
25
|
+
}
|
|
26
|
+
if (stack.length === 0) {
|
|
27
|
+
roots.push(node);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
stack[stack.length - 1].children.push(node);
|
|
31
|
+
}
|
|
32
|
+
stack.push(node);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
type: "md_outline",
|
|
36
|
+
nodes: roots
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Slugifies a string into an internal key.
|
|
41
|
+
*/
|
|
42
|
+
function slugify(text) {
|
|
43
|
+
return text
|
|
44
|
+
.toLowerCase()
|
|
45
|
+
.trim()
|
|
46
|
+
.replace(/[^\w\s-]/g, "")
|
|
47
|
+
.replace(/[\s_-]+/g, "-")
|
|
48
|
+
.replace(/^-+|-+$/g, "");
|
|
49
|
+
}
|