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