@techspokes/typescript-wsdl-client 0.1.7
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/LICENSE +21 -0
- package/README.md +245 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +94 -0
- package/dist/compiler/schemaCompiler.d.ts +50 -0
- package/dist/compiler/schemaCompiler.d.ts.map +1 -0
- package/dist/compiler/schemaCompiler.js +372 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +7 -0
- package/dist/emit/clientEmitter.d.ts +6 -0
- package/dist/emit/clientEmitter.d.ts.map +1 -0
- package/dist/emit/clientEmitter.js +31 -0
- package/dist/emit/metaEmitter.d.ts +4 -0
- package/dist/emit/metaEmitter.d.ts.map +1 -0
- package/dist/emit/metaEmitter.js +9 -0
- package/dist/emit/opsEmitter.d.ts +4 -0
- package/dist/emit/opsEmitter.d.ts.map +1 -0
- package/dist/emit/opsEmitter.js +13 -0
- package/dist/emit/runtimeEmitter.d.ts +2 -0
- package/dist/emit/runtimeEmitter.d.ts.map +1 -0
- package/dist/emit/runtimeEmitter.js +90 -0
- package/dist/emit/typesEmitter.d.ts +11 -0
- package/dist/emit/typesEmitter.d.ts.map +1 -0
- package/dist/emit/typesEmitter.js +91 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/loader/fetch.d.ts +5 -0
- package/dist/loader/fetch.d.ts.map +1 -0
- package/dist/loader/fetch.js +19 -0
- package/dist/loader/wsdlLoader.d.ts +14 -0
- package/dist/loader/wsdlLoader.d.ts.map +1 -0
- package/dist/loader/wsdlLoader.js +88 -0
- package/dist/util/xml.d.ts +13 -0
- package/dist/util/xml.d.ts.map +1 -0
- package/dist/util/xml.js +40 -0
- package/dist/xsd/primitives.d.ts +8 -0
- package/dist/xsd/primitives.d.ts.map +1 -0
- package/dist/xsd/primitives.js +116 -0
- package/package.json +74 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { getChildrenWithLocalName, getFirstWithLocalName, normalizeArray, pascal, resolveQName, } from "../util/xml.js";
|
|
2
|
+
import { xsdToTsPrimitive } from "../xsd/primitives.js";
|
|
3
|
+
const XS = "http://www.w3.org/2001/XMLSchema";
|
|
4
|
+
function qkey(q) {
|
|
5
|
+
return `{${q.ns}}${q.local}`;
|
|
6
|
+
}
|
|
7
|
+
/** Inline complex type naming */
|
|
8
|
+
function makeInlineTypeName(parentTypeName, propName, _max) {
|
|
9
|
+
const base = pascal(parentTypeName || "AnonParent");
|
|
10
|
+
const prop = pascal(propName || "");
|
|
11
|
+
if (prop)
|
|
12
|
+
return prop;
|
|
13
|
+
return `${base}Anon`;
|
|
14
|
+
}
|
|
15
|
+
export function compileCatalog(cat, _opts) {
|
|
16
|
+
// symbol tables discovered across all schemas
|
|
17
|
+
const complexTypes = new Map();
|
|
18
|
+
const simpleTypes = new Map();
|
|
19
|
+
const elements = new Map();
|
|
20
|
+
for (const s of cat.schemas) {
|
|
21
|
+
const tns = s.targetNS;
|
|
22
|
+
for (const n of getChildrenWithLocalName(s.xml, "complexType")) {
|
|
23
|
+
const name = n["@_name"];
|
|
24
|
+
if (name)
|
|
25
|
+
complexTypes.set(qkey({ ns: tns, local: name }), { node: n, tns, prefixes: s.prefixes });
|
|
26
|
+
}
|
|
27
|
+
for (const n of getChildrenWithLocalName(s.xml, "simpleType")) {
|
|
28
|
+
const name = n["@_name"];
|
|
29
|
+
if (name)
|
|
30
|
+
simpleTypes.set(qkey({ ns: tns, local: name }), { node: n, tns, prefixes: s.prefixes });
|
|
31
|
+
}
|
|
32
|
+
for (const n of getChildrenWithLocalName(s.xml, "element")) {
|
|
33
|
+
const name = n["@_name"];
|
|
34
|
+
if (name)
|
|
35
|
+
elements.set(qkey({ ns: tns, local: name }), { node: n, tns, prefixes: s.prefixes });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// outputs & state
|
|
39
|
+
const compiledMap = new Map(); // key: ns|name
|
|
40
|
+
const aliasMap = new Map(); // key: ns|name
|
|
41
|
+
const inProgress = new Set();
|
|
42
|
+
// meta accumulators
|
|
43
|
+
const attrSpec = {};
|
|
44
|
+
const childType = {};
|
|
45
|
+
const propMeta = {};
|
|
46
|
+
/** Compile a simpleType node to TS */
|
|
47
|
+
function compileSimpleTypeNode(simpleNode, schemaNS, prefixes) {
|
|
48
|
+
const rest = getFirstWithLocalName(simpleNode, "restriction");
|
|
49
|
+
if (rest) {
|
|
50
|
+
const enums = normalizeArray(rest["xs:enumeration"] || rest["enumeration"])
|
|
51
|
+
.map((e) => e["@_value"])
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
const base = rest["@_base"];
|
|
54
|
+
const q = base ? resolveQName(base, schemaNS, prefixes) : { ns: XS, local: "string" };
|
|
55
|
+
const declared = q.ns === XS ? `xs:${q.local}` : `{${q.ns}}${q.local}`;
|
|
56
|
+
if (enums.length) {
|
|
57
|
+
const union = enums.map((v) => JSON.stringify(v)).join(" | ");
|
|
58
|
+
return { tsType: union, declared, jsdoc: JSON.stringify({ kind: "enum", values: enums }) };
|
|
59
|
+
}
|
|
60
|
+
return { tsType: xsdToTsPrimitive(declared, _opts?.primitive), declared };
|
|
61
|
+
}
|
|
62
|
+
const list = getFirstWithLocalName(simpleNode, "list");
|
|
63
|
+
if (list?.["@_itemType"]) {
|
|
64
|
+
const q = resolveQName(list["@_itemType"], schemaNS, prefixes);
|
|
65
|
+
const declared = q.ns === XS ? `xs:${q.local}` : `{${q.ns}}${q.local}`;
|
|
66
|
+
return { tsType: `${xsdToTsPrimitive(declared, _opts?.primitive)}[]`, declared };
|
|
67
|
+
}
|
|
68
|
+
// fallback
|
|
69
|
+
return { tsType: "string", declared: "xs:string" };
|
|
70
|
+
}
|
|
71
|
+
/** Compile and cache a named simpleType */
|
|
72
|
+
function getOrCompileAlias(name, sNode, schemaNS, prefixes) {
|
|
73
|
+
const key = `${schemaNS}|${name}`;
|
|
74
|
+
const present = aliasMap.get(key);
|
|
75
|
+
if (present)
|
|
76
|
+
return present;
|
|
77
|
+
const { tsType, declared, jsdoc } = compileSimpleTypeNode(sNode, schemaNS, prefixes);
|
|
78
|
+
const alias = { name: pascal(name), ns: schemaNS, tsType, declared, jsdoc };
|
|
79
|
+
aliasMap.set(key, alias);
|
|
80
|
+
return alias;
|
|
81
|
+
}
|
|
82
|
+
/** Resolve a QName reference to a TS type; compile targets if needed. */
|
|
83
|
+
function resolveTypeRef(q, schemaNS, prefixes) {
|
|
84
|
+
if (!q.ns)
|
|
85
|
+
q = resolveQName(q.local, schemaNS, prefixes);
|
|
86
|
+
if (q.ns === XS) {
|
|
87
|
+
const label = `xs:${q.local}`;
|
|
88
|
+
return { tsType: xsdToTsPrimitive(label, _opts?.primitive), declared: label };
|
|
89
|
+
}
|
|
90
|
+
const k = qkey(q);
|
|
91
|
+
const srec = simpleTypes.get(k);
|
|
92
|
+
if (srec) {
|
|
93
|
+
const a = getOrCompileAlias(q.local, srec.node, srec.tns, srec.prefixes);
|
|
94
|
+
return { tsType: a.name, declared: `{${a.ns}}${q.local}` };
|
|
95
|
+
}
|
|
96
|
+
const crec = complexTypes.get(k);
|
|
97
|
+
if (crec) {
|
|
98
|
+
const t = getOrCompileComplex(q.local, crec.node, crec.tns, crec.prefixes);
|
|
99
|
+
return { tsType: t.name, declared: `{${t.ns}}${q.local}` };
|
|
100
|
+
}
|
|
101
|
+
// fallback
|
|
102
|
+
return { tsType: "any", declared: `{${q.ns}}${q.local}` };
|
|
103
|
+
}
|
|
104
|
+
function findComplexRec(q) {
|
|
105
|
+
const k = qkey(q);
|
|
106
|
+
return complexTypes.get(k);
|
|
107
|
+
}
|
|
108
|
+
function getOrCompileComplex(name, cnode, schemaNS, prefixes) {
|
|
109
|
+
const outName = pascal(name);
|
|
110
|
+
const key = `${schemaNS}|${outName}`;
|
|
111
|
+
const present = compiledMap.get(key);
|
|
112
|
+
if (present)
|
|
113
|
+
return present;
|
|
114
|
+
if (inProgress.has(key)) {
|
|
115
|
+
// minimal cycle break
|
|
116
|
+
return { name: outName, ns: schemaNS, attrs: [], elems: [] };
|
|
117
|
+
}
|
|
118
|
+
inProgress.add(key);
|
|
119
|
+
const mergeAttrs = (into, list) => {
|
|
120
|
+
const idx = new Map();
|
|
121
|
+
into.forEach((a, i) => idx.set(a.name, i));
|
|
122
|
+
for (const a of list) {
|
|
123
|
+
const pos = idx.get(a.name);
|
|
124
|
+
if (pos == null) {
|
|
125
|
+
idx.set(a.name, into.length);
|
|
126
|
+
into.push(a);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
into[pos] = a; // override
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const mergeElems = (into, list) => {
|
|
134
|
+
const idx = new Map();
|
|
135
|
+
into.forEach((e, i) => idx.set(e.name, i));
|
|
136
|
+
for (const e of list) {
|
|
137
|
+
const pos = idx.get(e.name);
|
|
138
|
+
if (pos == null) {
|
|
139
|
+
idx.set(e.name, into.length);
|
|
140
|
+
into.push(e);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
into[pos] = e; // override
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const collectAttributes = (node) => {
|
|
148
|
+
const out = [];
|
|
149
|
+
const attrs = getChildrenWithLocalName(node, "attribute");
|
|
150
|
+
for (const a of attrs) {
|
|
151
|
+
const an = a["@_name"];
|
|
152
|
+
if (!an)
|
|
153
|
+
continue;
|
|
154
|
+
const inlineSimple = getFirstWithLocalName(a, "simpleType");
|
|
155
|
+
if (inlineSimple) {
|
|
156
|
+
const r = compileSimpleTypeNode(inlineSimple, schemaNS, prefixes);
|
|
157
|
+
out.push({
|
|
158
|
+
name: an,
|
|
159
|
+
tsType: r.tsType,
|
|
160
|
+
use: a["@_use"] === "required" ? "required" : "optional",
|
|
161
|
+
declaredType: r.declared,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const t = a["@_type"];
|
|
166
|
+
const q = t ? resolveQName(t, schemaNS, prefixes) : { ns: XS, local: "string" };
|
|
167
|
+
const r = resolveTypeRef(q, schemaNS, prefixes);
|
|
168
|
+
out.push({
|
|
169
|
+
name: an,
|
|
170
|
+
tsType: r.tsType,
|
|
171
|
+
use: a["@_use"] === "required" ? "required" : "optional",
|
|
172
|
+
declaredType: r.declared,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
177
|
+
};
|
|
178
|
+
const collectParticles = (ownerTypeName, node) => {
|
|
179
|
+
const out = [];
|
|
180
|
+
const groups = [
|
|
181
|
+
...getChildrenWithLocalName(node, "sequence"),
|
|
182
|
+
...getChildrenWithLocalName(node, "all"),
|
|
183
|
+
...getChildrenWithLocalName(node, "choice"),
|
|
184
|
+
];
|
|
185
|
+
for (const grp of groups) {
|
|
186
|
+
for (const e of getChildrenWithLocalName(grp, "element")) {
|
|
187
|
+
const nameOrRef = e["@_name"] || e["@_ref"];
|
|
188
|
+
if (!nameOrRef)
|
|
189
|
+
continue;
|
|
190
|
+
let propName = e["@_name"] || undefined;
|
|
191
|
+
const min = e["@_minOccurs"] ? Number(e["@_minOccurs"]) : 1;
|
|
192
|
+
const maxAttr = e["@_maxOccurs"];
|
|
193
|
+
const max = maxAttr === "unbounded" ? "unbounded" : maxAttr ? Number(maxAttr) : 1;
|
|
194
|
+
const nillable = e["@_nillable"] === "true";
|
|
195
|
+
// inline complex/simple types
|
|
196
|
+
const inlineComplex = getFirstWithLocalName(e, "complexType");
|
|
197
|
+
const inlineSimple = getFirstWithLocalName(e, "simpleType");
|
|
198
|
+
if (inlineComplex) {
|
|
199
|
+
const inlineName = makeInlineTypeName(ownerTypeName, propName || nameOrRef, max);
|
|
200
|
+
const rec = getOrCompileComplex(inlineName, inlineComplex, schemaNS, prefixes);
|
|
201
|
+
out.push({
|
|
202
|
+
name: propName || nameOrRef,
|
|
203
|
+
tsType: rec.name,
|
|
204
|
+
min,
|
|
205
|
+
max,
|
|
206
|
+
nillable,
|
|
207
|
+
declaredType: `{${schemaNS}}${rec.name}`,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
else if (inlineSimple) {
|
|
211
|
+
const r = compileSimpleTypeNode(inlineSimple, schemaNS, prefixes);
|
|
212
|
+
out.push({
|
|
213
|
+
name: propName || nameOrRef,
|
|
214
|
+
tsType: r.tsType,
|
|
215
|
+
min,
|
|
216
|
+
max,
|
|
217
|
+
nillable,
|
|
218
|
+
declaredType: r.declared,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// normal ref/type
|
|
223
|
+
const t = e["@_type"] || e["@_ref"];
|
|
224
|
+
const q = t ? resolveQName(t, schemaNS, prefixes) : { ns: XS, local: "string" };
|
|
225
|
+
const r = resolveTypeRef(q, schemaNS, prefixes);
|
|
226
|
+
out.push({
|
|
227
|
+
name: propName || nameOrRef,
|
|
228
|
+
tsType: r.tsType,
|
|
229
|
+
min,
|
|
230
|
+
max,
|
|
231
|
+
nillable,
|
|
232
|
+
declaredType: r.declared,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return out;
|
|
238
|
+
};
|
|
239
|
+
// Result accumulators
|
|
240
|
+
const attrs = [];
|
|
241
|
+
const elems = [];
|
|
242
|
+
// Inheritance: complexContent
|
|
243
|
+
const complexContent = getFirstWithLocalName(cnode, "complexContent");
|
|
244
|
+
if (complexContent) {
|
|
245
|
+
const ext = getFirstWithLocalName(complexContent, "extension");
|
|
246
|
+
const res = getFirstWithLocalName(complexContent, "restriction");
|
|
247
|
+
const node = ext || res;
|
|
248
|
+
if (node) {
|
|
249
|
+
const baseAttr = node["@_base"];
|
|
250
|
+
if (baseAttr) {
|
|
251
|
+
const baseQ = resolveQName(baseAttr, schemaNS, prefixes);
|
|
252
|
+
const baseRec = findComplexRec(baseQ);
|
|
253
|
+
if (baseRec) {
|
|
254
|
+
const base = getOrCompileComplex(baseRec.node["@_name"], baseRec.node, baseRec.tns, baseRec.prefixes);
|
|
255
|
+
// inherit base
|
|
256
|
+
mergeAttrs(attrs, base.attrs);
|
|
257
|
+
mergeElems(elems, base.elems);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// local additions/overrides
|
|
261
|
+
mergeAttrs(attrs, collectAttributes(node));
|
|
262
|
+
mergeElems(elems, collectParticles(outName, node));
|
|
263
|
+
const result = { name: outName, ns: schemaNS, attrs, elems };
|
|
264
|
+
compiledMap.set(key, result);
|
|
265
|
+
inProgress.delete(key);
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Simple content: text + attributes (IMPORTANT: model text as "$value")
|
|
270
|
+
const simpleContent = getFirstWithLocalName(cnode, "simpleContent");
|
|
271
|
+
if (simpleContent) {
|
|
272
|
+
const ext = getFirstWithLocalName(simpleContent, "extension");
|
|
273
|
+
const res = getFirstWithLocalName(simpleContent, "restriction");
|
|
274
|
+
const model = (scNode) => {
|
|
275
|
+
const baseAttr = scNode["@_base"];
|
|
276
|
+
let r = { tsType: "string", declared: "xs:string" };
|
|
277
|
+
if (baseAttr) {
|
|
278
|
+
r = resolveTypeRef(resolveQName(baseAttr, schemaNS, prefixes), schemaNS, prefixes);
|
|
279
|
+
}
|
|
280
|
+
// 👇👇 text node is modeled as "$value" (not "value")
|
|
281
|
+
mergeElems(elems, [{
|
|
282
|
+
name: "$value",
|
|
283
|
+
tsType: r.tsType,
|
|
284
|
+
min: 0,
|
|
285
|
+
max: 1,
|
|
286
|
+
nillable: false,
|
|
287
|
+
declaredType: r.declared,
|
|
288
|
+
}]);
|
|
289
|
+
mergeAttrs(attrs, collectAttributes(scNode));
|
|
290
|
+
const result = { name: outName, ns: schemaNS, attrs, elems };
|
|
291
|
+
compiledMap.set(key, result);
|
|
292
|
+
inProgress.delete(key);
|
|
293
|
+
return result;
|
|
294
|
+
};
|
|
295
|
+
if (ext)
|
|
296
|
+
return model(ext);
|
|
297
|
+
if (res)
|
|
298
|
+
return model(res);
|
|
299
|
+
}
|
|
300
|
+
// Attributes + particles
|
|
301
|
+
mergeAttrs(attrs, collectAttributes(cnode));
|
|
302
|
+
mergeElems(elems, collectParticles(outName, cnode));
|
|
303
|
+
const result = { name: outName, ns: schemaNS, attrs, elems };
|
|
304
|
+
compiledMap.set(key, result);
|
|
305
|
+
inProgress.delete(key);
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
// compile every discovered complex type
|
|
309
|
+
for (const rec of complexTypes.values()) {
|
|
310
|
+
const name = rec.node["@_name"];
|
|
311
|
+
if (!name)
|
|
312
|
+
continue;
|
|
313
|
+
getOrCompileComplex(name, rec.node, rec.tns, rec.prefixes);
|
|
314
|
+
}
|
|
315
|
+
// emit lists
|
|
316
|
+
const typesList = Array.from(compiledMap.values());
|
|
317
|
+
const aliasList = Array.from(aliasMap.values());
|
|
318
|
+
// meta
|
|
319
|
+
for (const t of typesList) {
|
|
320
|
+
attrSpec[t.name] = (t.attrs || []).map(a => a.name);
|
|
321
|
+
const child = {};
|
|
322
|
+
const meta = {};
|
|
323
|
+
for (const e of t.elems || []) {
|
|
324
|
+
child[e.name] = typeof e.tsType === "string" ? e.tsType : "any";
|
|
325
|
+
meta[e.name] = {
|
|
326
|
+
declaredType: e.declaredType,
|
|
327
|
+
min: e.min,
|
|
328
|
+
max: e.max,
|
|
329
|
+
nillable: !!e.nillable,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
childType[t.name] = child;
|
|
333
|
+
propMeta[t.name] = meta;
|
|
334
|
+
}
|
|
335
|
+
// operations / soapAction (minimal)
|
|
336
|
+
const defs = cat.wsdlXml["wsdl:definitions"] || cat.wsdlXml["definitions"];
|
|
337
|
+
const portType = defs?.["wsdl:portType"] || defs?.["portType"];
|
|
338
|
+
const binding = defs?.["wsdl:binding"] || defs?.["binding"];
|
|
339
|
+
const pOps = normalizeArray(portType?.["wsdl:operation"] || portType?.["operation"]);
|
|
340
|
+
const bOps = new Map();
|
|
341
|
+
const bindingOps = normalizeArray(binding?.["wsdl:operation"] || binding?.["operation"]);
|
|
342
|
+
const bindingOpsAny = bindingOps.length ? bindingOps : getChildrenWithLocalName(binding || {}, "operation");
|
|
343
|
+
for (const bo of bindingOpsAny) {
|
|
344
|
+
const name = bo?.["@_name"];
|
|
345
|
+
if (!name)
|
|
346
|
+
continue;
|
|
347
|
+
let action = "";
|
|
348
|
+
for (const [k, v] of Object.entries(bo || {})) {
|
|
349
|
+
if (k === "operation" || k.endsWith(":operation")) {
|
|
350
|
+
const node = Array.isArray(v) ? v[0] : v;
|
|
351
|
+
action = node?.["@_soapAction"] || node?.["@_soapActionURI"] || node?.["@_soapActionUrl"] || "";
|
|
352
|
+
if (action)
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
bOps.set(name, action);
|
|
357
|
+
}
|
|
358
|
+
const ops = [];
|
|
359
|
+
for (const po of pOps) {
|
|
360
|
+
const name = po?.["@_name"];
|
|
361
|
+
if (!name)
|
|
362
|
+
continue;
|
|
363
|
+
ops.push({ name, soapAction: bOps.get(name) || "" });
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
types: typesList,
|
|
367
|
+
aliases: aliasList,
|
|
368
|
+
meta: { attrSpec, childType, propMeta },
|
|
369
|
+
operations: ops,
|
|
370
|
+
wsdlTargetNS: defs?.["@_targetNamespace"] || "",
|
|
371
|
+
};
|
|
372
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PrimitiveOptions } from "./xsd/primitives.js";
|
|
2
|
+
export type CompilerOptions = {
|
|
3
|
+
choice?: "all-optional" | "union";
|
|
4
|
+
dateAs?: "string" | "date";
|
|
5
|
+
intAs?: "number" | "string";
|
|
6
|
+
failOnUnresolved?: boolean;
|
|
7
|
+
/** Attribute bag key for the runtime mapper (node-soap). */
|
|
8
|
+
attributesKey?: string;
|
|
9
|
+
/** Controls how XSD primitives are mapped to TypeScript. Safe defaults apply. */
|
|
10
|
+
primitive?: PrimitiveOptions;
|
|
11
|
+
};
|
|
12
|
+
export declare const defaultOptions: CompilerOptions;
|
|
13
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG;IAC1B,MAAM,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;IAClC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,eAM5B,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
2
|
+
import type { CompilerOptions } from "../config.js";
|
|
3
|
+
export declare function emitClient(outFile: string, compiled: CompiledCatalog, opts: CompilerOptions & {
|
|
4
|
+
importExt?: string;
|
|
5
|
+
}): void;
|
|
6
|
+
//# sourceMappingURL=clientEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientEmitter.d.ts","sourceRoot":"","sources":["../../src/emit/clientEmitter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,eAAe,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,QA6BpH"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
export function emitClient(outFile, compiled, opts) {
|
|
3
|
+
const ext = opts.importExt ?? ".js";
|
|
4
|
+
const lines = [];
|
|
5
|
+
lines.push(`import { createSoapClient, toSoapArgs, fromSoapResult } from "./runtime${ext}";`);
|
|
6
|
+
lines.push(`import { ATTR_SPEC, CHILD_TYPE, PROP_META } from "./meta${ext}";`);
|
|
7
|
+
lines.push(`import type * as T from "./types${ext}";`);
|
|
8
|
+
lines.push("");
|
|
9
|
+
lines.push(`export class GeneratedSoapClient {`);
|
|
10
|
+
lines.push(` constructor(private source: string | any, private attributesKey: string = "${opts.attributesKey || "$attributes"}") {}`);
|
|
11
|
+
lines.push(` async _client() {`);
|
|
12
|
+
lines.push(` if (typeof this.source === 'string') return createSoapClient({ wsdlUrl: this.source });`);
|
|
13
|
+
lines.push(` return this.source;`);
|
|
14
|
+
lines.push(` }`);
|
|
15
|
+
for (const op of compiled.operations) {
|
|
16
|
+
const m = op.name;
|
|
17
|
+
lines.push(` /** SOAPAction: ${op.soapAction} */`);
|
|
18
|
+
lines.push(` async ${m}(args: any): Promise<any> {`);
|
|
19
|
+
lines.push(` const c: any = await this._client();`);
|
|
20
|
+
lines.push(` const meta = { ATTR_SPEC, CHILD_TYPE, PROP_META } as const;`);
|
|
21
|
+
lines.push(` const soapArgs = toSoapArgs(args, "${m}", meta, this.attributesKey);`);
|
|
22
|
+
lines.push(` return new Promise((resolve, reject) => {`);
|
|
23
|
+
lines.push(` c['${m}'](soapArgs, (err: any, result: any) => {`);
|
|
24
|
+
lines.push(` if (err) reject(err); else resolve(fromSoapResult(result, "${m}", meta, this.attributesKey));`);
|
|
25
|
+
lines.push(` });`);
|
|
26
|
+
lines.push(` });`);
|
|
27
|
+
lines.push(` }`);
|
|
28
|
+
}
|
|
29
|
+
lines.push(`}`);
|
|
30
|
+
fs.writeFileSync(outFile, lines.join("\n"), "utf8");
|
|
31
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
2
|
+
import type { CompilerOptions } from "../config.js";
|
|
3
|
+
export declare function emitMeta(outFile: string, compiled: CompiledCatalog, opts?: CompilerOptions): void;
|
|
4
|
+
//# sourceMappingURL=metaEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metaEmitter.d.ts","sourceRoot":"","sources":["../../src/emit/metaEmitter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,eAAe,QAQ1F"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
export function emitMeta(outFile, compiled, opts) {
|
|
3
|
+
const { attrSpec, childType, propMeta } = compiled.meta;
|
|
4
|
+
const src = `export const ATTR_SPEC = ${JSON.stringify(attrSpec, null, 2)} as const;\n` +
|
|
5
|
+
`export const CHILD_TYPE = ${JSON.stringify(childType, null, 2)} as const;\n` +
|
|
6
|
+
`export const PROP_META = ${JSON.stringify(propMeta, null, 2)} as const;\n` +
|
|
7
|
+
`export const OPTIONS = ${JSON.stringify(opts || {}, null, 2)} as const;\n`;
|
|
8
|
+
fs.writeFileSync(outFile, src, "utf8");
|
|
9
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
2
|
+
export declare function emitOperations(outFile: string, compiled: CompiledCatalog): void;
|
|
3
|
+
export declare function emitOps(outFile: string, compiled: CompiledCatalog): void;
|
|
4
|
+
//# sourceMappingURL=opsEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opsEmitter.d.ts","sourceRoot":"","sources":["../../src/emit/opsEmitter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAExE;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAOjE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
export function emitOperations(outFile, compiled) {
|
|
3
|
+
fs.writeFileSync(outFile, JSON.stringify(compiled.operations, null, 2), "utf8");
|
|
4
|
+
}
|
|
5
|
+
export function emitOps(outFile, compiled) {
|
|
6
|
+
if (outFile.endsWith(".ts")) {
|
|
7
|
+
const src = `export const OPERATIONS = ${JSON.stringify(compiled.operations, null, 2)} as const;\n`;
|
|
8
|
+
fs.writeFileSync(outFile, src, "utf8");
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
emitOperations(outFile, compiled);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtimeEmitter.d.ts","sourceRoot":"","sources":["../../src/emit/runtimeEmitter.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,QAuF1C"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export function emitRuntime(outFile) {
|
|
4
|
+
const code = `// noinspection NpmUsedModulesInstalled,JSLastCommaInObjectLiteral,CommaExpressionJS,JSUnresolvedReference
|
|
5
|
+
|
|
6
|
+
import soap from "soap";
|
|
7
|
+
export type CreateSoapClientOptions = {
|
|
8
|
+
wsdlUrl: string;
|
|
9
|
+
endpoint?: string;
|
|
10
|
+
wsdlOptions?: Record<string, any>;
|
|
11
|
+
requestOptions?: Record<string, any>;
|
|
12
|
+
}
|
|
13
|
+
export type AttrSpec = Record<string, readonly string[]>;
|
|
14
|
+
export type ChildType = Record<string, Readonly<Record<string, string>>>;
|
|
15
|
+
export type PropMeta = Record<string, Readonly<Record<string, any>>>;
|
|
16
|
+
|
|
17
|
+
export async function createSoapClient(opts: CreateSoapClientOptions): Promise<any> {
|
|
18
|
+
const client = await soap.createClientAsync(opts.wsdlUrl, opts.wsdlOptions || {});
|
|
19
|
+
if (opts.endpoint) client.setEndpoint(opts.endpoint);
|
|
20
|
+
if (opts.requestOptions) {
|
|
21
|
+
const { wsdlUrl, endpoint, wsdlOptions, ...req } = opts as any;
|
|
22
|
+
if (client.setSecurity && req) {
|
|
23
|
+
// security is caller's responsibility (if needed)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return client;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function toSoapArgs(
|
|
30
|
+
value: any,
|
|
31
|
+
typeName?: string,
|
|
32
|
+
meta?: { ATTR_SPEC: AttrSpec; CHILD_TYPE: ChildType; PROP_META: PropMeta },
|
|
33
|
+
attributesKey: string = "$attributes"
|
|
34
|
+
): any {
|
|
35
|
+
if (value == null) return value;
|
|
36
|
+
if (typeof value !== "object") return value;
|
|
37
|
+
const attrList = (typeName && meta?.ATTR_SPEC?.[typeName]) || [];
|
|
38
|
+
const childType = (typeName && meta?.CHILD_TYPE?.[typeName]) || {};
|
|
39
|
+
const out: any = {};
|
|
40
|
+
const attrBag: any = {};
|
|
41
|
+
// map TS $value -> SOAP $value
|
|
42
|
+
if ("$value" in value && Object.keys(value).length >= 1) out.$value = (value as any).$value;
|
|
43
|
+
|
|
44
|
+
for (const [k, v] of Object.entries<any>(value)) {
|
|
45
|
+
if (k === "$value") continue; // skip text node (already mapped)
|
|
46
|
+
if (k === attributesKey) continue; // user shouldn't send raw attr bag
|
|
47
|
+
if (attrList.includes(k)) { attrBag[k] = v; continue; }
|
|
48
|
+
const childT = (childType as any)[k] as string | undefined;
|
|
49
|
+
out[k] = Array.isArray(v)
|
|
50
|
+
? v.map(it => toSoapArgs(it, childT, meta, attributesKey))
|
|
51
|
+
: toSoapArgs(v, childT, meta, attributesKey);
|
|
52
|
+
}
|
|
53
|
+
if (Object.keys(attrBag).length) out[attributesKey] = attrBag;
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function fromSoapResult(
|
|
58
|
+
node: any,
|
|
59
|
+
typeName?: string,
|
|
60
|
+
meta?: { ATTR_SPEC: AttrSpec; CHILD_TYPE: ChildType; PROP_META: PropMeta },
|
|
61
|
+
attributesKey: string = "$attributes"
|
|
62
|
+
): any {
|
|
63
|
+
if (node == null) return node;
|
|
64
|
+
if (typeof node !== "object") return node;
|
|
65
|
+
if (Array.isArray(node)) return node.map(n => fromSoapResult(n, typeName, meta, attributesKey));
|
|
66
|
+
|
|
67
|
+
const childType = (typeName && meta?.CHILD_TYPE?.[typeName]) || {};
|
|
68
|
+
const result: any = {};
|
|
69
|
+
|
|
70
|
+
// map SOAP $value -> TS $value
|
|
71
|
+
if ("$value" in node) result.$value = (node as any).$value;
|
|
72
|
+
|
|
73
|
+
// hoist attributes
|
|
74
|
+
if (attributesKey in node && node[attributesKey] && typeof node[attributesKey] === "object") {
|
|
75
|
+
Object.assign(result, node[attributesKey]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (const [k, v] of Object.entries<any>(node)) {
|
|
79
|
+
if (k === attributesKey || k === "$value") continue;
|
|
80
|
+
const childT = (childType as any)[k] as string | undefined;
|
|
81
|
+
result[k] = Array.isArray(v)
|
|
82
|
+
? v.map(it => fromSoapResult(it, childT, meta, attributesKey))
|
|
83
|
+
: fromSoapResult(v, childT, meta, attributesKey);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
|
89
|
+
fs.writeFileSync(outFile, code, "utf8");
|
|
90
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
2
|
+
/**
|
|
3
|
+
* Emit TypeScript types from a compiled XSD catalog.
|
|
4
|
+
*
|
|
5
|
+
* - Text node is modeled as "$value" (not "value") to avoid collisions with real elements.
|
|
6
|
+
* - xs:complexType + xs:simpleContent/extension is flattened to `extends <BaseType>`.
|
|
7
|
+
* - All properties (attributes and elements) include @xsd JSDoc.
|
|
8
|
+
* - If a "$value" element is present, it is emitted last.
|
|
9
|
+
*/
|
|
10
|
+
export declare function emitTypes(outFile: string, compiled: CompiledCatalog): void;
|
|
11
|
+
//# sourceMappingURL=typesEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typesEmitter.d.ts","sourceRoot":"","sources":["../../src/emit/typesEmitter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QA+FnE"}
|