@metaobjectsdev/render 1.0.5 → 1.0.7
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/extract/extract.d.ts.map +1 -1
- package/dist/extract/extract.js +28 -5
- package/dist/extract/extract.js.map +1 -1
- package/dist/extract/locate.d.ts +6 -0
- package/dist/extract/locate.d.ts.map +1 -1
- package/dist/extract/locate.js +27 -1
- package/dist/extract/locate.js.map +1 -1
- package/dist/extract/strip.d.ts +3 -0
- package/dist/extract/strip.d.ts.map +1 -1
- package/dist/extract/strip.js +11 -0
- package/dist/extract/strip.js.map +1 -1
- package/dist/extract/xml-forgiving-reader.d.ts.map +1 -1
- package/dist/extract/xml-forgiving-reader.js +66 -6
- package/dist/extract/xml-forgiving-reader.js.map +1 -1
- package/package.json +1 -1
- package/src/extract/extract.ts +33 -5
- package/src/extract/locate.ts +25 -1
- package/src/extract/strip.ts +10 -0
- package/src/extract/xml-forgiving-reader.ts +69 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extract/extract.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAa,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQ9F,sFAAsF;AACtF,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,GACpC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extract/extract.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAa,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQ9F,sFAAsF;AACtF,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,GACpC,iBAAiB,CA6BnB"}
|
package/dist/extract/extract.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Public entry point. Runs the staged pipeline; NEVER throws. Mirrors Java Extract.
|
|
2
2
|
import { Format, FieldKind, FieldExtraction, Tolerance, normalizeOptions, } from "./types.js";
|
|
3
3
|
import { ExtractionReport } from "./types.js";
|
|
4
|
-
import { strip } from "./strip.js";
|
|
5
|
-
import { locateJson, locateXml } from "./locate.js";
|
|
4
|
+
import { strip, fencedBodies } from "./strip.js";
|
|
5
|
+
import { jsonCandidates, locateJson, locateXml } from "./locate.js";
|
|
6
6
|
import { readJson, TRUNCATED, NULL_LITERAL } from "./json-forgiving-reader.js";
|
|
7
7
|
import { readXml, readXmlRootless, TEXT_KEY } from "./xml-forgiving-reader.js";
|
|
8
8
|
import { coerceValue, scalarCoerce, MALFORMED } from "./coerce.js";
|
|
@@ -19,8 +19,7 @@ export function extract(text, schema, opts) {
|
|
|
19
19
|
let span;
|
|
20
20
|
let raw;
|
|
21
21
|
if (schema.format === Format.JSON) {
|
|
22
|
-
span =
|
|
23
|
-
raw = span == null ? {} : readJson(span);
|
|
22
|
+
({ span, raw } = selectJson(text, stripped, schema.fields, ci));
|
|
24
23
|
}
|
|
25
24
|
else if (o.rootless) {
|
|
26
25
|
span = stripped.length === 0 ? null : stripped;
|
|
@@ -36,6 +35,26 @@ export function extract(text, schema, opts) {
|
|
|
36
35
|
extractFields(schema.fields, raw, "", data, report, o, ci);
|
|
37
36
|
return { data, report };
|
|
38
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Pick the JSON object that answers the schema. Fenced blocks are searched first, then the
|
|
40
|
+
* whole reply, and the first object carrying at least one declared field wins, so a draft
|
|
41
|
+
* object, an echoed format example or a brace in prose no longer shadows the real answer
|
|
42
|
+
* (#363). A fenced object with none of the declared fields falls through the same way. When
|
|
43
|
+
* nothing carries a declared field, the first-object rule (locateJson) decides, as before.
|
|
44
|
+
*/
|
|
45
|
+
function selectJson(text, stripped, fields, ci) {
|
|
46
|
+
const regions = [...fencedBodies(text), stripped];
|
|
47
|
+
for (const region of regions) {
|
|
48
|
+
for (const candidate of jsonCandidates(region)) {
|
|
49
|
+
const parsed = readJson(candidate);
|
|
50
|
+
if (fields.some((f) => lookup(parsed, f.name, ci) !== undefined)) {
|
|
51
|
+
return { span: candidate, raw: parsed };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const span = locateJson(stripped);
|
|
56
|
+
return { span, raw: span == null ? {} : readJson(span) };
|
|
57
|
+
}
|
|
39
58
|
function extractFields(fields, raw, prefix, data, report, o, ci) {
|
|
40
59
|
for (const f of fields) {
|
|
41
60
|
const path = prefix.length === 0 ? f.name : `${prefix}.${f.name}`;
|
|
@@ -157,7 +176,11 @@ function extractValue(f, present, path, report, o, ci) {
|
|
|
157
176
|
// A text element that also carried XML attributes is represented by readXml as a record with
|
|
158
177
|
// the body under TEXT_KEY. A scalar field reads that text (attributes ignored for scalars —
|
|
159
178
|
// preserving pre-attribute-support behaviour).
|
|
160
|
-
if (isPlainObject(present)
|
|
179
|
+
if (isPlainObject(present)) {
|
|
180
|
+
// An element with no text of its own (only child elements) is not a scalar value. Never
|
|
181
|
+
// stringify the record: that delivered "[object Object]" as the field's text.
|
|
182
|
+
if (!Object.prototype.hasOwnProperty.call(present, TEXT_KEY))
|
|
183
|
+
return MALFORMED;
|
|
161
184
|
present = present[TEXT_KEY];
|
|
162
185
|
}
|
|
163
186
|
const rawStr = typeof present === "string" ? present : stringifyScalar(present);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/extract/extract.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,OAAO,EACL,MAAM,EACN,SAAS,EACT,eAAe,EACf,SAAS,EACT,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/extract/extract.ts"],"names":[],"mappings":"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"}
|
package/dist/extract/locate.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/** First balanced {...}; if none closes, first '{' to end; null if no '{'. */
|
|
2
2
|
export declare function locateJson(text: string | null | undefined): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Every top-level object span in `text`, in order: each balanced {...} (nested objects are
|
|
5
|
+
* part of their parent, not separate spans), and, for a '{' that never closes, the text from
|
|
6
|
+
* it to the end.
|
|
7
|
+
*/
|
|
8
|
+
export declare function jsonCandidates(text: string | null | undefined): string[];
|
|
3
9
|
/** Span of <root>...</root>; if close absent, opener to end; null if no opener. */
|
|
4
10
|
export declare function locateXml(text: string | null | undefined, rootName: string | null | undefined, caseInsensitive: boolean): string | null;
|
|
5
11
|
//# sourceMappingURL=locate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../../src/extract/locate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../../src/extract/locate.ts"],"names":[],"mappings":"AASA,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAWzE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAgBxE;AAyBD,mFAAmF;AACnF,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,eAAe,EAAE,OAAO,GACvB,MAAM,GAAG,IAAI,CAcf"}
|
package/dist/extract/locate.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Stages 2-3: isolate and select the payload root span.
|
|
2
|
-
//
|
|
2
|
+
// JSON: Extract picks among jsonCandidates by the schema (fenced first, first object carrying a
|
|
3
|
+
// declared field); locateJson (first-closed-else-first-open) is its fallback. Mirrors Java Locate.
|
|
3
4
|
/** Escape regex metacharacters (equivalent of Java Pattern.quote). */
|
|
4
5
|
function quote(s) {
|
|
5
6
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -20,6 +21,31 @@ export function locateJson(text) {
|
|
|
20
21
|
}
|
|
21
22
|
return firstOpen < 0 ? null : text.substring(firstOpen);
|
|
22
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Every top-level object span in `text`, in order: each balanced {...} (nested objects are
|
|
26
|
+
* part of their parent, not separate spans), and, for a '{' that never closes, the text from
|
|
27
|
+
* it to the end.
|
|
28
|
+
*/
|
|
29
|
+
export function jsonCandidates(text) {
|
|
30
|
+
if (text == null)
|
|
31
|
+
return [];
|
|
32
|
+
const out = [];
|
|
33
|
+
let tailAdded = false;
|
|
34
|
+
for (let i = 0; i < text.length; i++) {
|
|
35
|
+
if (text.charAt(i) !== "{")
|
|
36
|
+
continue;
|
|
37
|
+
const end = scanBalanced(text, i);
|
|
38
|
+
if (end >= 0) {
|
|
39
|
+
out.push(text.substring(i, end + 1));
|
|
40
|
+
i = end;
|
|
41
|
+
}
|
|
42
|
+
else if (!tailAdded) {
|
|
43
|
+
out.push(text.substring(i));
|
|
44
|
+
tailAdded = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
23
49
|
/** Returns index of the matching '}', or -1 if unterminated. String-aware. */
|
|
24
50
|
function scanBalanced(s, open) {
|
|
25
51
|
let depth = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locate.js","sourceRoot":"","sources":["../../src/extract/locate.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,
|
|
1
|
+
{"version":3,"file":"locate.js","sourceRoot":"","sources":["../../src/extract/locate.ts"],"names":[],"mappings":"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"}
|
package/dist/extract/strip.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export declare function strip(raw: string | null | undefined): string;
|
|
2
|
+
/** The body of every fenced block, in order. Locate searches these before the whole text,
|
|
3
|
+
* because a model told to fence its answer puts the answer there. */
|
|
4
|
+
export declare function fencedBodies(raw: string | null | undefined): string[];
|
|
2
5
|
//# sourceMappingURL=strip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strip.d.ts","sourceRoot":"","sources":["../../src/extract/strip.ts"],"names":[],"mappings":"AAMA,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAU5D"}
|
|
1
|
+
{"version":3,"file":"strip.d.ts","sourceRoot":"","sources":["../../src/extract/strip.ts"],"names":[],"mappings":"AAMA,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAU5D;AAED;sEACsE;AACtE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAMrE"}
|
package/dist/extract/strip.js
CHANGED
|
@@ -14,4 +14,15 @@ export function strip(raw) {
|
|
|
14
14
|
}
|
|
15
15
|
return raw.trim();
|
|
16
16
|
}
|
|
17
|
+
/** The body of every fenced block, in order. Locate searches these before the whole text,
|
|
18
|
+
* because a model told to fence its answer puts the answer there. */
|
|
19
|
+
export function fencedBodies(raw) {
|
|
20
|
+
if (raw == null)
|
|
21
|
+
return [];
|
|
22
|
+
const all = new RegExp(FENCE.source, "g");
|
|
23
|
+
const out = [];
|
|
24
|
+
for (let m = all.exec(raw); m != null; m = all.exec(raw))
|
|
25
|
+
out.push(m[1] ?? "");
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
17
28
|
//# sourceMappingURL=strip.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strip.js","sourceRoot":"","sources":["../../src/extract/strip.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,sBAAsB;AAEtB,4FAA4F;AAC5F,MAAM,KAAK,GAAG,8CAA8C,CAAC;AAE7D,MAAM,UAAU,KAAK,CAAC,GAA8B;IAClD,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACnD,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC"}
|
|
1
|
+
{"version":3,"file":"strip.js","sourceRoot":"","sources":["../../src/extract/strip.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,sBAAsB;AAEtB,4FAA4F;AAC5F,MAAM,KAAK,GAAG,8CAA8C,CAAC;AAE7D,MAAM,UAAU,KAAK,CAAC,GAA8B;IAClD,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACnD,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,YAAY,CAAC,GAA8B;IACzD,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/E,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-forgiving-reader.d.ts","sourceRoot":"","sources":["../../src/extract/xml-forgiving-reader.ts"],"names":[],"mappings":"AAcA;;4DAE4D;AAC5D,eAAO,MAAM,QAAQ,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"xml-forgiving-reader.d.ts","sourceRoot":"","sources":["../../src/extract/xml-forgiving-reader.ts"],"names":[],"mappings":"AAcA;;4DAE4D;AAC5D,eAAO,MAAM,QAAQ,UAAU,CAAC;AAsBhC,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAS1G;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,eAAe,EAAE,OAAO,GACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB"}
|
|
@@ -27,6 +27,9 @@ function matchFrom(source, flags, text, from) {
|
|
|
27
27
|
// tag name + everything up to the closing '>' (attributes and/or a trailing '/' for a
|
|
28
28
|
// self-closing tag). Non-greedy so the first '>' closes the open tag.
|
|
29
29
|
const OPEN_TAG_SRC = "<([A-Za-z_][A-Za-z0-9_]*)([^>]*?)>";
|
|
30
|
+
// a closing tag. Used to spot a STRAY close (of an element whose open never appeared in the
|
|
31
|
+
// body) — LLMs commonly end a block with the wrong tag.
|
|
32
|
+
const CLOSE_TAG_SRC = "</([A-Za-z_][A-Za-z0-9_]*)\\s*>";
|
|
30
33
|
// one attribute: name = "double" | 'single' | bareword.
|
|
31
34
|
const ATTR_SRC = "([A-Za-z_:][A-Za-z0-9_:.\\-]*)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s/>]+))";
|
|
32
35
|
export function readXml(span, caseInsensitive) {
|
|
@@ -38,7 +41,7 @@ export function readXml(span, caseInsensitive) {
|
|
|
38
41
|
return out;
|
|
39
42
|
const rootEnd = span.lastIndexOf("</");
|
|
40
43
|
const inner = span.substring(gt + 1, rootEnd < 0 || rootEnd <= gt ? span.length : rootEnd);
|
|
41
|
-
parseChildren(inner, caseInsensitive, out);
|
|
44
|
+
parseChildren(inner, caseInsensitive, out, null);
|
|
42
45
|
return out;
|
|
43
46
|
}
|
|
44
47
|
/**
|
|
@@ -50,16 +53,21 @@ export function readXmlRootless(text, caseInsensitive) {
|
|
|
50
53
|
const out = {};
|
|
51
54
|
if (text == null || text.trim().length === 0)
|
|
52
55
|
return out;
|
|
53
|
-
parseChildren(text, caseInsensitive, out);
|
|
56
|
+
parseChildren(text, caseInsensitive, out, null);
|
|
54
57
|
return out;
|
|
55
58
|
}
|
|
56
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Parse `inner`'s elements into `out`. When `loose` is non-null, the text BETWEEN those
|
|
61
|
+
* elements (an element's own text in mixed content) is appended to it, one segment per gap.
|
|
62
|
+
*/
|
|
63
|
+
function parseChildren(inner, ci, out, loose) {
|
|
57
64
|
const flags = ci ? "i" : "";
|
|
58
65
|
let pos = 0;
|
|
59
66
|
for (;;) {
|
|
60
67
|
const m = matchFrom(OPEN_TAG_SRC, flags, inner, pos);
|
|
61
68
|
if (m == null)
|
|
62
69
|
break;
|
|
70
|
+
loose?.push(inner.substring(pos, m.index));
|
|
63
71
|
const tag = m[1] ?? "";
|
|
64
72
|
const key = ci ? tag.toLowerCase() : tag;
|
|
65
73
|
let rawAttrs = (m[2] ?? "").trim();
|
|
@@ -107,24 +115,76 @@ function parseChildren(inner, ci, out) {
|
|
|
107
115
|
contentEnd = inner.length;
|
|
108
116
|
next = inner.length;
|
|
109
117
|
}
|
|
118
|
+
// A STRAY close tag of another element inside the unclosed element's body ends the body
|
|
119
|
+
// there (the model closed the block with the wrong tag), and the stray tag itself is
|
|
120
|
+
// dropped rather than kept as literal text.
|
|
121
|
+
const stray = findStrayClose(inner, contentStart, contentEnd, ci);
|
|
122
|
+
if (stray != null) {
|
|
123
|
+
contentEnd = stray[0];
|
|
124
|
+
next = stray[1];
|
|
125
|
+
}
|
|
110
126
|
}
|
|
111
127
|
const content = inner.substring(contentStart, contentEnd);
|
|
112
128
|
accumulate(out, key, combine(attrs, content, ci));
|
|
113
129
|
pos = next;
|
|
114
130
|
}
|
|
131
|
+
loose?.push(inner.substring(pos));
|
|
115
132
|
}
|
|
116
|
-
/**
|
|
133
|
+
/**
|
|
134
|
+
* The first close tag in `inner[from, to)` whose element was never opened after `from` — a
|
|
135
|
+
* stray close — as `[start, end]`, or `null`. A close whose open DID appear is a nested
|
|
136
|
+
* child's own close, not stray.
|
|
137
|
+
*/
|
|
138
|
+
function findStrayClose(inner, from, to, ci) {
|
|
139
|
+
const flags = ci ? "i" : "";
|
|
140
|
+
const bounded = inner.substring(0, to);
|
|
141
|
+
let at = from;
|
|
142
|
+
for (;;) {
|
|
143
|
+
const close = matchFrom(CLOSE_TAG_SRC, flags, bounded, at);
|
|
144
|
+
if (close == null)
|
|
145
|
+
return null;
|
|
146
|
+
const openName = close[1] ?? "";
|
|
147
|
+
const openRe = `<${quote(openName)}(?=[\\s/>])`;
|
|
148
|
+
const opened = matchFrom(openRe, flags, inner.substring(from, close.index), 0);
|
|
149
|
+
if (opened == null)
|
|
150
|
+
return [close.index, close.index + close[0].length];
|
|
151
|
+
at = close.index + close[0].length;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Combine an element's attributes with its body (nested children or plain text). Mixed content
|
|
156
|
+
* keeps BOTH: the children, and the element's own text under TEXT_KEY, so a scalar or
|
|
157
|
+
* `@xmlText` consumer still reads the prose around a child element.
|
|
158
|
+
*/
|
|
117
159
|
function combine(attrs, content, ci) {
|
|
118
160
|
if (content.includes("<")) {
|
|
119
161
|
const nested = {};
|
|
120
|
-
|
|
162
|
+
const loose = [];
|
|
163
|
+
parseChildren(content, ci, nested, loose);
|
|
121
164
|
if (Object.keys(nested).length > 0) {
|
|
122
165
|
// attributes first; a child element wins a name collision
|
|
123
|
-
|
|
166
|
+
const merged = { ...attrs, ...nested };
|
|
167
|
+
const text = mixedText(loose, ci);
|
|
168
|
+
if (text.length > 0)
|
|
169
|
+
merged[TEXT_KEY] = text;
|
|
170
|
+
return merged;
|
|
124
171
|
}
|
|
125
172
|
}
|
|
126
173
|
return textValue(attrs, content);
|
|
127
174
|
}
|
|
175
|
+
/** The text segments between child elements: stray close tags dropped, each trimmed, the
|
|
176
|
+
* non-empty ones joined with a single space. */
|
|
177
|
+
function mixedText(segments, ci) {
|
|
178
|
+
const closeRe = new RegExp(CLOSE_TAG_SRC, ci ? "gi" : "g");
|
|
179
|
+
const parts = [];
|
|
180
|
+
for (const seg of segments) {
|
|
181
|
+
closeRe.lastIndex = 0;
|
|
182
|
+
const t = seg.replace(closeRe, "").trim();
|
|
183
|
+
if (t.length > 0)
|
|
184
|
+
parts.push(t);
|
|
185
|
+
}
|
|
186
|
+
return parts.join(" ");
|
|
187
|
+
}
|
|
128
188
|
function textValue(attrs, content) {
|
|
129
189
|
const text = content.trim();
|
|
130
190
|
if (Object.keys(attrs).length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-forgiving-reader.js","sourceRoot":"","sources":["../../src/extract/xml-forgiving-reader.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,0FAA0F;AAC1F,8FAA8F;AAC9F,0BAA0B;AAC1B,EAAE;AACF,kBAAkB;AAClB,sFAAsF;AACtF,iGAAiG;AACjG,8FAA8F;AAC9F,2FAA2F;AAC3F,gGAAgG;AAChG,iGAAiG;AACjG,uEAAuE;AAEvE;;4DAE4D;AAC5D,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEhC,SAAS,KAAK,CAAC,CAAS;IACtB,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,mFAAmF;AACnF,SAAS,SAAS,CAAC,MAAc,EAAE,KAAa,EAAE,IAAY,EAAE,IAAY;IAC1E,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;IACxE,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC;IACnB,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,sFAAsF;AACtF,sEAAsE;AACtE,MAAM,YAAY,GAAG,oCAAoC,CAAC;AAC1D,wDAAwD;AACxD,MAAM,QAAQ,GAAG,+EAA+E,CAAC;AAEjG,MAAM,UAAU,OAAO,CAAC,IAA+B,EAAE,eAAwB;IAC/E,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACzD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC3F,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"xml-forgiving-reader.js","sourceRoot":"","sources":["../../src/extract/xml-forgiving-reader.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/render",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Logic-less, deterministic text render engine (Mustache) for MetaObjects templates — provider-resolved partials, format-driven escaping, zero core dependency.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
package/src/extract/extract.ts
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
} from "./types.js";
|
|
10
10
|
import type { FieldSpec, ExtractOptions, ExtractionOutcome, ExtractSchema } from "./types.js";
|
|
11
11
|
import { ExtractionReport } from "./types.js";
|
|
12
|
-
import { strip } from "./strip.js";
|
|
13
|
-
import { locateJson, locateXml } from "./locate.js";
|
|
12
|
+
import { strip, fencedBodies } from "./strip.js";
|
|
13
|
+
import { jsonCandidates, locateJson, locateXml } from "./locate.js";
|
|
14
14
|
import { readJson, TRUNCATED, NULL_LITERAL } from "./json-forgiving-reader.js";
|
|
15
15
|
import { readXml, readXmlRootless, TEXT_KEY } from "./xml-forgiving-reader.js";
|
|
16
16
|
import { coerceValue, scalarCoerce, MALFORMED } from "./coerce.js";
|
|
@@ -34,8 +34,7 @@ export function extract(
|
|
|
34
34
|
let span: string | null;
|
|
35
35
|
let raw: Record<string, unknown>;
|
|
36
36
|
if (schema.format === Format.JSON) {
|
|
37
|
-
span =
|
|
38
|
-
raw = span == null ? {} : readJson(span);
|
|
37
|
+
({ span, raw } = selectJson(text, stripped, schema.fields, ci));
|
|
39
38
|
} else if (o.rootless) {
|
|
40
39
|
span = stripped.length === 0 ? null : stripped;
|
|
41
40
|
raw = span == null ? {} : readXmlRootless(stripped, ci);
|
|
@@ -52,6 +51,32 @@ export function extract(
|
|
|
52
51
|
return { data, report };
|
|
53
52
|
}
|
|
54
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Pick the JSON object that answers the schema. Fenced blocks are searched first, then the
|
|
56
|
+
* whole reply, and the first object carrying at least one declared field wins, so a draft
|
|
57
|
+
* object, an echoed format example or a brace in prose no longer shadows the real answer
|
|
58
|
+
* (#363). A fenced object with none of the declared fields falls through the same way. When
|
|
59
|
+
* nothing carries a declared field, the first-object rule (locateJson) decides, as before.
|
|
60
|
+
*/
|
|
61
|
+
function selectJson(
|
|
62
|
+
text: string | null | undefined,
|
|
63
|
+
stripped: string,
|
|
64
|
+
fields: readonly FieldSpec[],
|
|
65
|
+
ci: boolean,
|
|
66
|
+
): { span: string | null; raw: Record<string, unknown> } {
|
|
67
|
+
const regions = [...fencedBodies(text), stripped];
|
|
68
|
+
for (const region of regions) {
|
|
69
|
+
for (const candidate of jsonCandidates(region)) {
|
|
70
|
+
const parsed = readJson(candidate);
|
|
71
|
+
if (fields.some((f) => lookup(parsed, f.name, ci) !== undefined)) {
|
|
72
|
+
return { span: candidate, raw: parsed };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const span = locateJson(stripped);
|
|
77
|
+
return { span, raw: span == null ? {} : readJson(span) };
|
|
78
|
+
}
|
|
79
|
+
|
|
55
80
|
function extractFields(
|
|
56
81
|
fields: readonly FieldSpec[],
|
|
57
82
|
raw: Record<string, unknown>,
|
|
@@ -184,7 +209,10 @@ function extractValue(
|
|
|
184
209
|
// A text element that also carried XML attributes is represented by readXml as a record with
|
|
185
210
|
// the body under TEXT_KEY. A scalar field reads that text (attributes ignored for scalars —
|
|
186
211
|
// preserving pre-attribute-support behaviour).
|
|
187
|
-
if (isPlainObject(present)
|
|
212
|
+
if (isPlainObject(present)) {
|
|
213
|
+
// An element with no text of its own (only child elements) is not a scalar value. Never
|
|
214
|
+
// stringify the record: that delivered "[object Object]" as the field's text.
|
|
215
|
+
if (!Object.prototype.hasOwnProperty.call(present, TEXT_KEY)) return MALFORMED;
|
|
188
216
|
present = (present as Record<string, unknown>)[TEXT_KEY];
|
|
189
217
|
}
|
|
190
218
|
const rawStr = typeof present === "string" ? present : stringifyScalar(present);
|
package/src/extract/locate.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Stages 2-3: isolate and select the payload root span.
|
|
2
|
-
//
|
|
2
|
+
// JSON: Extract picks among jsonCandidates by the schema (fenced first, first object carrying a
|
|
3
|
+
// declared field); locateJson (first-closed-else-first-open) is its fallback. Mirrors Java Locate.
|
|
3
4
|
|
|
4
5
|
/** Escape regex metacharacters (equivalent of Java Pattern.quote). */
|
|
5
6
|
function quote(s: string): string {
|
|
@@ -20,6 +21,29 @@ export function locateJson(text: string | null | undefined): string | null {
|
|
|
20
21
|
return firstOpen < 0 ? null : text.substring(firstOpen);
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Every top-level object span in `text`, in order: each balanced {...} (nested objects are
|
|
26
|
+
* part of their parent, not separate spans), and, for a '{' that never closes, the text from
|
|
27
|
+
* it to the end.
|
|
28
|
+
*/
|
|
29
|
+
export function jsonCandidates(text: string | null | undefined): string[] {
|
|
30
|
+
if (text == null) return [];
|
|
31
|
+
const out: string[] = [];
|
|
32
|
+
let tailAdded = false;
|
|
33
|
+
for (let i = 0; i < text.length; i++) {
|
|
34
|
+
if (text.charAt(i) !== "{") continue;
|
|
35
|
+
const end = scanBalanced(text, i);
|
|
36
|
+
if (end >= 0) {
|
|
37
|
+
out.push(text.substring(i, end + 1));
|
|
38
|
+
i = end;
|
|
39
|
+
} else if (!tailAdded) {
|
|
40
|
+
out.push(text.substring(i));
|
|
41
|
+
tailAdded = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
23
47
|
/** Returns index of the matching '}', or -1 if unterminated. String-aware. */
|
|
24
48
|
function scanBalanced(s: string, open: number): number {
|
|
25
49
|
let depth = 0;
|
package/src/extract/strip.ts
CHANGED
|
@@ -15,3 +15,13 @@ export function strip(raw: string | null | undefined): string {
|
|
|
15
15
|
}
|
|
16
16
|
return raw.trim();
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
/** The body of every fenced block, in order. Locate searches these before the whole text,
|
|
20
|
+
* because a model told to fence its answer puts the answer there. */
|
|
21
|
+
export function fencedBodies(raw: string | null | undefined): string[] {
|
|
22
|
+
if (raw == null) return [];
|
|
23
|
+
const all = new RegExp(FENCE.source, "g");
|
|
24
|
+
const out: string[] = [];
|
|
25
|
+
for (let m = all.exec(raw); m != null; m = all.exec(raw)) out.push(m[1] ?? "");
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
@@ -31,6 +31,9 @@ function matchFrom(source: string, flags: string, text: string, from: number): R
|
|
|
31
31
|
// tag name + everything up to the closing '>' (attributes and/or a trailing '/' for a
|
|
32
32
|
// self-closing tag). Non-greedy so the first '>' closes the open tag.
|
|
33
33
|
const OPEN_TAG_SRC = "<([A-Za-z_][A-Za-z0-9_]*)([^>]*?)>";
|
|
34
|
+
// a closing tag. Used to spot a STRAY close (of an element whose open never appeared in the
|
|
35
|
+
// body) — LLMs commonly end a block with the wrong tag.
|
|
36
|
+
const CLOSE_TAG_SRC = "</([A-Za-z_][A-Za-z0-9_]*)\\s*>";
|
|
34
37
|
// one attribute: name = "double" | 'single' | bareword.
|
|
35
38
|
const ATTR_SRC = "([A-Za-z_:][A-Za-z0-9_:.\\-]*)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s/>]+))";
|
|
36
39
|
|
|
@@ -41,7 +44,7 @@ export function readXml(span: string | null | undefined, caseInsensitive: boolea
|
|
|
41
44
|
if (gt < 0) return out;
|
|
42
45
|
const rootEnd = span.lastIndexOf("</");
|
|
43
46
|
const inner = span.substring(gt + 1, rootEnd < 0 || rootEnd <= gt ? span.length : rootEnd);
|
|
44
|
-
parseChildren(inner, caseInsensitive, out);
|
|
47
|
+
parseChildren(inner, caseInsensitive, out, null);
|
|
45
48
|
return out;
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -56,16 +59,26 @@ export function readXmlRootless(
|
|
|
56
59
|
): Record<string, unknown> {
|
|
57
60
|
const out: Record<string, unknown> = {};
|
|
58
61
|
if (text == null || text.trim().length === 0) return out;
|
|
59
|
-
parseChildren(text, caseInsensitive, out);
|
|
62
|
+
parseChildren(text, caseInsensitive, out, null);
|
|
60
63
|
return out;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Parse `inner`'s elements into `out`. When `loose` is non-null, the text BETWEEN those
|
|
68
|
+
* elements (an element's own text in mixed content) is appended to it, one segment per gap.
|
|
69
|
+
*/
|
|
70
|
+
function parseChildren(
|
|
71
|
+
inner: string,
|
|
72
|
+
ci: boolean,
|
|
73
|
+
out: Record<string, unknown>,
|
|
74
|
+
loose: string[] | null,
|
|
75
|
+
): void {
|
|
64
76
|
const flags = ci ? "i" : "";
|
|
65
77
|
let pos = 0;
|
|
66
78
|
for (;;) {
|
|
67
79
|
const m = matchFrom(OPEN_TAG_SRC, flags, inner, pos);
|
|
68
80
|
if (m == null) break;
|
|
81
|
+
loose?.push(inner.substring(pos, m.index));
|
|
69
82
|
const tag = m[1] ?? "";
|
|
70
83
|
const key = ci ? tag.toLowerCase() : tag;
|
|
71
84
|
|
|
@@ -113,27 +126,77 @@ function parseChildren(inner: string, ci: boolean, out: Record<string, unknown>)
|
|
|
113
126
|
contentEnd = inner.length;
|
|
114
127
|
next = inner.length;
|
|
115
128
|
}
|
|
129
|
+
// A STRAY close tag of another element inside the unclosed element's body ends the body
|
|
130
|
+
// there (the model closed the block with the wrong tag), and the stray tag itself is
|
|
131
|
+
// dropped rather than kept as literal text.
|
|
132
|
+
const stray = findStrayClose(inner, contentStart, contentEnd, ci);
|
|
133
|
+
if (stray != null) {
|
|
134
|
+
contentEnd = stray[0];
|
|
135
|
+
next = stray[1];
|
|
136
|
+
}
|
|
116
137
|
}
|
|
117
138
|
|
|
118
139
|
const content = inner.substring(contentStart, contentEnd);
|
|
119
140
|
accumulate(out, key, combine(attrs, content, ci));
|
|
120
141
|
pos = next;
|
|
121
142
|
}
|
|
143
|
+
loose?.push(inner.substring(pos));
|
|
122
144
|
}
|
|
123
145
|
|
|
124
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* The first close tag in `inner[from, to)` whose element was never opened after `from` — a
|
|
148
|
+
* stray close — as `[start, end]`, or `null`. A close whose open DID appear is a nested
|
|
149
|
+
* child's own close, not stray.
|
|
150
|
+
*/
|
|
151
|
+
function findStrayClose(inner: string, from: number, to: number, ci: boolean): [number, number] | null {
|
|
152
|
+
const flags = ci ? "i" : "";
|
|
153
|
+
const bounded = inner.substring(0, to);
|
|
154
|
+
let at = from;
|
|
155
|
+
for (;;) {
|
|
156
|
+
const close = matchFrom(CLOSE_TAG_SRC, flags, bounded, at);
|
|
157
|
+
if (close == null) return null;
|
|
158
|
+
const openName = close[1] ?? "";
|
|
159
|
+
const openRe = `<${quote(openName)}(?=[\\s/>])`;
|
|
160
|
+
const opened = matchFrom(openRe, flags, inner.substring(from, close.index), 0);
|
|
161
|
+
if (opened == null) return [close.index, close.index + close[0].length];
|
|
162
|
+
at = close.index + close[0].length;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Combine an element's attributes with its body (nested children or plain text). Mixed content
|
|
168
|
+
* keeps BOTH: the children, and the element's own text under TEXT_KEY, so a scalar or
|
|
169
|
+
* `@xmlText` consumer still reads the prose around a child element.
|
|
170
|
+
*/
|
|
125
171
|
function combine(attrs: Record<string, unknown>, content: string, ci: boolean): unknown {
|
|
126
172
|
if (content.includes("<")) {
|
|
127
173
|
const nested: Record<string, unknown> = {};
|
|
128
|
-
|
|
174
|
+
const loose: string[] = [];
|
|
175
|
+
parseChildren(content, ci, nested, loose);
|
|
129
176
|
if (Object.keys(nested).length > 0) {
|
|
130
177
|
// attributes first; a child element wins a name collision
|
|
131
|
-
|
|
178
|
+
const merged: Record<string, unknown> = { ...attrs, ...nested };
|
|
179
|
+
const text = mixedText(loose, ci);
|
|
180
|
+
if (text.length > 0) merged[TEXT_KEY] = text;
|
|
181
|
+
return merged;
|
|
132
182
|
}
|
|
133
183
|
}
|
|
134
184
|
return textValue(attrs, content);
|
|
135
185
|
}
|
|
136
186
|
|
|
187
|
+
/** The text segments between child elements: stray close tags dropped, each trimmed, the
|
|
188
|
+
* non-empty ones joined with a single space. */
|
|
189
|
+
function mixedText(segments: readonly string[], ci: boolean): string {
|
|
190
|
+
const closeRe = new RegExp(CLOSE_TAG_SRC, ci ? "gi" : "g");
|
|
191
|
+
const parts: string[] = [];
|
|
192
|
+
for (const seg of segments) {
|
|
193
|
+
closeRe.lastIndex = 0;
|
|
194
|
+
const t = seg.replace(closeRe, "").trim();
|
|
195
|
+
if (t.length > 0) parts.push(t);
|
|
196
|
+
}
|
|
197
|
+
return parts.join(" ");
|
|
198
|
+
}
|
|
199
|
+
|
|
137
200
|
function textValue(attrs: Record<string, unknown>, content: string): unknown {
|
|
138
201
|
const text = content.trim();
|
|
139
202
|
if (Object.keys(attrs).length === 0) return text;
|