toolcraft 0.0.797 → 0.0.798
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/safe-fs/dist/core.d.ts +1 -1
- package/node_modules/@poe-code/xml-ast/README.md +11 -0
- package/node_modules/@poe-code/xml-ast/dist/attributes.d.ts +47 -0
- package/node_modules/@poe-code/xml-ast/dist/attributes.js +62 -0
- package/node_modules/@poe-code/xml-ast/dist/index.d.ts +7 -1
- package/node_modules/@poe-code/xml-ast/dist/index.js +34 -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.798",
|
|
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.798",
|
|
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.798",
|
|
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.798",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -9,7 +9,7 @@ export * from "./fs/webdav/index.js";
|
|
|
9
9
|
export * from "./bridge/index.js";
|
|
10
10
|
export * from "./python/index.js";
|
|
11
11
|
export { parseXml, parseXmlSteps, parseXmlSourceSteps, normalizeXmlChunks, parseXmlStream, XmlLimitError } from "./xml.js";
|
|
12
|
-
export type { XmlName, XmlAttribute, XmlContent, XmlElement, XmlLimits, XmlParserFrame, XmlFrameRequest, XmlNamespaceScope, XmlNamespaceRequest } from "./xml.js";
|
|
12
|
+
export type { XmlName, XmlAttribute, XmlContent, XmlElement, XmlLimits, XmlParserFrame, XmlFrameRequest, XmlNamespaceScope, XmlNamespaceRequest, XmlAttributeRequest, XmlAttributeRecord } from "./xml.js";
|
|
13
13
|
export * from "./contracts/object.js";
|
|
14
14
|
export { ObjectAuthority } from "./fs/object-authority.js";
|
|
15
15
|
export * from "./fs/s3/index.js";
|
|
@@ -72,6 +72,17 @@ never changes ancestor scopes. In this mode event elements have an empty
|
|
|
72
72
|
The codec remains filesystem-independent, and individual names, attribute values
|
|
73
73
|
and namespace URIs still need a token storage strategy.
|
|
74
74
|
|
|
75
|
+
Set `storeAttributes: true` to move current-tag attribute values, source order,
|
|
76
|
+
and duplicate-name state behind `attributeOperation` requests (`has`, `append`,
|
|
77
|
+
`read`, and `expanded`). Service the request's `found` or `result` field as described
|
|
78
|
+
by `XmlAttributeRequest`, keeping records in caller-owned backing. With this flag,
|
|
79
|
+
element `attributes` arrays are empty. Supply `onAttribute(attribute, element)` to
|
|
80
|
+
receive resolved attributes in source order, after the open event and before any
|
|
81
|
+
content or close event. The parser yields between attributes so a host can await
|
|
82
|
+
storage or a consumer. Namespace declarations may follow prefixed attributes;
|
|
83
|
+
resolution and duplicate-expanded-name validation still happen after the complete
|
|
84
|
+
start tag. Individual attribute names and values retain their token cost.
|
|
85
|
+
|
|
75
86
|
Pass `undefined` as the source length to parse incrementally. Such read requests
|
|
76
87
|
have `streaming: true` and request at most 512 UTF-16 units. Return any nonempty
|
|
77
88
|
prefix available without pulling more input; set `complete: true` only when that
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface XmlAttributeRecord {
|
|
2
|
+
name: string;
|
|
3
|
+
prefix: string;
|
|
4
|
+
localName: string;
|
|
5
|
+
value: string;
|
|
6
|
+
next: number;
|
|
7
|
+
}
|
|
8
|
+
export interface XmlAttributeState {
|
|
9
|
+
reference: number;
|
|
10
|
+
first: number;
|
|
11
|
+
length: number;
|
|
12
|
+
size: number;
|
|
13
|
+
}
|
|
14
|
+
export type XmlAttributeRequest = {
|
|
15
|
+
attributeOperation: 'has' | 'expanded';
|
|
16
|
+
state: XmlAttributeState;
|
|
17
|
+
name: string;
|
|
18
|
+
found?: boolean;
|
|
19
|
+
} | {
|
|
20
|
+
attributeOperation: 'append';
|
|
21
|
+
state: XmlAttributeState;
|
|
22
|
+
attribute: Omit<XmlAttributeRecord, 'next'>;
|
|
23
|
+
result?: XmlAttributeState;
|
|
24
|
+
} | {
|
|
25
|
+
attributeOperation: 'read';
|
|
26
|
+
state: XmlAttributeState;
|
|
27
|
+
reference: number;
|
|
28
|
+
values: boolean;
|
|
29
|
+
result?: XmlAttributeRecord;
|
|
30
|
+
};
|
|
31
|
+
/** Buffered APIs use local collections; external parsing retains only a store
|
|
32
|
+
* handle and one current attribute. Hosts preserve order and last-value recovery. */
|
|
33
|
+
export declare class XmlAttributes {
|
|
34
|
+
private readonly external;
|
|
35
|
+
private state;
|
|
36
|
+
private readonly names;
|
|
37
|
+
private readonly records;
|
|
38
|
+
private readonly expandedNames;
|
|
39
|
+
constructor(external: boolean);
|
|
40
|
+
get length(): number;
|
|
41
|
+
get size(): number;
|
|
42
|
+
get first(): number;
|
|
43
|
+
has(name: string): Generator<XmlAttributeRequest, boolean, void>;
|
|
44
|
+
append(name: string, prefix: string, localName: string, value: string): Generator<XmlAttributeRequest, void, void>;
|
|
45
|
+
read(reference: number, values: boolean): Generator<XmlAttributeRequest, XmlAttributeRecord, void>;
|
|
46
|
+
expanded(name: string): Generator<XmlAttributeRequest, boolean, void>;
|
|
47
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Buffered APIs use local collections; external parsing retains only a store
|
|
2
|
+
* handle and one current attribute. Hosts preserve order and last-value recovery. */
|
|
3
|
+
export class XmlAttributes {
|
|
4
|
+
external;
|
|
5
|
+
state = { reference: 0, first: 0, length: 0, size: 0 };
|
|
6
|
+
names = new Map();
|
|
7
|
+
records = [];
|
|
8
|
+
expandedNames = new Set();
|
|
9
|
+
constructor(external) {
|
|
10
|
+
this.external = external;
|
|
11
|
+
}
|
|
12
|
+
get length() { return this.state.length; }
|
|
13
|
+
get size() { return this.state.size; }
|
|
14
|
+
get first() { return this.state.first; }
|
|
15
|
+
*has(name) {
|
|
16
|
+
if (!this.length)
|
|
17
|
+
return false;
|
|
18
|
+
if (!this.external)
|
|
19
|
+
return this.names.has(name);
|
|
20
|
+
const request = { attributeOperation: 'has', state: this.state, name };
|
|
21
|
+
yield request;
|
|
22
|
+
if (request.found === undefined)
|
|
23
|
+
throw new TypeError('Incomplete XML attribute lookup');
|
|
24
|
+
return request.found;
|
|
25
|
+
}
|
|
26
|
+
*append(name, prefix, localName, value) {
|
|
27
|
+
if (!this.external) {
|
|
28
|
+
this.names.set(name, value);
|
|
29
|
+
this.records.push({ name, prefix, localName });
|
|
30
|
+
this.state = { reference: 0, first: 1, length: this.records.length, size: this.names.size };
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const request = { attributeOperation: 'append', state: this.state, attribute: { name, prefix, localName, value } };
|
|
34
|
+
yield request;
|
|
35
|
+
if (!request.result)
|
|
36
|
+
throw new TypeError('Incomplete XML attribute append');
|
|
37
|
+
this.state = request.result;
|
|
38
|
+
}
|
|
39
|
+
*read(reference, values) {
|
|
40
|
+
if (!this.external) {
|
|
41
|
+
const attribute = this.records[reference - 1];
|
|
42
|
+
return { ...attribute, value: values ? this.names.get(attribute.name) : '', next: reference < this.length ? reference + 1 : 0 };
|
|
43
|
+
}
|
|
44
|
+
const request = { attributeOperation: 'read', state: this.state, reference, values };
|
|
45
|
+
yield request;
|
|
46
|
+
if (!request.result)
|
|
47
|
+
throw new TypeError('Incomplete XML attribute read');
|
|
48
|
+
return request.result;
|
|
49
|
+
}
|
|
50
|
+
*expanded(name) {
|
|
51
|
+
if (!this.external) {
|
|
52
|
+
const found = this.expandedNames.has(name);
|
|
53
|
+
this.expandedNames.add(name);
|
|
54
|
+
return found;
|
|
55
|
+
}
|
|
56
|
+
const request = { attributeOperation: 'expanded', state: this.state, name };
|
|
57
|
+
yield request;
|
|
58
|
+
if (request.found === undefined)
|
|
59
|
+
throw new TypeError('Incomplete XML expanded attribute lookup');
|
|
60
|
+
return request.found;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type XmlAttributeRequest } from "./attributes.js";
|
|
2
|
+
export type { XmlAttributeRequest, XmlAttributeRecord, XmlAttributeState } from "./attributes.js";
|
|
1
3
|
import { type XmlNamespaceRequest, type XmlFrameRequest } from "./frames.js";
|
|
2
4
|
export type { XmlParserFrame, XmlFrameRequest, XmlNamespaceScope, XmlNamespaceRequest } from "./frames.js";
|
|
3
5
|
export { normalizeXmlChunks } from "./characters.js";
|
|
@@ -63,12 +65,16 @@ export interface XmlSourceLimits extends XmlStepLimits {
|
|
|
63
65
|
readonly storeFrames?: boolean;
|
|
64
66
|
/** Resolve namespace scopes through host-serviced requests. Requires retainTree: false. */
|
|
65
67
|
readonly storeNamespaces?: boolean;
|
|
68
|
+
/** Store attribute collections through host requests and emit resolved attributes individually. */
|
|
69
|
+
readonly storeAttributes?: boolean;
|
|
70
|
+
readonly onAttribute?: (attribute: XmlAttribute, element: XmlElement) => void;
|
|
66
71
|
}
|
|
67
|
-
export type XmlParseStep = XmlSourceStep | XmlFrameRequest | XmlNamespaceRequest;
|
|
72
|
+
export type XmlParseStep = XmlSourceStep | XmlFrameRequest | XmlNamespaceRequest | XmlAttributeRequest;
|
|
68
73
|
/** Parse a validated, BOM-free, line-normalized UTF-16 source via bounded read requests. */
|
|
69
74
|
export declare function parseXmlSourceSteps(length: number | undefined, limits?: XmlStepLimits & {
|
|
70
75
|
readonly storeFrames?: false;
|
|
71
76
|
readonly storeNamespaces?: false;
|
|
77
|
+
readonly storeAttributes?: false;
|
|
72
78
|
}): Generator<XmlSourceStep, XmlElement, void>;
|
|
73
79
|
export declare function parseXmlSourceSteps(length: number | undefined, limits: XmlSourceLimits): Generator<XmlParseStep, XmlElement, void>;
|
|
74
80
|
export declare function parseXmlSteps(input: string, limits?: XmlStepLimits): Generator<number, XmlElement, void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { XmlAttributes } from "./attributes.js";
|
|
1
2
|
import { XmlFrames, bindNamespace, namespaceValue } from "./frames.js";
|
|
2
3
|
import { validCharacter } from "./characters.js";
|
|
3
4
|
export { normalizeXmlChunks } from "./characters.js";
|
|
@@ -255,6 +256,8 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
255
256
|
validateLimits(limits);
|
|
256
257
|
if (limits.storeFrames && limits.retainTree !== false)
|
|
257
258
|
throw new TypeError("Stored XML frames require retainTree: false");
|
|
259
|
+
if (limits.storeAttributes && limits.retainTree !== false)
|
|
260
|
+
throw new TypeError("Stored XML attributes require retainTree: false");
|
|
258
261
|
if (limits.storeNamespaces && limits.retainTree !== false)
|
|
259
262
|
throw new TypeError("Stored XML namespaces require retainTree: false");
|
|
260
263
|
if (limits.fragmentContent && limits.retainTree !== false)
|
|
@@ -555,8 +558,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
555
558
|
yield 512;
|
|
556
559
|
pendingWork -= 512;
|
|
557
560
|
}
|
|
558
|
-
|
|
559
|
-
const attrMeta = [];
|
|
561
|
+
const attributes = new XmlAttributes(limits.storeAttributes === true);
|
|
560
562
|
const namespaceParent = yield* stack.peek();
|
|
561
563
|
let namespaces = namespaceParent?.namespaceScope ?? namespaceParent?.namespaces ?? (initialNamespaces instanceof Map ? new Map(initialNamespaces) : initialNamespaces);
|
|
562
564
|
let ownsNamespaces = stack.length === 0;
|
|
@@ -576,11 +578,11 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
576
578
|
yield 512;
|
|
577
579
|
pendingWork -= 512;
|
|
578
580
|
}
|
|
579
|
-
if (attributes
|
|
581
|
+
if ((yield* attributes.has(attribute)))
|
|
580
582
|
invalid("duplicate attribute");
|
|
581
583
|
if (++attributeCount > maxAttributes)
|
|
582
584
|
throw new XmlLimitError("maxAttributes", "XML attribute limit exceeded");
|
|
583
|
-
if (
|
|
585
|
+
if (attributes.size >= maxAttributesPerElement)
|
|
584
586
|
throw new XmlLimitError("maxAttributesPerElement", "XML attribute limit exceeded");
|
|
585
587
|
yield* skipWhitespace();
|
|
586
588
|
if ((yield* source.slice(offset++, offset)) !== "=")
|
|
@@ -613,8 +615,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
613
615
|
pendingWork -= 512;
|
|
614
616
|
}
|
|
615
617
|
admitText(value);
|
|
616
|
-
|
|
617
|
-
attrMeta.push([attribute, attrPrefix, attrLocal]);
|
|
618
|
+
yield* attributes.append(attribute, attrPrefix, attrLocal, value);
|
|
618
619
|
offset = end + 1;
|
|
619
620
|
if (attribute === "xmlns" || attribute.startsWith("xmlns:")) {
|
|
620
621
|
const nsPrefix = attribute === "xmlns" ? "" : attribute.slice(6);
|
|
@@ -636,20 +637,20 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
636
637
|
throw new XmlLimitError("maxNamespaces", "XML namespace scope limit exceeded");
|
|
637
638
|
}
|
|
638
639
|
}
|
|
639
|
-
if (
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
640
|
+
if (attributes.length > 0) {
|
|
641
|
+
for (let cursor = attributes.first; cursor;) {
|
|
642
|
+
const record = yield* attributes.read(cursor, false);
|
|
643
|
+
cursor = record.next;
|
|
644
|
+
const { name: attribute, prefix: attrPrefix, localName: attrLocal } = record;
|
|
643
645
|
if (attribute === "xmlns" || attribute.startsWith("xmlns:"))
|
|
644
646
|
continue;
|
|
645
647
|
pendingWork += attribute.length;
|
|
646
648
|
if (attrPrefix && (yield* namespaceValue(namespaces, attrPrefix)) === undefined)
|
|
647
649
|
invalid("unbound attribute prefix");
|
|
648
|
-
if (
|
|
650
|
+
if (attributes.length > 1) {
|
|
649
651
|
const key = `${attrPrefix ? (yield* namespaceValue(namespaces, attrPrefix)) : ""}\0${attrLocal}`;
|
|
650
|
-
if (expanded
|
|
652
|
+
if (yield* attributes.expanded(key))
|
|
651
653
|
invalid("duplicate expanded attribute");
|
|
652
|
-
expanded.add(key);
|
|
653
654
|
}
|
|
654
655
|
}
|
|
655
656
|
}
|
|
@@ -668,13 +669,15 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
668
669
|
limits.onElement?.({ name, namespace, localName }, (yield* stack.peek())?.element, stack.length + 1);
|
|
669
670
|
admitContent();
|
|
670
671
|
const retainedAttributes = [];
|
|
671
|
-
if (retainContent
|
|
672
|
-
for (let
|
|
673
|
-
const
|
|
674
|
-
|
|
672
|
+
if (retainContent) {
|
|
673
|
+
for (let cursor = attributes.first; cursor;) {
|
|
674
|
+
const record = yield* attributes.read(cursor, !limits.storeAttributes);
|
|
675
|
+
cursor = record.next;
|
|
676
|
+
const { name: attribute, prefix: attrPrefix, localName: attrLocal, value } = record;
|
|
675
677
|
admitContent();
|
|
676
|
-
|
|
677
|
-
|
|
678
|
+
if (!limits.storeAttributes)
|
|
679
|
+
retainedAttributes.push({ name: attribute, localName: attrLocal,
|
|
680
|
+
namespace: attribute === "xmlns" || attrPrefix === "xmlns" ? xmlnsNamespace : attrPrefix ? (yield* namespaceValue(namespaces, attrPrefix)) : "", value });
|
|
678
681
|
pendingWork += attribute.length + 1;
|
|
679
682
|
}
|
|
680
683
|
}
|
|
@@ -705,9 +708,20 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
705
708
|
}
|
|
706
709
|
// Only cache compact, attribute-free spellings. Namespace resolution and
|
|
707
710
|
// every admission counter still run for each distinct physical element.
|
|
708
|
-
if (empty && !attributes && name.length <= 512 && (yield* source.slice(offset - name.length - 3, offset)) === `<${name}/>`)
|
|
711
|
+
if (empty && !attributes.length && name.length <= 512 && (yield* source.slice(offset - name.length - 3, offset)) === `<${name}/>`)
|
|
709
712
|
previousEmpty = { suffix: name + "/>", name, prefix, localName };
|
|
710
713
|
limits.events?.({ type: "open", element, parent: parent?.element });
|
|
714
|
+
if (limits.storeAttributes && limits.onAttribute && retainContent) {
|
|
715
|
+
yield 1;
|
|
716
|
+
for (let cursor = attributes.first; cursor;) {
|
|
717
|
+
const attribute = yield* attributes.read(cursor, true);
|
|
718
|
+
cursor = attribute.next;
|
|
719
|
+
const namespace = attribute.name === "xmlns" || attribute.prefix === "xmlns" ? xmlnsNamespace
|
|
720
|
+
: attribute.prefix ? (yield* namespaceValue(namespaces, attribute.prefix)) : "";
|
|
721
|
+
limits.onAttribute({ name: attribute.name, localName: attribute.localName, namespace, value: attribute.value }, element);
|
|
722
|
+
yield 1;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
711
725
|
if (!empty)
|
|
712
726
|
yield* stack.push({ element, content, name, namespaces: namespaces instanceof Map ? namespaces : new Map(), ...(namespaces instanceof Map ? {} : { namespaceScope: namespaces }) });
|
|
713
727
|
else
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.798",
|
|
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.798",
|
|
181
181
|
"toolcraft-design": "*",
|
|
182
182
|
"@poe-code/frontmatter": "*",
|
|
183
183
|
"@poe-code/agent-mcp-config": "*",
|