toolcraft 0.0.799 → 0.0.801
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/dist/human-in-loop/approval-tasks.js +3 -0
- package/dist/human-in-loop/plan-hash.js +6 -1
- package/dist/runtime.d.ts +6 -2
- package/node_modules/@poe-code/safe-fs/dist/core.d.ts +1 -1
- package/node_modules/@poe-code/xml-ast/README.md +38 -9
- package/node_modules/@poe-code/xml-ast/dist/attributes.d.ts +18 -3
- package/node_modules/@poe-code/xml-ast/dist/attributes.js +6 -6
- package/node_modules/@poe-code/xml-ast/dist/frames.d.ts +22 -4
- package/node_modules/@poe-code/xml-ast/dist/frames.js +26 -4
- package/node_modules/@poe-code/xml-ast/dist/index.d.ts +20 -2
- package/node_modules/@poe-code/xml-ast/dist/index.js +121 -36
- package/node_modules/@poe-code/xml-ast/dist/source.d.ts +4 -0
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +1 -0
- 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.801",
|
|
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.801",
|
|
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.801",
|
|
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.801",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -136,6 +136,9 @@ function getTaskListDirectory(taskList) {
|
|
|
136
136
|
return isTaskListConfig(taskList) ? taskList.dir : "unknown";
|
|
137
137
|
}
|
|
138
138
|
function isDeepEqualStateMachine(left, right) {
|
|
139
|
+
if (left.initial !== right.initial) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
139
142
|
if (!areEqualStrings(left.states, right.states)) {
|
|
140
143
|
return false;
|
|
141
144
|
}
|
|
@@ -44,7 +44,12 @@ function normalizePlan(value, seen) {
|
|
|
44
44
|
}
|
|
45
45
|
const normalized = {};
|
|
46
46
|
for (const key of Object.keys(value).sort()) {
|
|
47
|
-
normalized
|
|
47
|
+
Object.defineProperty(normalized, key, {
|
|
48
|
+
value: normalizePlan(value[key], seen),
|
|
49
|
+
enumerable: true,
|
|
50
|
+
writable: true,
|
|
51
|
+
configurable: true
|
|
52
|
+
});
|
|
48
53
|
}
|
|
49
54
|
return normalized;
|
|
50
55
|
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -227,10 +227,14 @@ export interface CommandRequirementOptions {
|
|
|
227
227
|
}
|
|
228
228
|
export declare function resolveCommandSecrets(command: Command<any, any, any, any>, env?: Record<string, string | undefined>): Record<string, string | undefined>;
|
|
229
229
|
export declare function assertCommandRequirements(command: Command<any, any, any, any>, context: GroupCheckContext<any>, options?: CommandRequirementOptions): Promise<void>;
|
|
230
|
-
export declare function defineCommand<TServices extends object = EmptyServices, TName extends string = string, TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TResult = unknown, TOwnScope extends ScopeInput = undefined, TOwnHumanInLoop extends
|
|
230
|
+
export declare function defineCommand<TServices extends object = EmptyServices, TName extends string = string, TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TResult = unknown, TOwnScope extends ScopeInput = undefined, TOwnHumanInLoop extends {
|
|
231
|
+
mode: HumanInLoopMode;
|
|
232
|
+
} | null | undefined = undefined>(config: Omit<CommandConfig<TServices, TParamsSchema, TSecrets, TResult>, "name" | "scope" | "humanInLoop"> & {
|
|
231
233
|
name: TName;
|
|
232
234
|
scope?: TOwnScope;
|
|
233
|
-
humanInLoop?: TOwnHumanInLoop
|
|
235
|
+
humanInLoop?: (TOwnHumanInLoop | {
|
|
236
|
+
[K in keyof TOwnHumanInLoop]: TOwnHumanInLoop[K];
|
|
237
|
+
}) & (HumanInLoopConfig<TParamsSchema> | null);
|
|
234
238
|
}): Command<TServices, TParamsSchema, TSecrets, TResult> & TypedCommandMetadata<TName, TParamsSchema, TResult, TOwnScope, ResolveOwnHumanInLoopMode<TOwnHumanInLoop>>;
|
|
235
239
|
export declare function defineStreamCommand<TServices extends object = EmptyServices, TName extends string = string, TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TEventSchema extends AnySchema = AnySchema, TOwnScope extends ScopeInput = undefined>(config: Omit<StreamCommandConfig<TServices, TParamsSchema, TSecrets, TEventSchema>, "name" | "scope"> & {
|
|
236
240
|
name: TName;
|
|
@@ -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, XmlAttributeRequest, XmlAttributeRecord } from "./xml.js";
|
|
12
|
+
export type { XmlName, XmlAttribute, XmlContent, XmlElement, XmlLimits, XmlParserFrame, XmlFrameRequest, XmlNamespaceScope, XmlNamespaceRequest, XmlSourceRead, XmlSourceSpan, 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";
|
|
@@ -64,31 +64,48 @@ size cost. The default string and stream APIs retain their existing ancestry beh
|
|
|
64
64
|
|
|
65
65
|
Also set `storeNamespaces: true` to resolve namespace scopes through host-backed
|
|
66
66
|
immutable storage. `namespaceOperation: "get"` supplies a scope and prefix; fill
|
|
67
|
-
`value` when present and set `complete: true`. For `"
|
|
67
|
+
`value` when present and set `complete: true`. For `"has"`, fill `found` using
|
|
68
|
+
membership without reading the URI value. For `"set"`, bind the supplied prefix
|
|
68
69
|
and value in a new scope, then fill `result` with its storage `reference` and the
|
|
69
70
|
number of distinct bindings (`size`). Frames carry this scope handle so shadowing
|
|
70
71
|
never changes ancestor scopes. In this mode event elements have an empty
|
|
71
72
|
`namespaces` map; their names and attributes still carry resolved namespace URIs.
|
|
72
|
-
The codec remains filesystem-independent
|
|
73
|
-
|
|
73
|
+
The codec remains filesystem-independent. With `deferNamespaces: true`, resolved
|
|
74
|
+
URI metadata uses optional `namespaceReference` handles instead of complete strings.
|
|
75
|
+
Service `namespaceOperation: "reference"` by supplying the token `reference` when
|
|
76
|
+
present and setting `complete: true`. These handles belong to the host scope store;
|
|
77
|
+
retain or stream them before retiring that store. Built-in xml/xmlns names keep
|
|
78
|
+
their short namespace strings. Individual names still retain their token cost;
|
|
79
|
+
attribute values can use the fragment protocol below.
|
|
74
80
|
|
|
75
81
|
Set `storeAttributes: true` to move current-tag attribute values, source order,
|
|
76
82
|
and duplicate-name state behind `attributeOperation` requests (`has`, `append`,
|
|
77
83
|
`read`, and `expanded`). Service the request's `found` or `result` field as described
|
|
78
|
-
by `XmlAttributeRequest`, keeping records in caller-owned backing.
|
|
84
|
+
by `XmlAttributeRequest`, keeping records in caller-owned backing. When namespace
|
|
85
|
+
storage is also enabled, `expanded` supplies the local name and a `namespace` scope
|
|
86
|
+
and prefix. Check the pair of resolved URI and local name without joining them in
|
|
87
|
+
memory; an empty prefix means no attribute namespace, regardless of the default
|
|
88
|
+
element namespace. With this flag,
|
|
79
89
|
element `attributes` arrays are empty. Supply `onAttribute(attribute, element)` to
|
|
80
90
|
receive resolved attributes in source order, after the open event and before any
|
|
81
91
|
content or close event. The parser yields between attributes so a host can await
|
|
82
92
|
storage or a consumer. Namespace declarations may follow prefixed attributes;
|
|
83
93
|
resolution and duplicate-expanded-name validation still happen after the complete
|
|
84
|
-
start tag. With `fragmentAttributes: true`, ordinary values are validated
|
|
85
|
-
stored as
|
|
94
|
+
start tag. With `fragmentAttributes: true`, ordinary values are validated through source spans; all attribute
|
|
95
|
+
values are stored as spans on attribute records and replayed in at most 512 UTF-16
|
|
86
96
|
units. Hosts must preserve the optional `source` field in append/read requests.
|
|
87
97
|
The third `onAttribute` argument is `true` for continuations of the same logical
|
|
88
98
|
attribute; await each fragment before requesting the next step. Empty attributes
|
|
89
99
|
still emit once. Entity diagnostics are emitted during validation, not replay.
|
|
90
|
-
This mode requires `storeAttributes: true`.
|
|
91
|
-
|
|
100
|
+
This mode requires `storeAttributes: true`. Combining it with `storeNamespaces`
|
|
101
|
+
also validates namespace declarations in bounded fragments. A namespace `set`
|
|
102
|
+
request's `value` may then be a generator: strings are decoded value fragments,
|
|
103
|
+
numbers are work checkpoints, and objects are source-read requests. Service each
|
|
104
|
+
step before advancing, consume the complete value before filling `result`, and
|
|
105
|
+
close the producer if storage fails. Reserved URI checks preserve their diagnostic
|
|
106
|
+
order without joining fragments. Expanded-name events return complete URI strings
|
|
107
|
+
unless deferred namespace metadata is enabled; individual names still retain
|
|
108
|
+
their token cost.
|
|
92
109
|
|
|
93
110
|
Pass `undefined` as the source length to parse incrementally. Such read requests
|
|
94
111
|
have `streaming: true` and request at most 512 UTF-16 units. Return any nonempty
|
|
@@ -107,4 +124,16 @@ decoding replay bounded source windows before publishing a logical node, retaini
|
|
|
107
124
|
its diagnostic and limit ordering. Numeric entity references are decoded without
|
|
108
125
|
materializing the token. Set `compactDeclaration: true` to retain normalized declaration fields without
|
|
109
126
|
copying long whitespace spans; validation always reads bounded windows. The
|
|
110
|
-
buffered API keeps the original declaration spelling.
|
|
127
|
+
buffered API keeps the original declaration spelling.
|
|
128
|
+
|
|
129
|
+
Combine `fragmentContent` with `deferContentNames: true` to validate long
|
|
130
|
+
processing-instruction targets through source windows. Their events have an empty
|
|
131
|
+
`target` and a `targetSource` span; replay that span before retiring the source.
|
|
132
|
+
All body continuations carry the same target span. Short targets remain strings.
|
|
133
|
+
The stored document engine transfers these spans to its own token store and
|
|
134
|
+
streams targets during output. With `deferElementNames: true` and `retainTree: false`, long element local names
|
|
135
|
+
also use `nameSource`/`localNameSource` spans. Closing tags compare source windows;
|
|
136
|
+
element events retain the short `prefix` separately. Stored documents copy these
|
|
137
|
+
names into token references for formatting, XPath and xq grouping. Attribute names
|
|
138
|
+
and namespace prefixes longer than 512 UTF-16 units still retain their token cost;
|
|
139
|
+
this option does not impose a name-length limit.
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import type { XmlSourceSpan } from "./source.js";
|
|
2
|
+
import type { XmlNamespaceScope } from "./frames.js";
|
|
1
3
|
export interface XmlAttributeRecord {
|
|
2
4
|
name: string;
|
|
3
5
|
prefix: string;
|
|
4
6
|
localName: string;
|
|
5
7
|
value: string;
|
|
6
8
|
next: number;
|
|
9
|
+
nameSource?: XmlSourceSpan;
|
|
10
|
+
localNameSource?: XmlSourceSpan;
|
|
11
|
+
prefixSource?: XmlSourceSpan;
|
|
7
12
|
source?: {
|
|
8
13
|
start: number;
|
|
9
14
|
end: number;
|
|
@@ -19,7 +24,13 @@ export type XmlAttributeRequest = {
|
|
|
19
24
|
attributeOperation: 'has' | 'expanded';
|
|
20
25
|
state: XmlAttributeState;
|
|
21
26
|
name: string;
|
|
27
|
+
nameSource?: XmlSourceSpan;
|
|
22
28
|
found?: boolean;
|
|
29
|
+
namespace?: {
|
|
30
|
+
scope: XmlNamespaceScope;
|
|
31
|
+
prefix: string;
|
|
32
|
+
prefixSource?: XmlSourceSpan;
|
|
33
|
+
};
|
|
23
34
|
} | {
|
|
24
35
|
attributeOperation: 'append';
|
|
25
36
|
state: XmlAttributeState;
|
|
@@ -44,11 +55,15 @@ export declare class XmlAttributes {
|
|
|
44
55
|
get length(): number;
|
|
45
56
|
get size(): number;
|
|
46
57
|
get first(): number;
|
|
47
|
-
has(name: string): Generator<XmlAttributeRequest, boolean, void>;
|
|
58
|
+
has(name: string, nameSource?: XmlSourceSpan): Generator<XmlAttributeRequest, boolean, void>;
|
|
48
59
|
append(name: string, prefix: string, localName: string, value: string, source?: {
|
|
49
60
|
start: number;
|
|
50
61
|
end: number;
|
|
51
|
-
}): Generator<XmlAttributeRequest, void, void>;
|
|
62
|
+
}, nameSource?: XmlSourceSpan, localNameSource?: XmlSourceSpan, prefixSource?: XmlSourceSpan): Generator<XmlAttributeRequest, void, void>;
|
|
52
63
|
read(reference: number, values: boolean): Generator<XmlAttributeRequest, XmlAttributeRecord, void>;
|
|
53
|
-
expanded(name: string
|
|
64
|
+
expanded(name: string, namespace?: {
|
|
65
|
+
scope: XmlNamespaceScope;
|
|
66
|
+
prefix: string;
|
|
67
|
+
prefixSource?: XmlSourceSpan;
|
|
68
|
+
}, nameSource?: XmlSourceSpan): Generator<XmlAttributeRequest, boolean, void>;
|
|
54
69
|
}
|
|
@@ -12,25 +12,25 @@ export class XmlAttributes {
|
|
|
12
12
|
get length() { return this.state.length; }
|
|
13
13
|
get size() { return this.state.size; }
|
|
14
14
|
get first() { return this.state.first; }
|
|
15
|
-
*has(name) {
|
|
15
|
+
*has(name, nameSource) {
|
|
16
16
|
if (!this.length)
|
|
17
17
|
return false;
|
|
18
18
|
if (!this.external)
|
|
19
19
|
return this.names.has(name);
|
|
20
|
-
const request = { attributeOperation: 'has', state: this.state, name };
|
|
20
|
+
const request = { attributeOperation: 'has', state: this.state, name, ...(nameSource ? { nameSource } : {}) };
|
|
21
21
|
yield request;
|
|
22
22
|
if (request.found === undefined)
|
|
23
23
|
throw new TypeError('Incomplete XML attribute lookup');
|
|
24
24
|
return request.found;
|
|
25
25
|
}
|
|
26
|
-
*append(name, prefix, localName, value, source) {
|
|
26
|
+
*append(name, prefix, localName, value, source, nameSource, localNameSource, prefixSource) {
|
|
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, ...(source ? { source } : {}) } };
|
|
33
|
+
const request = { attributeOperation: 'append', state: this.state, attribute: { name, prefix, localName, value, ...(source ? { source } : {}), ...(nameSource ? { nameSource } : {}), ...(localNameSource ? { localNameSource } : {}), ...(prefixSource ? { prefixSource } : {}) } };
|
|
34
34
|
yield request;
|
|
35
35
|
if (!request.result)
|
|
36
36
|
throw new TypeError('Incomplete XML attribute append');
|
|
@@ -47,13 +47,13 @@ export class XmlAttributes {
|
|
|
47
47
|
throw new TypeError('Incomplete XML attribute read');
|
|
48
48
|
return request.result;
|
|
49
49
|
}
|
|
50
|
-
*expanded(name) {
|
|
50
|
+
*expanded(name, namespace, nameSource) {
|
|
51
51
|
if (!this.external) {
|
|
52
52
|
const found = this.expandedNames.has(name);
|
|
53
53
|
this.expandedNames.add(name);
|
|
54
54
|
return found;
|
|
55
55
|
}
|
|
56
|
-
const request = { attributeOperation: 'expanded', state: this.state, name };
|
|
56
|
+
const request = { attributeOperation: 'expanded', state: this.state, name, ...(namespace ? { namespace } : {}), ...(nameSource ? { nameSource } : {}) };
|
|
57
57
|
yield request;
|
|
58
58
|
if (request.found === undefined)
|
|
59
59
|
throw new TypeError('Incomplete XML expanded attribute lookup');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { XmlSourceStep, XmlSourceSpan } from './source.js';
|
|
2
|
+
import type { XmlContent, XmlElement, XmlName } from './index.js';
|
|
2
3
|
export interface XmlParserFrame {
|
|
3
4
|
element: XmlElement;
|
|
4
5
|
content: XmlContent[] | undefined;
|
|
@@ -33,17 +34,34 @@ export interface XmlNamespaceScope {
|
|
|
33
34
|
readonly size: number;
|
|
34
35
|
}
|
|
35
36
|
export type XmlNamespaceRequest = {
|
|
37
|
+
readonly namespaceOperation: 'reference';
|
|
38
|
+
readonly scope: XmlNamespaceScope;
|
|
39
|
+
readonly prefix: string;
|
|
40
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
41
|
+
reference?: number;
|
|
42
|
+
complete?: true;
|
|
43
|
+
} | {
|
|
44
|
+
readonly namespaceOperation: 'has';
|
|
45
|
+
readonly scope: XmlNamespaceScope;
|
|
46
|
+
readonly prefix: string;
|
|
47
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
48
|
+
found?: boolean;
|
|
49
|
+
} | {
|
|
36
50
|
readonly namespaceOperation: 'get';
|
|
37
51
|
readonly scope: XmlNamespaceScope;
|
|
38
52
|
readonly prefix: string;
|
|
53
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
39
54
|
value?: string;
|
|
40
55
|
complete?: true;
|
|
41
56
|
} | {
|
|
42
57
|
readonly namespaceOperation: 'set';
|
|
43
58
|
readonly scope: XmlNamespaceScope;
|
|
44
59
|
readonly prefix: string;
|
|
45
|
-
readonly
|
|
60
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
61
|
+
readonly value: string | Generator<XmlSourceStep | string, void, void>;
|
|
46
62
|
result?: XmlNamespaceScope;
|
|
47
63
|
};
|
|
48
|
-
export declare function namespaceValue(scope: Map<string, string> | XmlNamespaceScope, prefix: string): Generator<XmlNamespaceRequest, string | undefined, void>;
|
|
49
|
-
export declare function
|
|
64
|
+
export declare function namespaceValue(scope: Map<string, string> | XmlNamespaceScope, prefix: string, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, string | undefined, void>;
|
|
65
|
+
export declare function namespaceMetadata(scope: Map<string, string> | XmlNamespaceScope, prefix: string, deferred?: boolean, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, Pick<XmlName, 'namespace' | 'namespaceReference'>, void>;
|
|
66
|
+
export declare function hasNamespace(scope: Map<string, string> | XmlNamespaceScope, prefix: string, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, boolean, void>;
|
|
67
|
+
export declare function bindNamespace(scope: Map<string, string> | XmlNamespaceScope, prefix: string, value: string | Generator<XmlSourceStep | string, void, void>, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, Map<string, string> | XmlNamespaceScope, void>;
|
|
@@ -43,21 +43,43 @@ export class XmlFrames {
|
|
|
43
43
|
return frame;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
export function* namespaceValue(scope, prefix) {
|
|
46
|
+
export function* namespaceValue(scope, prefix, prefixSource) {
|
|
47
47
|
if (scope instanceof Map)
|
|
48
48
|
return scope.get(prefix);
|
|
49
|
-
const request = { namespaceOperation: 'get', scope, prefix };
|
|
49
|
+
const request = { namespaceOperation: 'get', scope, prefix, ...(prefixSource ? { prefixSource } : {}) };
|
|
50
50
|
yield request;
|
|
51
51
|
if (!request.complete)
|
|
52
52
|
throw new TypeError('Incomplete XML namespace read');
|
|
53
53
|
return request.value;
|
|
54
54
|
}
|
|
55
|
-
export function*
|
|
55
|
+
export function* namespaceMetadata(scope, prefix, deferred = false, prefixSource) {
|
|
56
|
+
if (!deferred || scope instanceof Map)
|
|
57
|
+
return { namespace: (yield* namespaceValue(scope, prefix, prefixSource)) ?? '' };
|
|
58
|
+
if (prefix === 'xml')
|
|
59
|
+
return { namespace: 'http://www.w3.org/XML/1998/namespace' };
|
|
60
|
+
const request = { namespaceOperation: 'reference', scope, prefix, ...(prefixSource ? { prefixSource } : {}) };
|
|
61
|
+
yield request;
|
|
62
|
+
if (!request.complete)
|
|
63
|
+
throw new TypeError('Incomplete XML namespace reference lookup');
|
|
64
|
+
return { namespace: '', ...(request.reference === undefined ? {} : { namespaceReference: request.reference }) };
|
|
65
|
+
}
|
|
66
|
+
export function* hasNamespace(scope, prefix, prefixSource) {
|
|
67
|
+
if (scope instanceof Map)
|
|
68
|
+
return scope.has(prefix);
|
|
69
|
+
const request = { namespaceOperation: 'has', scope, prefix, ...(prefixSource ? { prefixSource } : {}) };
|
|
70
|
+
yield request;
|
|
71
|
+
if (request.found === undefined)
|
|
72
|
+
throw new TypeError('Incomplete XML namespace membership lookup');
|
|
73
|
+
return request.found;
|
|
74
|
+
}
|
|
75
|
+
export function* bindNamespace(scope, prefix, value, prefixSource) {
|
|
56
76
|
if (scope instanceof Map) {
|
|
77
|
+
if (typeof value !== 'string')
|
|
78
|
+
throw new TypeError('Streamed XML namespace values require external scopes');
|
|
57
79
|
scope.set(prefix, value);
|
|
58
80
|
return scope;
|
|
59
81
|
}
|
|
60
|
-
const request = { namespaceOperation: 'set', scope, prefix, value };
|
|
82
|
+
const request = { namespaceOperation: 'set', scope, prefix, value, ...(prefixSource ? { prefixSource } : {}) };
|
|
61
83
|
yield request;
|
|
62
84
|
if (!request.result)
|
|
63
85
|
throw new TypeError('Incomplete XML namespace update');
|
|
@@ -3,13 +3,21 @@ export type { XmlAttributeRequest, XmlAttributeRecord, XmlAttributeState } from
|
|
|
3
3
|
import { type XmlNamespaceRequest, type XmlFrameRequest } from "./frames.js";
|
|
4
4
|
export type { XmlParserFrame, XmlFrameRequest, XmlNamespaceScope, XmlNamespaceRequest } from "./frames.js";
|
|
5
5
|
export { normalizeXmlChunks } from "./characters.js";
|
|
6
|
-
import { type XmlSourceStep } from "./source.js";
|
|
7
|
-
export type { XmlSourceRead, XmlSourceStep } from "./source.js";
|
|
6
|
+
import { type XmlSourceSpan, type XmlSourceStep } from "./source.js";
|
|
7
|
+
export type { XmlSourceRead, XmlSourceSpan, XmlSourceStep } from "./source.js";
|
|
8
8
|
import type { XmlStreamEvent } from "./stream.js";
|
|
9
9
|
export { XmlLimitError } from "./errors.js";
|
|
10
10
|
export interface XmlName {
|
|
11
11
|
readonly name: string;
|
|
12
|
+
readonly nameSource?: XmlSourceSpan;
|
|
13
|
+
readonly nameReference?: number;
|
|
14
|
+
readonly localNameSource?: XmlSourceSpan;
|
|
15
|
+
readonly localNameReference?: number;
|
|
16
|
+
readonly prefix?: string;
|
|
17
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
18
|
+
readonly prefixReference?: number;
|
|
12
19
|
readonly namespace: string;
|
|
20
|
+
readonly namespaceReference?: number;
|
|
13
21
|
readonly localName: string;
|
|
14
22
|
}
|
|
15
23
|
export interface XmlAttribute extends XmlName {
|
|
@@ -21,6 +29,8 @@ export type XmlContent = XmlElement | {
|
|
|
21
29
|
} | {
|
|
22
30
|
readonly kind: "processing-instruction";
|
|
23
31
|
readonly target: string;
|
|
32
|
+
readonly targetSource?: XmlSourceSpan;
|
|
33
|
+
readonly targetReference?: number;
|
|
24
34
|
readonly text: string;
|
|
25
35
|
};
|
|
26
36
|
export interface XmlElement extends XmlName {
|
|
@@ -65,6 +75,14 @@ export interface XmlSourceLimits extends XmlStepLimits {
|
|
|
65
75
|
readonly storeFrames?: boolean;
|
|
66
76
|
/** Resolve namespace scopes through host-serviced requests. Requires retainTree: false. */
|
|
67
77
|
readonly storeNamespaces?: boolean;
|
|
78
|
+
/** Carry host namespace token references in event metadata. Requires stored namespaces. */
|
|
79
|
+
readonly deferNamespaces?: boolean;
|
|
80
|
+
/** Emit long processing-instruction targets as source spans. Requires fragmentContent. */
|
|
81
|
+
readonly deferContentNames?: boolean;
|
|
82
|
+
/** Defer long element names and, with external namespaces, their prefixes. */
|
|
83
|
+
readonly deferElementNames?: boolean;
|
|
84
|
+
/** Defer attribute names and namespace declaration prefixes to source spans. */
|
|
85
|
+
readonly deferAttributeNames?: boolean;
|
|
68
86
|
/** Store attribute collections through host requests and emit resolved attributes individually. */
|
|
69
87
|
readonly storeAttributes?: boolean;
|
|
70
88
|
readonly fragmentAttributes?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { XmlAttributes } from "./attributes.js";
|
|
2
|
-
import { XmlFrames, bindNamespace, namespaceValue } from "./frames.js";
|
|
2
|
+
import { XmlFrames, bindNamespace, namespaceValue, namespaceMetadata, hasNamespace } from "./frames.js";
|
|
3
3
|
import { validCharacter } from "./characters.js";
|
|
4
4
|
export { normalizeXmlChunks } from "./characters.js";
|
|
5
5
|
import { XmlSource } from "./source.js";
|
|
@@ -68,6 +68,41 @@ function qualifiedNameSync(name, cache) {
|
|
|
68
68
|
}
|
|
69
69
|
return parts;
|
|
70
70
|
}
|
|
71
|
+
/** Validate a name span without retaining its spelling. */
|
|
72
|
+
function* validateNameSpan(source, start, end) {
|
|
73
|
+
let first = true, colon = -1, work = 0;
|
|
74
|
+
for (let offset = start; offset < end;) {
|
|
75
|
+
let point = yield* source.charCodeAt(offset);
|
|
76
|
+
if (point >= 0xd800 && point <= 0xdbff && offset + 1 < end) {
|
|
77
|
+
const low = yield* source.charCodeAt(offset + 1);
|
|
78
|
+
if (low >= 0xdc00 && low <= 0xdfff)
|
|
79
|
+
point = 0x10000 + (point - 0xd800) * 1024 + low - 0xdc00;
|
|
80
|
+
}
|
|
81
|
+
if (point === 58) {
|
|
82
|
+
if (colon >= 0 || first)
|
|
83
|
+
invalid("invalid qualified name");
|
|
84
|
+
colon = offset;
|
|
85
|
+
first = true;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
if (!(first ? nameStart(point) : namePart(point)))
|
|
89
|
+
invalid("invalid qualified name");
|
|
90
|
+
first = false;
|
|
91
|
+
}
|
|
92
|
+
const size = point > 0xffff ? 2 : 1;
|
|
93
|
+
offset += size;
|
|
94
|
+
work += size;
|
|
95
|
+
if (work >= 512) {
|
|
96
|
+
yield 512;
|
|
97
|
+
work -= 512;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (first)
|
|
101
|
+
invalid("invalid qualified name");
|
|
102
|
+
if (work)
|
|
103
|
+
yield work;
|
|
104
|
+
return colon;
|
|
105
|
+
}
|
|
71
106
|
function* entity(source, start, end, recover) {
|
|
72
107
|
// Inspect only a bounded prefix, even for arbitrarily long numeric references.
|
|
73
108
|
const prefix = typeof source === "string" ? source.slice(start, Math.min(end, start + 4))
|
|
@@ -260,12 +295,20 @@ function validateLimits(limits) {
|
|
|
260
295
|
}
|
|
261
296
|
export function* parseXmlSourceSteps(length, limits = {}) {
|
|
262
297
|
validateLimits(limits);
|
|
298
|
+
if (limits.deferAttributeNames && (!limits.storeAttributes || !limits.storeNamespaces))
|
|
299
|
+
throw new TypeError("Deferred attribute names require stored attributes and namespaces");
|
|
300
|
+
if (limits.deferElementNames && limits.retainTree !== false)
|
|
301
|
+
throw new TypeError("Deferred element names require retainTree: false");
|
|
302
|
+
if (limits.deferContentNames && !limits.fragmentContent)
|
|
303
|
+
throw new TypeError("Deferred XML content names require fragmentContent: true");
|
|
263
304
|
if (limits.fragmentAttributes && !limits.storeAttributes)
|
|
264
305
|
throw new TypeError("XML attribute fragments require storeAttributes: true");
|
|
265
306
|
if (limits.storeFrames && limits.retainTree !== false)
|
|
266
307
|
throw new TypeError("Stored XML frames require retainTree: false");
|
|
267
308
|
if (limits.storeAttributes && limits.retainTree !== false)
|
|
268
309
|
throw new TypeError("Stored XML attributes require retainTree: false");
|
|
310
|
+
if (limits.deferNamespaces && !limits.storeNamespaces)
|
|
311
|
+
throw new TypeError("Deferred XML namespaces require stored namespaces");
|
|
269
312
|
if (limits.storeNamespaces && limits.retainTree !== false)
|
|
270
313
|
throw new TypeError("Stored XML namespaces require retainTree: false");
|
|
271
314
|
if (limits.fragmentContent && limits.retainTree !== false)
|
|
@@ -322,7 +365,24 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
322
365
|
}
|
|
323
366
|
return offset - start;
|
|
324
367
|
};
|
|
325
|
-
const
|
|
368
|
+
const sameName = function* (left, right, span) {
|
|
369
|
+
if (!left.nameSource && !span)
|
|
370
|
+
return left.name === right;
|
|
371
|
+
const leftLength = left.nameSource ? left.nameSource.end - left.nameSource.start : left.name.length;
|
|
372
|
+
const rightLength = span ? span.end - span.start : right.length;
|
|
373
|
+
if (leftLength !== rightLength)
|
|
374
|
+
return false;
|
|
375
|
+
for (let index = 0; index < leftLength; index += 512) {
|
|
376
|
+
const end = Math.min(leftLength, index + 512);
|
|
377
|
+
const a = left.nameSource ? yield* source.slice(left.nameSource.start + index, left.nameSource.start + end) : left.name.slice(index, end);
|
|
378
|
+
const b = span ? yield* source.slice(span.start + index, span.start + end) : right.slice(index, end);
|
|
379
|
+
yield end - index;
|
|
380
|
+
if (a !== b)
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
return true;
|
|
384
|
+
};
|
|
385
|
+
const scanName = function* (defer) {
|
|
326
386
|
const start = offset;
|
|
327
387
|
while (yield* source.has(offset)) {
|
|
328
388
|
const c = (yield* source.charCodeAt(offset));
|
|
@@ -335,6 +395,21 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
335
395
|
pendingWork -= 512;
|
|
336
396
|
}
|
|
337
397
|
}
|
|
398
|
+
if (defer && offset - start > 512) {
|
|
399
|
+
const colon = yield* validateNameSpan(source, start, offset);
|
|
400
|
+
if (defer === "content")
|
|
401
|
+
return ["", "", "", { start, end: offset }];
|
|
402
|
+
if (colon - start > 512 && !limits.storeNamespaces) {
|
|
403
|
+
const name = yield* source.slice(start, offset);
|
|
404
|
+
return [name, name.slice(0, colon - start), name.slice(colon - start + 1)];
|
|
405
|
+
}
|
|
406
|
+
const localStart = colon < 0 ? start : colon + 1;
|
|
407
|
+
const prefixSource = colon - start > 512 ? { start, end: colon } : undefined;
|
|
408
|
+
const prefix = colon < 0 || prefixSource ? "" : yield* source.slice(start, colon);
|
|
409
|
+
const localNameSource = offset - localStart > 512 ? { start: localStart, end: offset } : undefined;
|
|
410
|
+
const local = localNameSource ? "" : yield* source.slice(localStart, offset);
|
|
411
|
+
return ["", prefix, local, { start, end: offset }, localNameSource, prefixSource];
|
|
412
|
+
}
|
|
338
413
|
const name = (yield* source.slice(start, offset));
|
|
339
414
|
pendingWork += offset - start;
|
|
340
415
|
while (pendingWork >= 512) {
|
|
@@ -344,7 +419,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
344
419
|
const [prefix, localName] = qualifiedNameSync(name, qualifiedNames);
|
|
345
420
|
return [name, prefix, localName];
|
|
346
421
|
};
|
|
347
|
-
const rawContent = function* (kind, start, end, parent, target = "") {
|
|
422
|
+
const rawContent = function* (kind, start, end, parent, target = "", targetSource) {
|
|
348
423
|
if (end - start > maxTextLength - textLength)
|
|
349
424
|
throw new XmlLimitError("maxTextLength", "XML text limit exceeded");
|
|
350
425
|
textLength += end - start;
|
|
@@ -358,7 +433,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
358
433
|
finish--;
|
|
359
434
|
}
|
|
360
435
|
const text = yield* source.slice(cursor, finish);
|
|
361
|
-
const content = kind === "processing-instruction" ? { kind, target, text } : { kind, text };
|
|
436
|
+
const content = kind === "processing-instruction" ? { kind, target, text, ...(targetSource ? { targetSource } : {}) } : { kind, text };
|
|
362
437
|
if (kind === "cdata" && retainTree)
|
|
363
438
|
parent.element.text += text;
|
|
364
439
|
if (retain)
|
|
@@ -494,7 +569,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
494
569
|
else if ((yield* source.startsWith("<?", offset))) {
|
|
495
570
|
const start = offset;
|
|
496
571
|
offset += 2;
|
|
497
|
-
const [target] = yield* scanName();
|
|
572
|
+
const [target, , , targetSource] = yield* scanName(limits.deferContentNames ? "content" : undefined);
|
|
498
573
|
while (pendingWork >= 512) {
|
|
499
574
|
yield 512;
|
|
500
575
|
pendingWork -= 512;
|
|
@@ -527,7 +602,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
527
602
|
yield 512;
|
|
528
603
|
pendingWork -= 512;
|
|
529
604
|
}
|
|
530
|
-
yield* rawContent("processing-instruction", body, end, yield* stack.peek(), target);
|
|
605
|
+
yield* rawContent("processing-instruction", body, end, yield* stack.peek(), target, targetSource);
|
|
531
606
|
}
|
|
532
607
|
offset = end + 2;
|
|
533
608
|
}
|
|
@@ -536,14 +611,14 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
536
611
|
}
|
|
537
612
|
else if ((yield* source.charCodeAt(offset + 1)) === 47) {
|
|
538
613
|
offset += 2;
|
|
539
|
-
const [name] = yield* scanName();
|
|
614
|
+
const [name, , , nameSource] = yield* scanName(limits.deferElementNames ? "element" : undefined);
|
|
540
615
|
yield* skipWhitespace();
|
|
541
616
|
while (pendingWork >= 512) {
|
|
542
617
|
yield 512;
|
|
543
618
|
pendingWork -= 512;
|
|
544
619
|
}
|
|
545
620
|
const closed = (yield* source.slice(offset++, offset)) === ">" ? (yield* stack.pop()) : undefined;
|
|
546
|
-
if (closed
|
|
621
|
+
if (!closed || !(yield* sameName(closed.element, name, nameSource))) {
|
|
547
622
|
if (!limits.recover)
|
|
548
623
|
invalid("mismatched closing tag");
|
|
549
624
|
limits.recover("mismatched closing tag");
|
|
@@ -554,9 +629,9 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
554
629
|
else {
|
|
555
630
|
offset++;
|
|
556
631
|
const repeated = previousEmpty && (yield* source.startsWith(previousEmpty.suffix, offset)) ? previousEmpty : undefined;
|
|
557
|
-
const [name, prefix, localName] = repeated
|
|
632
|
+
const [name, prefix, localName, nameSource, localNameSource, prefixSource] = repeated
|
|
558
633
|
? [repeated.name, repeated.prefix, repeated.localName]
|
|
559
|
-
: (yield* scanName());
|
|
634
|
+
: (yield* scanName(limits.deferElementNames ? "element" : undefined));
|
|
560
635
|
if (repeated)
|
|
561
636
|
offset += name.length;
|
|
562
637
|
// Preserve scan/validation work while reusing the admitted spelling.
|
|
@@ -581,12 +656,12 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
581
656
|
break;
|
|
582
657
|
if (ws === 0)
|
|
583
658
|
invalid("attributes require whitespace");
|
|
584
|
-
const [attribute, attrPrefix, attrLocal] = yield* scanName();
|
|
659
|
+
const [attribute, attrPrefix, attrLocal, nameSource, localNameSource, attrPrefixSource] = yield* scanName(limits.deferAttributeNames ? "attribute" : undefined);
|
|
585
660
|
while (pendingWork >= 512) {
|
|
586
661
|
yield 512;
|
|
587
662
|
pendingWork -= 512;
|
|
588
663
|
}
|
|
589
|
-
if ((yield* attributes.has(attribute)))
|
|
664
|
+
if ((yield* attributes.has(attribute, nameSource)))
|
|
590
665
|
invalid("duplicate attribute");
|
|
591
666
|
if (++attributeCount > maxAttributes)
|
|
592
667
|
throw new XmlLimitError("maxAttributes", "XML attribute limit exceeded");
|
|
@@ -608,18 +683,23 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
608
683
|
}
|
|
609
684
|
if (end < 0)
|
|
610
685
|
invalid("unterminated attribute");
|
|
611
|
-
const fragmented = limits.fragmentAttributes && attribute !== "xmlns" && attrPrefix !== "xmlns";
|
|
612
|
-
|
|
686
|
+
const fragmented = limits.fragmentAttributes && (limits.storeNamespaces || attribute !== "xmlns" && attrPrefix !== "xmlns");
|
|
687
|
+
const valueStart = offset;
|
|
688
|
+
let value = "", size = 0, matchesXml = true, matchesXmlns = true;
|
|
613
689
|
if (fragmented) {
|
|
614
690
|
if ((yield* source.indexOf("<", offset, end)) >= 0)
|
|
615
691
|
invalid("less-than in attribute");
|
|
616
|
-
let size = 0;
|
|
617
692
|
for (const part of textFragments(source, offset, end, true, limits.recover, true)) {
|
|
618
693
|
if (typeof part !== "string")
|
|
619
694
|
yield part;
|
|
620
|
-
else
|
|
695
|
+
else {
|
|
696
|
+
matchesXml = matchesXml && part === xmlNamespace.slice(size, size + part.length);
|
|
697
|
+
matchesXmlns = matchesXmlns && part === xmlnsNamespace.slice(size, size + part.length);
|
|
621
698
|
size += part.length;
|
|
699
|
+
}
|
|
622
700
|
}
|
|
701
|
+
matchesXml = matchesXml && size === xmlNamespace.length;
|
|
702
|
+
matchesXmlns = matchesXmlns && size === xmlnsNamespace.length;
|
|
623
703
|
if (size > maxTextLength - textLength)
|
|
624
704
|
throw new XmlLimitError("maxTextLength", "XML text limit exceeded");
|
|
625
705
|
textLength += size;
|
|
@@ -646,13 +726,14 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
646
726
|
}
|
|
647
727
|
admitText(value);
|
|
648
728
|
}
|
|
649
|
-
yield* attributes.append(attribute, attrPrefix, attrLocal, value,
|
|
729
|
+
yield* attributes.append(attribute, attrPrefix, attrLocal, value, limits.fragmentAttributes ? { start: offset, end } : undefined, nameSource, localNameSource, attrPrefixSource);
|
|
650
730
|
offset = end + 1;
|
|
651
|
-
if (attribute === "xmlns" ||
|
|
652
|
-
const nsPrefix = attribute === "xmlns" ? "" :
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|| (nsPrefix
|
|
731
|
+
if (attribute === "xmlns" || attrPrefix === "xmlns") {
|
|
732
|
+
const nsPrefix = attribute === "xmlns" ? "" : attrLocal;
|
|
733
|
+
const nsPrefixSource = attrPrefix === "xmlns" ? localNameSource : undefined;
|
|
734
|
+
if (nsPrefix === "xmlns" || (fragmented ? matchesXmlns : value === xmlnsNamespace)
|
|
735
|
+
|| (nsPrefix === "xml") !== (fragmented ? matchesXml : value === xmlNamespace)
|
|
736
|
+
|| ((nsPrefix !== "" || nsPrefixSource) && (fragmented ? size === 0 : value === "")))
|
|
656
737
|
invalid("invalid namespace binding");
|
|
657
738
|
if (!ownsNamespaces && namespaces instanceof Map) {
|
|
658
739
|
const copy = new Map();
|
|
@@ -663,7 +744,8 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
663
744
|
namespaces = copy;
|
|
664
745
|
ownsNamespaces = true;
|
|
665
746
|
}
|
|
666
|
-
namespaces = yield* bindNamespace(namespaces, nsPrefix,
|
|
747
|
+
namespaces = yield* bindNamespace(namespaces, nsPrefix, fragmented
|
|
748
|
+
? textFragments(source, valueStart, end, true, limits.recover ? () => { } : undefined, true) : value, nsPrefixSource);
|
|
667
749
|
if (namespaces.size > maxNamespaces)
|
|
668
750
|
throw new XmlLimitError("maxNamespaces", "XML namespace scope limit exceeded");
|
|
669
751
|
}
|
|
@@ -673,14 +755,15 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
673
755
|
const record = yield* attributes.read(cursor, false);
|
|
674
756
|
cursor = record.next;
|
|
675
757
|
const { name: attribute, prefix: attrPrefix, localName: attrLocal } = record;
|
|
676
|
-
if (attribute === "xmlns" ||
|
|
758
|
+
if (attribute === "xmlns" || attrPrefix === "xmlns")
|
|
677
759
|
continue;
|
|
678
760
|
pendingWork += attribute.length;
|
|
679
|
-
if (attrPrefix && (yield*
|
|
761
|
+
if ((attrPrefix || record.prefixSource) && !(yield* hasNamespace(namespaces, attrPrefix, record.prefixSource)))
|
|
680
762
|
invalid("unbound attribute prefix");
|
|
681
763
|
if (attributes.length > 1) {
|
|
682
|
-
const
|
|
683
|
-
|
|
764
|
+
const backed = limits.storeAttributes && !(namespaces instanceof Map) ? namespaces : undefined;
|
|
765
|
+
const key = backed ? attrLocal : `${attrPrefix ? (yield* namespaceValue(namespaces, attrPrefix)) : ""}\0${attrLocal}`;
|
|
766
|
+
if (yield* attributes.expanded(key, backed ? { scope: backed, prefix: attrPrefix, ...(record.prefixSource ? { prefixSource: record.prefixSource } : {}) } : undefined, record.localNameSource))
|
|
684
767
|
invalid("duplicate expanded attribute");
|
|
685
768
|
}
|
|
686
769
|
}
|
|
@@ -690,14 +773,15 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
690
773
|
yield 512;
|
|
691
774
|
pendingWork -= 512;
|
|
692
775
|
}
|
|
693
|
-
if (prefix === "xmlns" || (prefix && (yield*
|
|
776
|
+
if (prefix === "xmlns" || ((prefix || prefixSource) && !(yield* hasNamespace(namespaces, prefix, prefixSource))))
|
|
694
777
|
invalid("unbound element prefix");
|
|
695
778
|
if (++nodes > maxNodes)
|
|
696
779
|
throw new XmlLimitError("maxNodes", "XML resource limit exceeded");
|
|
697
780
|
if (stack.length + 1 > maxDepth)
|
|
698
781
|
throw new XmlLimitError("maxDepth", "XML resource limit exceeded");
|
|
699
|
-
const namespace =
|
|
700
|
-
|
|
782
|
+
const namespace = yield* namespaceMetadata(namespaces, prefix, limits.deferNamespaces, prefixSource);
|
|
783
|
+
const elementName = { name, localName, ...(nameSource ? { nameSource, prefix } : {}), ...(localNameSource ? { localNameSource } : {}), ...(prefixSource ? { prefixSource } : {}) };
|
|
784
|
+
limits.onElement?.({ ...elementName, ...namespace }, (yield* stack.peek())?.element, stack.length + 1);
|
|
701
785
|
admitContent();
|
|
702
786
|
const retainedAttributes = [];
|
|
703
787
|
if (retainContent) {
|
|
@@ -717,7 +801,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
717
801
|
pendingWork -= 512;
|
|
718
802
|
}
|
|
719
803
|
const content = retain ? [] : undefined;
|
|
720
|
-
const element = { kind: "element",
|
|
804
|
+
const element = { kind: "element", ...elementName, ...namespace, children: [], text: "", content: content ?? emptyContent, attributes: retainContent ? retainedAttributes : emptyAttributes, namespaces: retainContent && namespaces instanceof Map ? namespaces : emptyNamespaces, ...(root === undefined && retainContent ? { prolog, epilog, ...(declaration === undefined ? {} : { declaration }) } : {}) };
|
|
721
805
|
const parent = (yield* stack.peek());
|
|
722
806
|
if (parent) {
|
|
723
807
|
if (retainTree) {
|
|
@@ -739,7 +823,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
739
823
|
}
|
|
740
824
|
// Only cache compact, attribute-free spellings. Namespace resolution and
|
|
741
825
|
// every admission counter still run for each distinct physical element.
|
|
742
|
-
if (empty && !attributes.length && name.length <= 512 && (yield* source.slice(offset - name.length - 3, offset)) === `<${name}/>`)
|
|
826
|
+
if (empty && !nameSource && !attributes.length && name.length <= 512 && (yield* source.slice(offset - name.length - 3, offset)) === `<${name}/>`)
|
|
743
827
|
previousEmpty = { suffix: name + "/>", name, prefix, localName };
|
|
744
828
|
limits.events?.({ type: "open", element, parent: parent?.element });
|
|
745
829
|
if (limits.storeAttributes && limits.onAttribute && retainContent) {
|
|
@@ -747,8 +831,9 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
747
831
|
for (let cursor = attributes.first; cursor;) {
|
|
748
832
|
const attribute = yield* attributes.read(cursor, true);
|
|
749
833
|
cursor = attribute.next;
|
|
750
|
-
const namespace = attribute.name === "xmlns" || attribute.prefix === "xmlns" ? xmlnsNamespace
|
|
751
|
-
: attribute.prefix ?
|
|
834
|
+
const namespace = attribute.name === "xmlns" || attribute.prefix === "xmlns" ? { namespace: xmlnsNamespace }
|
|
835
|
+
: attribute.prefix || attribute.prefixSource ? yield* namespaceMetadata(namespaces, attribute.prefix, limits.deferNamespaces, attribute.prefixSource) : { namespace: "" };
|
|
836
|
+
const nameMetadata = { name: attribute.name, localName: attribute.localName, ...(attribute.nameSource ? { nameSource: attribute.nameSource, prefix: attribute.prefix } : {}), ...(attribute.localNameSource ? { localNameSource: attribute.localNameSource } : {}), ...(attribute.prefixSource ? { prefixSource: attribute.prefixSource } : {}) };
|
|
752
837
|
let continuation = false;
|
|
753
838
|
if (attribute.source) {
|
|
754
839
|
for (const part of textFragments(source, attribute.source.start, attribute.source.end, true, limits.recover ? () => { } : undefined, true)) {
|
|
@@ -756,13 +841,13 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
756
841
|
yield part;
|
|
757
842
|
continue;
|
|
758
843
|
}
|
|
759
|
-
limits.onAttribute({
|
|
844
|
+
limits.onAttribute({ ...nameMetadata, ...namespace, value: part }, element, continuation);
|
|
760
845
|
continuation = true;
|
|
761
846
|
yield 1;
|
|
762
847
|
}
|
|
763
848
|
}
|
|
764
849
|
if (!continuation) {
|
|
765
|
-
limits.onAttribute({
|
|
850
|
+
limits.onAttribute({ ...nameMetadata, ...namespace, value: attribute.value }, element);
|
|
766
851
|
yield 1;
|
|
767
852
|
}
|
|
768
853
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.801",
|
|
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.801",
|
|
181
181
|
"toolcraft-design": "*",
|
|
182
182
|
"@poe-code/frontmatter": "*",
|
|
183
183
|
"@poe-code/agent-mcp-config": "*",
|