toolcraft 0.0.798 → 0.0.799
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/composition.json +2 -2
- package/dist/composition.json +2 -2
- package/node_modules/@poe-code/xml-ast/README.md +9 -3
- package/node_modules/@poe-code/xml-ast/dist/attributes.d.ts +8 -1
- package/node_modules/@poe-code/xml-ast/dist/attributes.js +2 -2
- package/node_modules/@poe-code/xml-ast/dist/index.d.ts +2 -1
- package/node_modules/@poe-code/xml-ast/dist/index.js +65 -20
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
package/composition.json
CHANGED
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"name": "toolcraft",
|
|
141
|
-
"version": "0.0.
|
|
141
|
+
"version": "0.0.799",
|
|
142
142
|
"license": "MIT"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
"name": "toolcraft-schema",
|
|
151
|
-
"version": "0.0.
|
|
151
|
+
"version": "0.0.799",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
package/dist/composition.json
CHANGED
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"name": "toolcraft",
|
|
141
|
-
"version": "0.0.
|
|
141
|
+
"version": "0.0.799",
|
|
142
142
|
"license": "MIT"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
"name": "toolcraft-schema",
|
|
151
|
-
"version": "0.0.
|
|
151
|
+
"version": "0.0.799",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -81,7 +81,14 @@ receive resolved attributes in source order, after the open event and before any
|
|
|
81
81
|
content or close event. The parser yields between attributes so a host can await
|
|
82
82
|
storage or a consumer. Namespace declarations may follow prefixed attributes;
|
|
83
83
|
resolution and duplicate-expanded-name validation still happen after the complete
|
|
84
|
-
start tag.
|
|
84
|
+
start tag. With `fragmentAttributes: true`, ordinary values are validated and
|
|
85
|
+
stored as source spans on attribute records, then replayed in at most 512 UTF-16
|
|
86
|
+
units. Hosts must preserve the optional `source` field in append/read requests.
|
|
87
|
+
The third `onAttribute` argument is `true` for continuations of the same logical
|
|
88
|
+
attribute; await each fragment before requesting the next step. Empty attributes
|
|
89
|
+
still emit once. Entity diagnostics are emitted during validation, not replay.
|
|
90
|
+
This mode requires `storeAttributes: true`. Namespace declaration values and
|
|
91
|
+
individual names still retain their token cost.
|
|
85
92
|
|
|
86
93
|
Pass `undefined` as the source length to parse incrementally. Such read requests
|
|
87
94
|
have `streaming: true` and request at most 512 UTF-16 units. Return any nonempty
|
|
@@ -100,5 +107,4 @@ decoding replay bounded source windows before publishing a logical node, retaini
|
|
|
100
107
|
its diagnostic and limit ordering. Numeric entity references are decoded without
|
|
101
108
|
materializing the token. Set `compactDeclaration: true` to retain normalized declaration fields without
|
|
102
109
|
copying long whitespace spans; validation always reads bounded windows. The
|
|
103
|
-
buffered API keeps the original declaration spelling. Names
|
|
104
|
-
and namespace scopes still require their own memory budget.
|
|
110
|
+
buffered API keeps the original declaration spelling. Names and namespace declaration values still require their own memory budget.
|
|
@@ -4,6 +4,10 @@ export interface XmlAttributeRecord {
|
|
|
4
4
|
localName: string;
|
|
5
5
|
value: string;
|
|
6
6
|
next: number;
|
|
7
|
+
source?: {
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
};
|
|
7
11
|
}
|
|
8
12
|
export interface XmlAttributeState {
|
|
9
13
|
reference: number;
|
|
@@ -41,7 +45,10 @@ export declare class XmlAttributes {
|
|
|
41
45
|
get size(): number;
|
|
42
46
|
get first(): number;
|
|
43
47
|
has(name: string): Generator<XmlAttributeRequest, boolean, void>;
|
|
44
|
-
append(name: string, prefix: string, localName: string, value: string
|
|
48
|
+
append(name: string, prefix: string, localName: string, value: string, source?: {
|
|
49
|
+
start: number;
|
|
50
|
+
end: number;
|
|
51
|
+
}): Generator<XmlAttributeRequest, void, void>;
|
|
45
52
|
read(reference: number, values: boolean): Generator<XmlAttributeRequest, XmlAttributeRecord, void>;
|
|
46
53
|
expanded(name: string): Generator<XmlAttributeRequest, boolean, void>;
|
|
47
54
|
}
|
|
@@ -23,14 +23,14 @@ export class XmlAttributes {
|
|
|
23
23
|
throw new TypeError('Incomplete XML attribute lookup');
|
|
24
24
|
return request.found;
|
|
25
25
|
}
|
|
26
|
-
*append(name, prefix, localName, value) {
|
|
26
|
+
*append(name, prefix, localName, value, source) {
|
|
27
27
|
if (!this.external) {
|
|
28
28
|
this.names.set(name, value);
|
|
29
29
|
this.records.push({ name, prefix, localName });
|
|
30
30
|
this.state = { reference: 0, first: 1, length: this.records.length, size: this.names.size };
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
const request = { attributeOperation: 'append', state: this.state, attribute: { name, prefix, localName, value } };
|
|
33
|
+
const request = { attributeOperation: 'append', state: this.state, attribute: { name, prefix, localName, value, ...(source ? { source } : {}) } };
|
|
34
34
|
yield request;
|
|
35
35
|
if (!request.result)
|
|
36
36
|
throw new TypeError('Incomplete XML attribute append');
|
|
@@ -67,7 +67,8 @@ export interface XmlSourceLimits extends XmlStepLimits {
|
|
|
67
67
|
readonly storeNamespaces?: boolean;
|
|
68
68
|
/** Store attribute collections through host requests and emit resolved attributes individually. */
|
|
69
69
|
readonly storeAttributes?: boolean;
|
|
70
|
-
readonly
|
|
70
|
+
readonly fragmentAttributes?: boolean;
|
|
71
|
+
readonly onAttribute?: (attribute: XmlAttribute, element: XmlElement, continuation?: boolean) => void;
|
|
71
72
|
}
|
|
72
73
|
export type XmlParseStep = XmlSourceStep | XmlFrameRequest | XmlNamespaceRequest | XmlAttributeRequest;
|
|
73
74
|
/** Parse a validated, BOM-free, line-normalized UTF-16 source via bounded read requests. */
|
|
@@ -102,7 +102,7 @@ function* entity(source, start, end, recover) {
|
|
|
102
102
|
return String.fromCodePoint(point);
|
|
103
103
|
}
|
|
104
104
|
/** Decoded text fragments; source read/work requests remain host-serviced. */
|
|
105
|
-
function* textParts(source, start, end, decode, recover) {
|
|
105
|
+
function* textParts(source, start, end, decode, recover, attribute = false) {
|
|
106
106
|
let cursor = start;
|
|
107
107
|
while (cursor < end) {
|
|
108
108
|
let finish = Math.min(end, cursor + 512);
|
|
@@ -111,7 +111,13 @@ function* textParts(source, start, end, decode, recover) {
|
|
|
111
111
|
if (last >= 0xd800 && last <= 0xdbff)
|
|
112
112
|
finish--;
|
|
113
113
|
}
|
|
114
|
-
|
|
114
|
+
let raw = yield* source.slice(cursor, finish);
|
|
115
|
+
if (attribute) {
|
|
116
|
+
let normalized = "";
|
|
117
|
+
for (const character of raw)
|
|
118
|
+
normalized += "\t\n\r".includes(character) ? " " : character;
|
|
119
|
+
raw = normalized;
|
|
120
|
+
}
|
|
115
121
|
const found = decode ? raw.indexOf("&") : -1;
|
|
116
122
|
if (found < 0) {
|
|
117
123
|
yield raw;
|
|
@@ -140,9 +146,9 @@ function* textParts(source, start, end, decode, recover) {
|
|
|
140
146
|
cursor = semicolon + 1;
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
|
-
function* textFragments(source, start, end, decode, recover) {
|
|
149
|
+
function* textFragments(source, start, end, decode, recover, attribute = false) {
|
|
144
150
|
let pending = "";
|
|
145
|
-
for (const part of textParts(source, start, end, decode, recover)) {
|
|
151
|
+
for (const part of textParts(source, start, end, decode, recover, attribute)) {
|
|
146
152
|
if (typeof part !== "string") {
|
|
147
153
|
yield part;
|
|
148
154
|
continue;
|
|
@@ -254,6 +260,8 @@ function validateLimits(limits) {
|
|
|
254
260
|
}
|
|
255
261
|
export function* parseXmlSourceSteps(length, limits = {}) {
|
|
256
262
|
validateLimits(limits);
|
|
263
|
+
if (limits.fragmentAttributes && !limits.storeAttributes)
|
|
264
|
+
throw new TypeError("XML attribute fragments require storeAttributes: true");
|
|
257
265
|
if (limits.storeFrames && limits.retainTree !== false)
|
|
258
266
|
throw new TypeError("Stored XML frames require retainTree: false");
|
|
259
267
|
if (limits.storeAttributes && limits.retainTree !== false)
|
|
@@ -600,22 +608,45 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
600
608
|
}
|
|
601
609
|
if (end < 0)
|
|
602
610
|
invalid("unterminated attribute");
|
|
603
|
-
const
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
yield
|
|
607
|
-
|
|
611
|
+
const fragmented = limits.fragmentAttributes && attribute !== "xmlns" && attrPrefix !== "xmlns";
|
|
612
|
+
let value = "";
|
|
613
|
+
if (fragmented) {
|
|
614
|
+
if ((yield* source.indexOf("<", offset, end)) >= 0)
|
|
615
|
+
invalid("less-than in attribute");
|
|
616
|
+
let size = 0;
|
|
617
|
+
for (const part of textFragments(source, offset, end, true, limits.recover, true)) {
|
|
618
|
+
if (typeof part !== "string")
|
|
619
|
+
yield part;
|
|
620
|
+
else
|
|
621
|
+
size += part.length;
|
|
622
|
+
}
|
|
623
|
+
if (size > maxTextLength - textLength)
|
|
624
|
+
throw new XmlLimitError("maxTextLength", "XML text limit exceeded");
|
|
625
|
+
textLength += size;
|
|
608
626
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
627
|
+
else {
|
|
628
|
+
const raw = (yield* source.slice(offset, end));
|
|
629
|
+
pendingWork += raw.length * 2;
|
|
630
|
+
while (pendingWork >= 512) {
|
|
631
|
+
yield 512;
|
|
632
|
+
pendingWork -= 512;
|
|
633
|
+
}
|
|
634
|
+
if (raw.indexOf("<") >= 0)
|
|
635
|
+
invalid("less-than in attribute");
|
|
636
|
+
let normalized = raw;
|
|
637
|
+
if (raw.includes("\t") || raw.includes("\n") || raw.includes("\r")) {
|
|
638
|
+
normalized = "";
|
|
639
|
+
for (const character of raw)
|
|
640
|
+
normalized += "\t\n\r".includes(character) ? " " : character;
|
|
641
|
+
}
|
|
642
|
+
value = normalized.indexOf("&") < 0 ? (pendingWork += normalized.length, normalized) : yield* entities(normalized, limits.recover);
|
|
643
|
+
while (pendingWork >= 512) {
|
|
644
|
+
yield 512;
|
|
645
|
+
pendingWork -= 512;
|
|
646
|
+
}
|
|
647
|
+
admitText(value);
|
|
616
648
|
}
|
|
617
|
-
|
|
618
|
-
yield* attributes.append(attribute, attrPrefix, attrLocal, value);
|
|
649
|
+
yield* attributes.append(attribute, attrPrefix, attrLocal, value, fragmented ? { start: offset, end } : undefined);
|
|
619
650
|
offset = end + 1;
|
|
620
651
|
if (attribute === "xmlns" || attribute.startsWith("xmlns:")) {
|
|
621
652
|
const nsPrefix = attribute === "xmlns" ? "" : attribute.slice(6);
|
|
@@ -718,8 +749,22 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
718
749
|
cursor = attribute.next;
|
|
719
750
|
const namespace = attribute.name === "xmlns" || attribute.prefix === "xmlns" ? xmlnsNamespace
|
|
720
751
|
: attribute.prefix ? (yield* namespaceValue(namespaces, attribute.prefix)) : "";
|
|
721
|
-
|
|
722
|
-
|
|
752
|
+
let continuation = false;
|
|
753
|
+
if (attribute.source) {
|
|
754
|
+
for (const part of textFragments(source, attribute.source.start, attribute.source.end, true, limits.recover ? () => { } : undefined, true)) {
|
|
755
|
+
if (typeof part !== "string") {
|
|
756
|
+
yield part;
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
limits.onAttribute({ name: attribute.name, localName: attribute.localName, namespace, value: part }, element, continuation);
|
|
760
|
+
continuation = true;
|
|
761
|
+
yield 1;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (!continuation) {
|
|
765
|
+
limits.onAttribute({ name: attribute.name, localName: attribute.localName, namespace, value: attribute.value }, element);
|
|
766
|
+
yield 1;
|
|
767
|
+
}
|
|
723
768
|
}
|
|
724
769
|
}
|
|
725
770
|
if (!empty)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.799",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
"saxes"
|
|
178
178
|
],
|
|
179
179
|
"optionalDependencies": {
|
|
180
|
-
"toolcraft-schema": "0.0.
|
|
180
|
+
"toolcraft-schema": "0.0.799",
|
|
181
181
|
"toolcraft-design": "*",
|
|
182
182
|
"@poe-code/frontmatter": "*",
|
|
183
183
|
"@poe-code/agent-mcp-config": "*",
|