@techspokes/typescript-wsdl-client 1.1.8 → 1.2.0
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/README.md +17 -3
- package/dist/checkedPlanning.js +27 -4
- package/dist/cli.js +17 -1
- package/dist/client/generateClient.js +72 -16
- package/dist/client/generateOperations.js +30 -11
- package/dist/client/generateUtils.js +5 -1
- package/dist/compiler/canonicalGraph.d.ts +4 -15
- package/dist/compiler/canonicalGraph.js +1 -8
- package/dist/compiler/componentRecordProjection.d.ts +3 -0
- package/dist/compiler/componentRecordProjection.js +10 -0
- package/dist/compiler/declarationIdentity.d.ts +22 -0
- package/dist/compiler/declarationIdentity.js +9 -0
- package/dist/compiler/directCodec.d.ts +22 -2
- package/dist/compiler/directCodec.js +40 -7
- package/dist/compiler/directOperation.d.ts +26 -4
- package/dist/compiler/directOperation.js +59 -5
- package/dist/compiler/directSoap.js +24 -7
- package/dist/compiler/directSourceCapsule.js +59 -3
- package/dist/compiler/directStructure.js +6 -2
- package/dist/compiler/directStructurePlan.d.ts +10 -1
- package/dist/compiler/directStructurePlan.js +27 -7
- package/dist/compiler/directValues.d.ts +15 -3
- package/dist/compiler/directValues.js +20 -4
- package/dist/compiler/legacyDeclarations.d.ts +26 -0
- package/dist/compiler/legacyDeclarations.js +144 -0
- package/dist/compiler/projectionScalar.d.ts +18 -1
- package/dist/compiler/projectionScalar.js +47 -13
- package/dist/compiler/rpcStringValues.d.ts +30 -0
- package/dist/compiler/rpcStringValues.js +196 -0
- package/dist/compiler/rpcTypedValues.d.ts +48 -0
- package/dist/compiler/rpcTypedValues.js +190 -0
- package/dist/compiler/schemaCompiler.js +44 -109
- package/dist/compiler/semanticCatalog.d.ts +2 -2
- package/dist/gateway/generateComposedGateway.d.ts +16 -0
- package/dist/gateway/generateComposedGateway.js +65 -0
- package/dist/gateway/generateGateway.js +1 -0
- package/dist/gateway/generators.js +19 -4
- package/dist/gateway/helpers.d.ts +1 -0
- package/dist/gateway/helpers.js +15 -0
- package/dist/generation/componentShape.js +25 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/loader/orderedSyntax.d.ts +4 -0
- package/dist/loader/orderedSyntax.js +18 -4
- package/dist/multiServicePipeline.d.ts +41 -0
- package/dist/multiServicePipeline.js +287 -0
- package/dist/openapi/composeOpenAPI.d.ts +29 -0
- package/dist/openapi/composeOpenAPI.js +322 -0
- package/dist/pipeline.d.ts +1 -1
- package/dist/pipeline.js +2 -0
- package/docs/agent-skill.md +10 -1
- package/docs/api-reference.md +127 -9
- package/docs/checked-gateway.md +2 -0
- package/docs/checked-generation.md +11 -5
- package/docs/cli-reference.md +25 -5
- package/docs/concepts.md +4 -5
- package/docs/configuration.md +10 -3
- package/docs/corpus.md +1 -1
- package/docs/gateway-guide.md +104 -27
- package/docs/generated-code.md +12 -6
- package/docs/migration-playbook.md +4 -0
- package/docs/migration.md +124 -6
- package/docs/output-anatomy.md +20 -17
- package/docs/production.md +7 -5
- package/docs/start-here.md +12 -2
- package/docs/supported-patterns.md +17 -0
- package/docs/testing.md +2 -0
- package/docs/troubleshooting.md +3 -1
- package/llms.txt +9 -1
- package/package.json +2 -2
- package/src/runtime/clientStreamMethods.tpl.txt +156 -148
- package/src/runtime/operationsStreamHelper.tpl.txt +6 -6
- package/src/runtime/streamXml.ts +48 -20
package/src/runtime/streamXml.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* Q4 (saxes placement): runtime dependency of the wsdl-tsc package; the
|
|
18
18
|
* generated client imports the emitted copy of this module and
|
|
19
19
|
* inherits saxes via its own dependency tree.
|
|
20
|
+
* @since Unreleased
|
|
20
21
|
*/
|
|
21
22
|
import {SaxesParser, type SaxesTagPlain} from "saxes";
|
|
22
23
|
|
|
@@ -42,6 +43,8 @@ export interface RecordParseSpec {
|
|
|
42
43
|
* detection only.
|
|
43
44
|
*/
|
|
44
45
|
childType?: Record<string, Record<string, string>>;
|
|
46
|
+
/** Explicit repeated XML properties; when supplied, child-type [] hints describe list values instead. */
|
|
47
|
+
repeatedElements?: Record<string, readonly string[]>;
|
|
45
48
|
/**
|
|
46
49
|
* Compiled-catalog prop-meta map: carries min/max/nillable/declaredType.
|
|
47
50
|
* When present, `max > 1` or `max === "unbounded"` drives array emission
|
|
@@ -58,12 +61,12 @@ export interface PropMeta {
|
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
/**
|
|
61
|
-
* Consume
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* the
|
|
64
|
+
* Consume XML bytes or strings and yield complete legacy record nodes.
|
|
65
|
+
* @param source - Single-pass XML bytes or strings; UTF-8 byte boundaries may split characters.
|
|
66
|
+
* @param spec - Local-name record path and optional catalog metadata; attribute bags remain lexical strings.
|
|
67
|
+
* @returns Complete records without buffering the complete XML document.
|
|
68
|
+
* @throws Error for malformed XML, SOAP Body faults, or an empty record path.
|
|
69
|
+
* @constraints Exhaust or return the single-pass iterator to release its source; undeclared xsi:nil remains accepted for legacy compatibility.
|
|
67
70
|
*/
|
|
68
71
|
export async function* parseRecords<T = unknown>(
|
|
69
72
|
source: AsyncIterable<string | Uint8Array>,
|
|
@@ -75,9 +78,12 @@ export async function* parseRecords<T = unknown>(
|
|
|
75
78
|
throw new Error("parseRecords: recordPath must not be empty");
|
|
76
79
|
}
|
|
77
80
|
const attrsKey = spec.attributesKey ?? "$attributes";
|
|
81
|
+
const decoder = new TextDecoder("utf-8");
|
|
78
82
|
|
|
79
83
|
// Global tag stack, maintained across the entire document.
|
|
80
84
|
const stack: string[] = [];
|
|
85
|
+
const namespaces: Array<Record<string, string>> = [];
|
|
86
|
+
const elementNamespaces: string[] = [];
|
|
81
87
|
// Records materialized during the current chunk write, awaiting yield.
|
|
82
88
|
const pending: T[] = [];
|
|
83
89
|
// When a parser.on('error') fires we buffer the error for re-throw on the
|
|
@@ -102,11 +108,27 @@ export async function* parseRecords<T = unknown>(
|
|
|
102
108
|
const openNodes: OpenNode[] = [];
|
|
103
109
|
|
|
104
110
|
parser.on("opentag", (tag: SaxesTagPlain) => {
|
|
105
|
-
|
|
111
|
+
const inherited = namespaces.at(-1);
|
|
112
|
+
const scope: Record<string, string> = Object.assign(Object.create(null) as Record<string, string>, inherited);
|
|
113
|
+
for (const [name, value] of Object.entries(tag.attributes)) {
|
|
114
|
+
if (name === "xmlns") scope[""] = value;
|
|
115
|
+
else if (name.startsWith("xmlns:")) scope[name.slice(6)] = value;
|
|
116
|
+
}
|
|
117
|
+
const localName = local(tag.name);
|
|
118
|
+
const prefix = tag.name.includes(":") ? tag.name.slice(0, tag.name.indexOf(":")) : "";
|
|
119
|
+
const namespace = scope[prefix] ?? "";
|
|
120
|
+
if (localName === "Fault" && namespace === elementNamespaces.at(-1) &&
|
|
121
|
+
(namespace === "http://schemas.xmlsoap.org/soap/envelope/" || namespace === "http://www.w3.org/2003/05/soap-envelope") &&
|
|
122
|
+
stack.at(-1) === "Body") {
|
|
123
|
+
parseError = new Error("SOAP Fault received in stream response");
|
|
124
|
+
}
|
|
125
|
+
namespaces.push(scope);
|
|
126
|
+
elementNamespaces.push(namespace);
|
|
127
|
+
stack.push(localName);
|
|
106
128
|
if (openNodes.length === 0) {
|
|
107
129
|
// Not yet inside a record. Check whether entering the path tail.
|
|
108
130
|
if (tailMatches(stack, recordPath)) {
|
|
109
|
-
openNodes.push(newNode(tag, spec.recordTypeName, null, attrsKey));
|
|
131
|
+
openNodes.push(newNode(tag, spec.recordTypeName, null, attrsKey, scope));
|
|
110
132
|
}
|
|
111
133
|
return;
|
|
112
134
|
}
|
|
@@ -114,9 +136,9 @@ export async function* parseRecords<T = unknown>(
|
|
|
114
136
|
const parent = openNodes[openNodes.length - 1];
|
|
115
137
|
parent.hadChildren = true;
|
|
116
138
|
const parentType = parent.typeName;
|
|
117
|
-
const childTypeRaw = parentType ? spec.childType?.[parentType]?.[
|
|
139
|
+
const childTypeRaw = parentType ? spec.childType?.[parentType]?.[localName] : undefined;
|
|
118
140
|
const childTypeName = childTypeRaw ? stripArraySuffix(childTypeRaw) : null;
|
|
119
|
-
openNodes.push(newNode(tag, childTypeName,
|
|
141
|
+
openNodes.push(newNode(tag, childTypeName, localName, attrsKey, scope));
|
|
120
142
|
});
|
|
121
143
|
|
|
122
144
|
const appendText = (t: string) => {
|
|
@@ -139,6 +161,8 @@ export async function* parseRecords<T = unknown>(
|
|
|
139
161
|
}
|
|
140
162
|
}
|
|
141
163
|
stack.pop();
|
|
164
|
+
namespaces.pop();
|
|
165
|
+
elementNamespaces.pop();
|
|
142
166
|
});
|
|
143
167
|
|
|
144
168
|
parser.on("error", (err: Error) => {
|
|
@@ -148,13 +172,14 @@ export async function* parseRecords<T = unknown>(
|
|
|
148
172
|
try {
|
|
149
173
|
for await (const chunk of source) {
|
|
150
174
|
if (parseError) throw parseError;
|
|
151
|
-
const text = typeof chunk === "string" ? chunk :
|
|
175
|
+
const text = typeof chunk === "string" ? decoder.decode() + chunk : decoder.decode(chunk, {stream: true});
|
|
152
176
|
parser.write(text);
|
|
153
177
|
if (parseError) throw parseError;
|
|
154
178
|
while (pending.length > 0) {
|
|
155
179
|
yield pending.shift()!;
|
|
156
180
|
}
|
|
157
181
|
}
|
|
182
|
+
parser.write(decoder.decode());
|
|
158
183
|
parser.close();
|
|
159
184
|
if (parseError) throw parseError;
|
|
160
185
|
while (pending.length > 0) {
|
|
@@ -176,6 +201,7 @@ function newNode(
|
|
|
176
201
|
typeName: string | null,
|
|
177
202
|
propName: string | null,
|
|
178
203
|
attrsKey: string,
|
|
204
|
+
namespaces: Record<string, string>,
|
|
179
205
|
): {
|
|
180
206
|
obj: Record<string, unknown>;
|
|
181
207
|
typeName: string | null;
|
|
@@ -193,7 +219,11 @@ function newNode(
|
|
|
193
219
|
// concern that should not pollute the user-visible record.
|
|
194
220
|
const cleaned: Record<string, string> = {};
|
|
195
221
|
for (const k of attrKeys) {
|
|
196
|
-
if (
|
|
222
|
+
if (k === "xmlns" || k.startsWith("xmlns:")) continue;
|
|
223
|
+
const prefix = k.includes(":") ? k.slice(0, k.indexOf(":")) : "";
|
|
224
|
+
const isNilAttribute = k === "nil" || k === "xsi:nil" && !namespaces.xsi ||
|
|
225
|
+
local(k) === "nil" && namespaces[prefix] === "http://www.w3.org/2001/XMLSchema-instance";
|
|
226
|
+
if (isNilAttribute && (attrs[k] === "true" || attrs[k] === "1")) {
|
|
197
227
|
isNil = true;
|
|
198
228
|
continue;
|
|
199
229
|
}
|
|
@@ -241,16 +271,16 @@ function assignChild(
|
|
|
241
271
|
const propMetaEntry = parentType ? spec.propMeta?.[parentType]?.[propName] : undefined;
|
|
242
272
|
const childTypeHint = parentType ? spec.childType?.[parentType]?.[propName] : undefined;
|
|
243
273
|
|
|
244
|
-
//
|
|
245
|
-
// ends in `[]`, or (c) the slot is already occupied (implicit repetition).
|
|
274
|
+
// @constraints Explicit repetition metadata distinguishes inline xs:list values from repeated XML elements.
|
|
246
275
|
const metaSaysArray =
|
|
247
276
|
propMetaEntry?.max === "unbounded" ||
|
|
248
277
|
(typeof propMetaEntry?.max === "number" && propMetaEntry.max > 1);
|
|
249
|
-
const hintSaysArray = !!childTypeHint && childTypeHint.endsWith("[]");
|
|
278
|
+
const hintSaysArray = spec.repeatedElements === undefined && !!childTypeHint && childTypeHint.endsWith("[]");
|
|
279
|
+
const declaredRepeated = parentType ? spec.repeatedElements?.[parentType]?.includes(propName) : false;
|
|
250
280
|
const existing = parent.obj[propName];
|
|
251
281
|
const slotTaken = existing !== undefined;
|
|
252
282
|
|
|
253
|
-
if (metaSaysArray || hintSaysArray) {
|
|
283
|
+
if (metaSaysArray || hintSaysArray || declaredRepeated) {
|
|
254
284
|
if (Array.isArray(existing)) {
|
|
255
285
|
existing.push(value);
|
|
256
286
|
} else if (slotTaken) {
|
|
@@ -286,8 +316,6 @@ function tailMatches(stack: string[], path: string[]): boolean {
|
|
|
286
316
|
return true;
|
|
287
317
|
}
|
|
288
318
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
function decodeUtf8(buf: Uint8Array): string {
|
|
292
|
-
return UTF8_DECODER.decode(buf);
|
|
319
|
+
function local(name: string): string {
|
|
320
|
+
return name.slice(name.lastIndexOf(":") + 1);
|
|
293
321
|
}
|