toolcraft 0.0.781 → 0.0.783
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 +7 -0
- package/node_modules/@poe-code/xml-ast/dist/index.d.ts +1 -1
- package/node_modules/@poe-code/xml-ast/dist/stream.d.ts +13 -0
- package/node_modules/@poe-code/xml-ast/dist/stream.js +24 -8
- 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.783",
|
|
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.783",
|
|
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.783",
|
|
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.783",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -35,3 +35,10 @@ For validation or root-name detection, pass `retainTree: false` to `parseXmlStre
|
|
|
35
35
|
Use `streamElements: { matches, consume }` to process selected complete subtrees asynchronously. Matching non-root elements are detached from their parent; nested matches remain inside the selected ancestor. `consume(element, parent, before?)` runs in source order and is awaited before the next 512-unit parse window. The producer closes on consumer failure. This mode requires normal tree/content retention and retains each selected subtree until consumption; individual large subtrees and XML tokens still need their own storage strategy.
|
|
36
36
|
|
|
37
37
|
Set `streamElements.captureBefore: true` to detach preceding sibling content when each subtree is selected and receive it as `before`. This preserves text, CDATA, comments and sibling order even when multiple subtrees share one parse window. The remaining trailing content stays in the parent. Store both `before` and the subtree when you need to reconstruct the original mixed content.
|
|
38
|
+
|
|
39
|
+
`parseXmlStream` also accepts `events` with `retainTree: false` to consume ordered
|
|
40
|
+
open, content and close events without constructing a document tree. Each parser
|
|
41
|
+
window awaits the consumer before advancing. Event elements contain names,
|
|
42
|
+
attributes and namespace metadata; individual XML tokens and open ancestry still
|
|
43
|
+
remain resident. This mode lets a caller own document storage independently of
|
|
44
|
+
the codec. Consumer failures propagate unchanged and close the input iterator.
|
|
@@ -42,4 +42,4 @@ export interface XmlLimits {
|
|
|
42
42
|
}
|
|
43
43
|
export declare function parseXmlSteps(input: string, limits?: XmlLimits): Generator<number, XmlElement, void>;
|
|
44
44
|
export declare function parseXml(input: string, limits?: XmlLimits): XmlElement;
|
|
45
|
-
export { parseXmlStream, type XmlStreamLimits } from "./stream.js";
|
|
45
|
+
export { parseXmlStream, type XmlStreamLimits, type XmlStreamEvent } from "./stream.js";
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import type { XmlContent, XmlElement, XmlLimits, XmlName } from "./index.js";
|
|
2
|
+
export type XmlStreamEvent = {
|
|
3
|
+
readonly type: "open" | "close";
|
|
4
|
+
readonly element: XmlElement;
|
|
5
|
+
readonly parent: XmlElement | undefined;
|
|
6
|
+
} | {
|
|
7
|
+
readonly type: "content";
|
|
8
|
+
readonly content: Exclude<XmlContent, XmlElement>;
|
|
9
|
+
readonly parent: XmlElement | undefined;
|
|
10
|
+
};
|
|
2
11
|
export interface XmlStreamLimits extends XmlLimits {
|
|
3
12
|
/** Validate the full document but return only its root name, without a retained tree. */
|
|
4
13
|
readonly retainTree?: boolean;
|
|
14
|
+
/** Ordered node events, awaited after each parser window. Requires retainTree:
|
|
15
|
+
* false; elements carry metadata without child/content arrays. Individual XML
|
|
16
|
+
* tokens remain resident until the underlying parser completes them. */
|
|
17
|
+
readonly events?: (event: XmlStreamEvent) => void | Promise<void>;
|
|
5
18
|
/** Detach selected non-root subtrees and await their consumer before parsing
|
|
6
19
|
* the next 512-unit window. By default nested matches belong to the selected ancestor. */
|
|
7
20
|
readonly streamElements?: {
|
|
@@ -16,6 +16,11 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
16
16
|
}
|
|
17
17
|
function charge(key, value = 1) { counters[key] += value; bound(key, counters[key]); }
|
|
18
18
|
const retainContent = limits.retainContent !== false, tree = limits.retainTree !== false, retain = tree && retainContent;
|
|
19
|
+
const events = limits.events;
|
|
20
|
+
if (events && tree)
|
|
21
|
+
throw new TypeError("XML events require retainTree: false");
|
|
22
|
+
const describe = retain || !!events;
|
|
23
|
+
const queued = [];
|
|
19
24
|
const streaming = limits.streamElements;
|
|
20
25
|
if (streaming && !retain)
|
|
21
26
|
throw new TypeError("XML subtree streaming requires retained content and tree mode");
|
|
@@ -28,7 +33,7 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
28
33
|
const parser = new SaxesParser({ xmlns: true, defaultXMLVersion: "1.0", forceXMLVersion: true });
|
|
29
34
|
parser.on("error", error => { throw new SyntaxError(`Invalid XML: ${error.message}`); });
|
|
30
35
|
parser.on("doctype", () => { throw new SyntaxError("Invalid XML: DTD and entity declarations are forbidden"); });
|
|
31
|
-
let prefix = "", capturing =
|
|
36
|
+
let prefix = "", capturing = describe;
|
|
32
37
|
parser.on("xmldecl", value => {
|
|
33
38
|
const encoding = value.encoding?.toUpperCase();
|
|
34
39
|
if (value.version !== "1.0" || encoding !== undefined &&
|
|
@@ -36,7 +41,7 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
36
41
|
limits.expectedEncoding !== undefined && encoding !== limits.expectedEncoding &&
|
|
37
42
|
!(encoding === "UTF-16" && ["UTF-16LE", "UTF-16BE"].includes(limits.expectedEncoding))))
|
|
38
43
|
throw new SyntaxError("Invalid XML: unsupported XML declaration");
|
|
39
|
-
if (
|
|
44
|
+
if (describe)
|
|
40
45
|
declaration = prefix.slice(0, prefix.indexOf("?>") + 2);
|
|
41
46
|
prefix = "";
|
|
42
47
|
capturing = false;
|
|
@@ -72,11 +77,11 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
72
77
|
parent.element.text = '';
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
|
-
charge("maxContentNodes", 1 + (retainContent ? attrs.length : 0));
|
|
80
|
+
charge("maxContentNodes", 1 + (retainContent || events ? attrs.length : 0));
|
|
76
81
|
const element = { kind: "element", ...name, children: [], content: [], text: "",
|
|
77
|
-
attributes:
|
|
78
|
-
namespaces:
|
|
79
|
-
...(!root &&
|
|
82
|
+
attributes: describe ? attrs.map(attr => ({ name: attr.name, localName: attr.local, namespace: attr.uri, value: attr.value })) : [],
|
|
83
|
+
namespaces: describe ? namespaces : emptyNamespaces,
|
|
84
|
+
...(!root && describe ? { prolog, epilog, ...(declaration === undefined ? {} : { declaration }) } : {}) };
|
|
80
85
|
if (parent && tree && !selected) {
|
|
81
86
|
parent.element.children.push(element);
|
|
82
87
|
if (retain)
|
|
@@ -85,9 +90,13 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
85
90
|
else if (!parent)
|
|
86
91
|
root = element;
|
|
87
92
|
stack.push({ element, namespaces, selected, before });
|
|
93
|
+
if (events)
|
|
94
|
+
queued.push({ type: "open", element, parent: parent?.element });
|
|
88
95
|
});
|
|
89
96
|
parser.on("closetag", () => {
|
|
90
97
|
const frame = stack.pop();
|
|
98
|
+
if (events)
|
|
99
|
+
queued.push({ type: "close", element: frame.element, parent: stack.at(-1)?.element });
|
|
91
100
|
if (frame.selected) {
|
|
92
101
|
completed.push({ element: frame.element, parent: stack.at(-1).element, before: frame.before });
|
|
93
102
|
selectedCount--;
|
|
@@ -99,11 +108,18 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
99
108
|
await streaming.consume(entry.element, entry.parent, entry.before);
|
|
100
109
|
}
|
|
101
110
|
completed.length = 0;
|
|
111
|
+
for (const event of queued) {
|
|
112
|
+
await checkpoint?.(0);
|
|
113
|
+
await events(event);
|
|
114
|
+
}
|
|
115
|
+
queued.length = 0;
|
|
102
116
|
}
|
|
103
117
|
function append(content) {
|
|
104
118
|
charge("maxTextLength", content.text.length);
|
|
105
119
|
charge("maxContentNodes");
|
|
106
120
|
const parent = stack.at(-1)?.element;
|
|
121
|
+
if (events)
|
|
122
|
+
queued.push({ type: "content", content, parent });
|
|
107
123
|
if (tree && parent && (content.kind === "text" || content.kind === "cdata"))
|
|
108
124
|
parent.text += content.text;
|
|
109
125
|
if (retain)
|
|
@@ -148,14 +164,14 @@ export async function parseXmlStream(source, limits = {}, checkpoint) {
|
|
|
148
164
|
for (let i = 0; i < text.length; i += 512) {
|
|
149
165
|
await checkpoint?.(0);
|
|
150
166
|
write(text.slice(i, i + 512));
|
|
151
|
-
if (completed.length)
|
|
167
|
+
if (completed.length || queued.length)
|
|
152
168
|
await drain();
|
|
153
169
|
await checkpoint?.(Math.min(512, text.length - i));
|
|
154
170
|
}
|
|
155
171
|
}
|
|
156
172
|
await checkpoint?.(0);
|
|
157
173
|
parser.close();
|
|
158
|
-
if (completed.length)
|
|
174
|
+
if (completed.length || queued.length)
|
|
159
175
|
await drain();
|
|
160
176
|
if (!root)
|
|
161
177
|
throw new SyntaxError("Invalid XML: incomplete document");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.783",
|
|
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.783",
|
|
181
181
|
"toolcraft-design": "*",
|
|
182
182
|
"@poe-code/frontmatter": "*",
|
|
183
183
|
"@poe-code/agent-mcp-config": "*",
|