@techspokes/typescript-wsdl-client 0.10.4 → 0.11.1
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 +26 -0
- package/dist/cli.js +18 -1
- package/dist/client/generateOperations.d.ts +13 -0
- package/dist/client/generateOperations.d.ts.map +1 -0
- package/dist/client/generateOperations.js +71 -0
- package/dist/compiler/schemaCompiler.d.ts.map +1 -1
- package/dist/compiler/schemaCompiler.js +15 -1
- package/dist/gateway/generateGateway.d.ts +1 -0
- package/dist/gateway/generateGateway.d.ts.map +1 -1
- package/dist/gateway/generateGateway.js +4 -2
- package/dist/gateway/generators.d.ts +2 -15
- package/dist/gateway/generators.d.ts.map +1 -1
- package/dist/gateway/generators.js +114 -30
- package/dist/gateway/helpers.d.ts +4 -2
- package/dist/gateway/helpers.d.ts.map +1 -1
- package/dist/gateway/helpers.js +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/loader/wsdlLoader.d.ts.map +1 -1
- package/dist/loader/wsdlLoader.js +30 -4
- package/dist/openapi/generateOpenAPI.d.ts +1 -0
- package/dist/openapi/generateOpenAPI.d.ts.map +1 -1
- package/dist/openapi/generateOpenAPI.js +1 -0
- package/dist/openapi/generateSchemas.d.ts +1 -0
- package/dist/openapi/generateSchemas.d.ts.map +1 -1
- package/dist/openapi/generateSchemas.js +4 -3
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +6 -1
- package/dist/util/builder.d.ts.map +1 -1
- package/dist/util/builder.js +1 -0
- package/dist/util/cli.d.ts +3 -2
- package/dist/util/cli.d.ts.map +1 -1
- package/dist/util/cli.js +14 -4
- package/dist/util/errors.d.ts +37 -0
- package/dist/util/errors.d.ts.map +1 -0
- package/dist/util/errors.js +37 -0
- package/docs/README.md +1 -0
- package/docs/cli-reference.md +2 -0
- package/docs/concepts.md +29 -2
- package/docs/generated-code.md +24 -0
- package/docs/testing.md +193 -0
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { generateTypes } from "./client/generateTypes.js";
|
|
|
20
20
|
import { generateUtils } from "./client/generateUtils.js";
|
|
21
21
|
import { generateCatalog } from "./compiler/generateCatalog.js";
|
|
22
22
|
import { generateClient } from "./client/generateClient.js";
|
|
23
|
+
import { generateOperations } from "./client/generateOperations.js";
|
|
23
24
|
import { info } from "./util/cli.js";
|
|
24
25
|
export { generateOpenAPI } from "./openapi/generateOpenAPI.js";
|
|
25
26
|
export { generateGateway } from "./gateway/generateGateway.js";
|
|
@@ -76,6 +77,7 @@ export async function compileWsdlToProject(input) {
|
|
|
76
77
|
// Emit artifacts
|
|
77
78
|
const typesFile = path.join(input.outDir, "types.ts");
|
|
78
79
|
const utilsFile = path.join(input.outDir, "utils.ts");
|
|
80
|
+
const operationsFile = path.join(input.outDir, "operations.ts");
|
|
79
81
|
const catalogFile = path.join(input.outDir, "catalog.json");
|
|
80
82
|
const clientFile = path.join(input.outDir, "client.ts");
|
|
81
83
|
// Prepare output dir
|
|
@@ -89,6 +91,7 @@ export async function compileWsdlToProject(input) {
|
|
|
89
91
|
generateClient(clientFile, compiled);
|
|
90
92
|
generateTypes(typesFile, compiled);
|
|
91
93
|
generateUtils(utilsFile, compiled);
|
|
94
|
+
generateOperations(operationsFile, compiled);
|
|
92
95
|
if (compiled.options.catalog) {
|
|
93
96
|
generateCatalog(catalogFile, compiled);
|
|
94
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wsdlLoader.d.ts","sourceRoot":"","sources":["../../src/loader/wsdlLoader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wsdlLoader.d.ts","sourceRoot":"","sources":["../../src/loader/wsdlLoader.ts"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC;IACb,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,CAAC;AAKF;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAsE1E"}
|
|
@@ -14,6 +14,7 @@ import { XMLParser } from "fast-xml-parser";
|
|
|
14
14
|
import { fetchText } from "./fetch.js";
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import { getChildrenWithLocalName } from "../util/tools.js";
|
|
17
|
+
import { WsdlCompilationError } from "../util/errors.js";
|
|
17
18
|
// Configure XML parser to preserve attributes with @_ prefix
|
|
18
19
|
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_" });
|
|
19
20
|
/**
|
|
@@ -32,12 +33,37 @@ const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_
|
|
|
32
33
|
*/
|
|
33
34
|
export async function loadWsdl(wsdlUrlOrPath) {
|
|
34
35
|
// Fetch and parse the WSDL document
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
let wsdlUri;
|
|
37
|
+
let text;
|
|
38
|
+
try {
|
|
39
|
+
const fetched = await fetchText(wsdlUrlOrPath);
|
|
40
|
+
wsdlUri = fetched.uri;
|
|
41
|
+
text = fetched.text;
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
throw new WsdlCompilationError(`Failed to load WSDL document: ${err instanceof Error ? err.message : String(err)}`, {
|
|
45
|
+
file: wsdlUrlOrPath,
|
|
46
|
+
suggestion: "Verify the file path or URL is correct and accessible.",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
let wsdlXml;
|
|
50
|
+
try {
|
|
51
|
+
wsdlXml = parser.parse(text);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw new WsdlCompilationError(`Failed to parse WSDL/XSD document as XML: ${err instanceof Error ? err.message : String(err)}`, {
|
|
55
|
+
file: wsdlUrlOrPath,
|
|
56
|
+
suggestion: "Validate the XML with an external tool (e.g., xmllint) and fix any syntax errors.",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
37
59
|
// Extract the WSDL definitions node (with or without namespace prefix)
|
|
38
60
|
const defs = wsdlXml["wsdl:definitions"] || wsdlXml["definitions"];
|
|
39
|
-
if (!defs)
|
|
40
|
-
throw new
|
|
61
|
+
if (!defs) {
|
|
62
|
+
throw new WsdlCompilationError("Not a WSDL 1.1 file: missing <wsdl:definitions> root element.", {
|
|
63
|
+
file: wsdlUrlOrPath,
|
|
64
|
+
suggestion: "Ensure the file is a valid WSDL 1.1 document with a <definitions> root element.",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
41
67
|
// Extract namespace prefixes declared at the WSDL level
|
|
42
68
|
const prefixMap = {};
|
|
43
69
|
for (const [k, v] of Object.entries(defs)) {
|
|
@@ -76,6 +76,7 @@ export interface GenerateOpenAPIOptions {
|
|
|
76
76
|
skipValidate?: boolean;
|
|
77
77
|
envelopeNamespace?: string;
|
|
78
78
|
errorNamespace?: string;
|
|
79
|
+
flattenArrayWrappers?: boolean;
|
|
79
80
|
}
|
|
80
81
|
export declare function generateOpenAPI(opts: GenerateOpenAPIOptions): Promise<{
|
|
81
82
|
doc: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateOpenAPI.d.ts","sourceRoot":"","sources":["../../src/openapi/generateOpenAPI.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAiB,KAAK,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAKnF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3C,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"generateOpenAPI.d.ts","sourceRoot":"","sources":["../../src/openapi/generateOpenAPI.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAiB,KAAK,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAKnF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3C,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAC3E,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CA0RD"}
|
|
@@ -80,6 +80,7 @@ export async function generateOpenAPI(opts) {
|
|
|
80
80
|
const schemas = generateSchemas(compiled, {
|
|
81
81
|
closedSchemas: opts.closedSchemas,
|
|
82
82
|
pruneUnusedSchemas: opts.pruneUnusedSchemas,
|
|
83
|
+
flattenArrayWrappers: opts.flattenArrayWrappers,
|
|
83
84
|
});
|
|
84
85
|
// Build paths
|
|
85
86
|
const tagStyle = opts.tagStyle || "default";
|
|
@@ -24,6 +24,7 @@ import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
|
24
24
|
export interface GenerateSchemasOptions {
|
|
25
25
|
closedSchemas?: boolean;
|
|
26
26
|
pruneUnusedSchemas?: boolean;
|
|
27
|
+
flattenArrayWrappers?: boolean;
|
|
27
28
|
}
|
|
28
29
|
export type ComponentsSchemas = Record<string, any>;
|
|
29
30
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateSchemas.d.ts","sourceRoot":"","sources":["../../src/openapi/generateSchemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAgB,eAAe,EAAe,MAAM,+BAA+B,CAAC;AAEhG;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"generateSchemas.d.ts","sourceRoot":"","sources":["../../src/openapi/generateSchemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAgB,eAAe,EAAe,MAAM,+BAA+B,CAAC;AAEhG;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAwIpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,sBAAsB,GAAG,iBAAiB,CA+C1G"}
|
|
@@ -47,7 +47,7 @@ function isArrayWrapper(t) {
|
|
|
47
47
|
return null;
|
|
48
48
|
return { itemType: e.tsType };
|
|
49
49
|
}
|
|
50
|
-
function buildComplexSchema(t, closed, knownTypeNames, aliasNames) {
|
|
50
|
+
function buildComplexSchema(t, closed, knownTypeNames, aliasNames, flattenWrappers) {
|
|
51
51
|
// Use knownTypeNames/aliasNames to validate $ref targets so we surface
|
|
52
52
|
// compiler issues early instead of emitting dangling references in OpenAPI output.
|
|
53
53
|
function refOrPrimitive(ts) {
|
|
@@ -77,7 +77,7 @@ function buildComplexSchema(t, closed, knownTypeNames, aliasNames) {
|
|
|
77
77
|
return { $ref: `#/components/schemas/${ts}` };
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
const arrayWrap = isArrayWrapper(t);
|
|
80
|
+
const arrayWrap = flattenWrappers ? isArrayWrapper(t) : null;
|
|
81
81
|
if (arrayWrap) {
|
|
82
82
|
const item = refOrPrimitive(String(arrayWrap.itemType));
|
|
83
83
|
return { type: "array", items: item };
|
|
@@ -148,6 +148,7 @@ function buildComplexSchema(t, closed, knownTypeNames, aliasNames) {
|
|
|
148
148
|
*/
|
|
149
149
|
export function generateSchemas(compiled, opts) {
|
|
150
150
|
const closed = !!opts.closedSchemas;
|
|
151
|
+
const flattenWrappers = opts.flattenArrayWrappers !== false; // default true
|
|
151
152
|
const schemas = {};
|
|
152
153
|
const typeNames = new Set(compiled.types.map(t => t.name));
|
|
153
154
|
const aliasNames = new Set(compiled.aliases.map(a => a.name));
|
|
@@ -156,7 +157,7 @@ export function generateSchemas(compiled, opts) {
|
|
|
156
157
|
schemas[a.name] = buildAliasSchema(a);
|
|
157
158
|
}
|
|
158
159
|
for (const t of compiled.types) {
|
|
159
|
-
schemas[t.name] = buildComplexSchema(t, closed, typeNames, aliasNames);
|
|
160
|
+
schemas[t.name] = buildComplexSchema(t, closed, typeNames, aliasNames, flattenWrappers);
|
|
160
161
|
}
|
|
161
162
|
if (opts.pruneUnusedSchemas) {
|
|
162
163
|
// Root references: each operation's inputElement.local, outputElement.local
|
package/dist/pipeline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAkB,KAAK,sBAAsB,EAAC,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAkB,KAAK,sBAAsB,EAAC,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAC,KAAK,eAAe,EAAyB,MAAM,aAAa,CAAC;AAGzE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,aAAa,GAAG,iBAAiB,CAAC,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1G,OAAO,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,GAAG,iBAAiB,CAAC,GAAG;QAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;QACnC,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,CAAC;CAAE,CAAC,CA4HhH"}
|
package/dist/pipeline.js
CHANGED
|
@@ -13,6 +13,7 @@ import { compileCatalog } from "./compiler/schemaCompiler.js";
|
|
|
13
13
|
import { generateClient } from "./client/generateClient.js";
|
|
14
14
|
import { generateTypes } from "./client/generateTypes.js";
|
|
15
15
|
import { generateUtils } from "./client/generateUtils.js";
|
|
16
|
+
import { generateOperations } from "./client/generateOperations.js";
|
|
16
17
|
import { generateCatalog } from "./compiler/generateCatalog.js";
|
|
17
18
|
import { generateOpenAPI } from "./openapi/generateOpenAPI.js";
|
|
18
19
|
import { generateGateway } from "./gateway/generateGateway.js";
|
|
@@ -63,7 +64,7 @@ export async function runGenerationPipeline(opts) {
|
|
|
63
64
|
success(`Compiled catalog written to ${opts.catalogOut}`);
|
|
64
65
|
// Step 4: Optionally generate TypeScript client artifacts
|
|
65
66
|
if (opts.clientOutDir) {
|
|
66
|
-
emitClientArtifacts(opts.clientOutDir, compiled, generateClient, generateTypes, generateUtils);
|
|
67
|
+
emitClientArtifacts(opts.clientOutDir, compiled, generateClient, generateTypes, generateUtils, generateOperations);
|
|
67
68
|
}
|
|
68
69
|
// Step 4: Optionally generate OpenAPI specification
|
|
69
70
|
let openapiDoc;
|
|
@@ -99,6 +100,10 @@ export async function runGenerationPipeline(opts) {
|
|
|
99
100
|
clientDir: opts.clientOutDir ? path.resolve(opts.clientOutDir) : undefined,
|
|
100
101
|
// Reuse the same imports mode as the TypeScript client/types/utils emitters
|
|
101
102
|
imports: finalCompiler.imports,
|
|
103
|
+
// Pass catalog for runtime unwrap generation
|
|
104
|
+
catalogFile: path.resolve(opts.catalogOut),
|
|
105
|
+
// Thread flatten flag from OpenAPI options
|
|
106
|
+
flattenArrayWrappers: opts.openapi?.flattenArrayWrappers,
|
|
102
107
|
});
|
|
103
108
|
success(`Gateway code generated in ${gatewayOutDir}`);
|
|
104
109
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/util/builder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,+BAA+B,CAAC;AAE1E;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBhF;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAC5C,OAAO,EAAE,MAAM,EAAE,GAChB,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/util/builder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,+BAA+B,CAAC;AAE1E;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBhF;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAC5C,OAAO,EAAE,MAAM,EAAE,GAChB,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC,CAqBtF"}
|
package/dist/util/builder.js
CHANGED
|
@@ -47,6 +47,7 @@ export function buildOpenApiOptionsFromArgv(argv, format, servers) {
|
|
|
47
47
|
tagsFile: argv["openapi-tags-file"],
|
|
48
48
|
title: argv["openapi-title"],
|
|
49
49
|
version: argv["openapi-version-tag"],
|
|
50
|
+
flattenArrayWrappers: argv["openapi-flatten-array-wrappers"],
|
|
50
51
|
asYaml: format === "yaml",
|
|
51
52
|
};
|
|
52
53
|
}
|
package/dist/util/cli.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export declare function reportCompilationStats(wsdlCatalog: {
|
|
|
81
81
|
operations: any[];
|
|
82
82
|
}): void;
|
|
83
83
|
/**
|
|
84
|
-
* Emit TypeScript client artifacts (client.ts, types.ts, utils.ts)
|
|
84
|
+
* Emit TypeScript client artifacts (client.ts, types.ts, utils.ts, operations.ts)
|
|
85
85
|
*
|
|
86
86
|
* Note: catalog.json is NOT emitted by this function - it should be handled
|
|
87
87
|
* separately by the caller using generateCatalog() with explicit --catalog-file path.
|
|
@@ -91,8 +91,9 @@ export declare function reportCompilationStats(wsdlCatalog: {
|
|
|
91
91
|
* @param generateClient - Client generator function
|
|
92
92
|
* @param generateTypes - Types generator function
|
|
93
93
|
* @param generateUtils - Utils generator function
|
|
94
|
+
* @param generateOperations - Operations interface generator function
|
|
94
95
|
*/
|
|
95
|
-
export declare function emitClientArtifacts(outDir: string, compiled: any, generateClient: (path: string, compiled: any) => void, generateTypes: (path: string, compiled: any) => void, generateUtils: (path: string, compiled: any) => void): void;
|
|
96
|
+
export declare function emitClientArtifacts(outDir: string, compiled: any, generateClient: (path: string, compiled: any) => void, generateTypes: (path: string, compiled: any) => void, generateUtils: (path: string, compiled: any) => void, generateOperations?: (path: string, compiled: any) => void): void;
|
|
96
97
|
/**
|
|
97
98
|
* Validate gateway generation requirements
|
|
98
99
|
*
|
package/dist/util/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/util/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/util/cli.ts"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAc1E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAMhE;AAED;;;;;;;;;GASG;AAEH;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,GAAE,MAAU,GAAG,KAAK,CAQ7E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CASP;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE;IAAE,OAAO,EAAE,GAAG,EAAE,CAAA;CAAE,EAC/B,QAAQ,EAAE;IAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAAC,UAAU,EAAE,GAAG,EAAE,CAAA;CAAE,GAC5C,IAAI,CAIN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,GAAG,EACb,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,EACrD,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,EACpD,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,EACpD,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,GACzD,IAAI,CAWN;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,oBAAoB,EAAE,MAAM,GAAG,SAAS,GACvC,IAAI,CAUN"}
|
package/dist/util/cli.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import fs from "node:fs";
|
|
10
|
+
import { WsdlCompilationError } from "./errors.js";
|
|
10
11
|
/**
|
|
11
12
|
* Parse comma-separated status codes from CLI argument
|
|
12
13
|
*
|
|
@@ -94,8 +95,13 @@ export function info(message) {
|
|
|
94
95
|
* @param exitCode - Process exit code (default: 1)
|
|
95
96
|
*/
|
|
96
97
|
export function handleCLIError(errorObj, exitCode = 1) {
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
if (errorObj instanceof WsdlCompilationError) {
|
|
99
|
+
error(errorObj.toUserMessage());
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const message = errorObj instanceof Error ? errorObj.message : String(errorObj);
|
|
103
|
+
error(message);
|
|
104
|
+
}
|
|
99
105
|
process.exit(exitCode);
|
|
100
106
|
}
|
|
101
107
|
/**
|
|
@@ -125,7 +131,7 @@ export function reportCompilationStats(wsdlCatalog, compiled) {
|
|
|
125
131
|
info(`Operations: ${compiled.operations.length}`);
|
|
126
132
|
}
|
|
127
133
|
/**
|
|
128
|
-
* Emit TypeScript client artifacts (client.ts, types.ts, utils.ts)
|
|
134
|
+
* Emit TypeScript client artifacts (client.ts, types.ts, utils.ts, operations.ts)
|
|
129
135
|
*
|
|
130
136
|
* Note: catalog.json is NOT emitted by this function - it should be handled
|
|
131
137
|
* separately by the caller using generateCatalog() with explicit --catalog-file path.
|
|
@@ -135,12 +141,16 @@ export function reportCompilationStats(wsdlCatalog, compiled) {
|
|
|
135
141
|
* @param generateClient - Client generator function
|
|
136
142
|
* @param generateTypes - Types generator function
|
|
137
143
|
* @param generateUtils - Utils generator function
|
|
144
|
+
* @param generateOperations - Operations interface generator function
|
|
138
145
|
*/
|
|
139
|
-
export function emitClientArtifacts(outDir, compiled, generateClient, generateTypes, generateUtils) {
|
|
146
|
+
export function emitClientArtifacts(outDir, compiled, generateClient, generateTypes, generateUtils, generateOperations) {
|
|
140
147
|
fs.mkdirSync(outDir, { recursive: true });
|
|
141
148
|
generateClient(path.join(outDir, "client.ts"), compiled);
|
|
142
149
|
generateTypes(path.join(outDir, "types.ts"), compiled);
|
|
143
150
|
generateUtils(path.join(outDir, "utils.ts"), compiled);
|
|
151
|
+
if (generateOperations) {
|
|
152
|
+
generateOperations(path.join(outDir, "operations.ts"), compiled);
|
|
153
|
+
}
|
|
144
154
|
success(`Generated TypeScript client in ${outDir}`);
|
|
145
155
|
}
|
|
146
156
|
/**
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error types for WSDL compilation
|
|
3
|
+
*
|
|
4
|
+
* Provides context-rich error messages with element names, namespaces,
|
|
5
|
+
* and actionable suggestions for common issues.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Context information attached to WSDL compilation errors
|
|
9
|
+
*/
|
|
10
|
+
export interface WsdlErrorContext {
|
|
11
|
+
/** Element or type name that triggered the error */
|
|
12
|
+
element?: string;
|
|
13
|
+
/** XML namespace where the error occurred */
|
|
14
|
+
namespace?: string;
|
|
15
|
+
/** File or URI of the source document */
|
|
16
|
+
file?: string;
|
|
17
|
+
/** Referenced-by context (e.g., "element 'bar' in type 'Baz'") */
|
|
18
|
+
referencedBy?: string;
|
|
19
|
+
/** Actionable suggestion for resolving the error */
|
|
20
|
+
suggestion?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Structured error for WSDL/XSD compilation failures.
|
|
24
|
+
*
|
|
25
|
+
* Extends Error with context fields for element, namespace, file, and suggestion.
|
|
26
|
+
* The CLI error handler formats these into multi-line user-friendly messages.
|
|
27
|
+
*/
|
|
28
|
+
export declare class WsdlCompilationError extends Error {
|
|
29
|
+
readonly context: WsdlErrorContext;
|
|
30
|
+
readonly name = "WsdlCompilationError";
|
|
31
|
+
constructor(message: string, context?: WsdlErrorContext);
|
|
32
|
+
/**
|
|
33
|
+
* Formats the error into a user-friendly multi-line message.
|
|
34
|
+
*/
|
|
35
|
+
toUserMessage(): string;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/util/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAK3B,OAAO,EAAE,gBAAgB;IAJ3C,SAAkB,IAAI,0BAA0B;gBAG9C,OAAO,EAAE,MAAM,EACC,OAAO,GAAE,gBAAqB;IAKhD;;OAEG;IACH,aAAa,IAAI,MAAM;CASxB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error types for WSDL compilation
|
|
3
|
+
*
|
|
4
|
+
* Provides context-rich error messages with element names, namespaces,
|
|
5
|
+
* and actionable suggestions for common issues.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Structured error for WSDL/XSD compilation failures.
|
|
9
|
+
*
|
|
10
|
+
* Extends Error with context fields for element, namespace, file, and suggestion.
|
|
11
|
+
* The CLI error handler formats these into multi-line user-friendly messages.
|
|
12
|
+
*/
|
|
13
|
+
export class WsdlCompilationError extends Error {
|
|
14
|
+
context;
|
|
15
|
+
name = "WsdlCompilationError";
|
|
16
|
+
constructor(message, context = {}) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.context = context;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Formats the error into a user-friendly multi-line message.
|
|
22
|
+
*/
|
|
23
|
+
toUserMessage() {
|
|
24
|
+
const parts = [this.message];
|
|
25
|
+
if (this.context.element)
|
|
26
|
+
parts.push(` Element: ${this.context.element}`);
|
|
27
|
+
if (this.context.namespace)
|
|
28
|
+
parts.push(` Namespace: ${this.context.namespace}`);
|
|
29
|
+
if (this.context.referencedBy)
|
|
30
|
+
parts.push(` Referenced by: ${this.context.referencedBy}`);
|
|
31
|
+
if (this.context.file)
|
|
32
|
+
parts.push(` File: ${this.context.file}`);
|
|
33
|
+
if (this.context.suggestion)
|
|
34
|
+
parts.push(` Suggestion: ${this.context.suggestion}`);
|
|
35
|
+
return parts.join("\n");
|
|
36
|
+
}
|
|
37
|
+
}
|
package/docs/README.md
CHANGED
|
@@ -13,6 +13,7 @@ Human-maintained reference documents for `@techspokes/typescript-wsdl-client`. T
|
|
|
13
13
|
- [generated-code.md](generated-code.md) – Using clients and types
|
|
14
14
|
- [migration.md](migration.md) – Upgrade paths between versions
|
|
15
15
|
- [production.md](production.md) – CI/CD, validation, logging, limitations
|
|
16
|
+
- [testing.md](testing.md) – Testing patterns and mock client examples
|
|
16
17
|
- [troubleshooting.md](troubleshooting.md) – Common issues and debugging
|
|
17
18
|
|
|
18
19
|
## Conventions
|
package/docs/cli-reference.md
CHANGED
|
@@ -87,6 +87,7 @@ The catalog is auto-placed alongside the first available output directory: `{cli
|
|
|
87
87
|
| `--openapi-method` | `post` | Default HTTP method |
|
|
88
88
|
| `--openapi-tag-style` | `default` | Tag inference: default, service, or first |
|
|
89
89
|
| `--openapi-closed-schemas` | `false` | Add additionalProperties: false |
|
|
90
|
+
| `--openapi-flatten-array-wrappers` | `true` | Flatten ArrayOf* wrappers to plain arrays; emit runtime unwrap in gateway |
|
|
90
91
|
| `--openapi-prune-unused-schemas` | `false` | Emit only referenced schemas |
|
|
91
92
|
| `--openapi-envelope-namespace` | `ResponseEnvelope` | Envelope component name suffix |
|
|
92
93
|
| `--openapi-error-namespace` | `ErrorObject` | Error object name suffix |
|
|
@@ -107,6 +108,7 @@ The catalog is auto-placed alongside the first available output directory: `{cli
|
|
|
107
108
|
| `--gateway-decorator-name` | {serviceSlug}Client | Fastify decorator name |
|
|
108
109
|
| `--gateway-skip-plugin` | `false` | Skip plugin.ts generation |
|
|
109
110
|
| `--gateway-skip-runtime` | `false` | Skip runtime.ts generation |
|
|
111
|
+
| `--openapi-flatten-array-wrappers` | `true` | Generate runtime unwrap for ArrayOf* wrapper types |
|
|
110
112
|
|
|
111
113
|
### App Scaffold Flags
|
|
112
114
|
|
package/docs/concepts.md
CHANGED
|
@@ -163,7 +163,8 @@ interface MyType {
|
|
|
163
163
|
## Array Wrapper Flattening
|
|
164
164
|
|
|
165
165
|
A complex type whose only child is a single repeated element with no attributes
|
|
166
|
-
collapses to an array schema in OpenAPI.
|
|
166
|
+
collapses to an array schema in OpenAPI. Controlled by
|
|
167
|
+
`--openapi-flatten-array-wrappers` (default `true`).
|
|
167
168
|
|
|
168
169
|
```xml
|
|
169
170
|
<xs:complexType name="ArrayOfForecast">
|
|
@@ -173,7 +174,7 @@ collapses to an array schema in OpenAPI.
|
|
|
173
174
|
</xs:complexType>
|
|
174
175
|
```
|
|
175
176
|
|
|
176
|
-
|
|
177
|
+
With flattening enabled (default), the OpenAPI schema becomes a plain array:
|
|
177
178
|
|
|
178
179
|
```json
|
|
179
180
|
{
|
|
@@ -184,6 +185,32 @@ The resulting OpenAPI schema:
|
|
|
184
185
|
}
|
|
185
186
|
```
|
|
186
187
|
|
|
188
|
+
The TypeScript types preserve the wrapper structure:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
export interface ArrayOfForecast {
|
|
192
|
+
Forecast?: Forecast[];
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Runtime Unwrap
|
|
197
|
+
|
|
198
|
+
Because the SOAP client returns wrapper-shaped objects (`{ Forecast: [...] }`)
|
|
199
|
+
while the OpenAPI schema expects flat arrays, the generated gateway includes an
|
|
200
|
+
`unwrapArrayWrappers()` function in `runtime.ts`. Route handlers call it
|
|
201
|
+
automatically before serialization. This bridges the TS-type/schema gap without
|
|
202
|
+
requiring consumers to transform responses manually.
|
|
203
|
+
|
|
204
|
+
### Disabling Flattening
|
|
205
|
+
|
|
206
|
+
Pass `--openapi-flatten-array-wrappers false` to preserve the wrapper object
|
|
207
|
+
structure in OpenAPI schemas. When disabled:
|
|
208
|
+
|
|
209
|
+
- ArrayOf* types emit as `type: "object"` with their inner element as a property
|
|
210
|
+
- No `unwrapArrayWrappers()` function is generated in `runtime.ts`
|
|
211
|
+
- Route handlers pass SOAP responses through unmodified
|
|
212
|
+
- The OpenAPI schema matches the TypeScript types exactly
|
|
213
|
+
|
|
187
214
|
## Inheritance Flattening
|
|
188
215
|
|
|
189
216
|
Three XSD inheritance patterns are supported.
|
package/docs/generated-code.md
CHANGED
|
@@ -104,3 +104,27 @@ Key features of the generated handlers:
|
|
|
104
104
|
- **Envelope wrapping** — `buildSuccessEnvelope()` wraps the raw SOAP response in the standard `{ status, message, data, error }` envelope
|
|
105
105
|
|
|
106
106
|
See [Gateway Guide](gateway-guide.md) for the full architecture and [CLI Reference](cli-reference.md) for generation flags.
|
|
107
|
+
|
|
108
|
+
## Operations Interface
|
|
109
|
+
|
|
110
|
+
The generated `operations.ts` exports a typed interface (`{ServiceName}Operations`) that mirrors the concrete client class methods. Use it for dependency injection and testing:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import type { WeatherOperations } from "./client/operations.js";
|
|
114
|
+
|
|
115
|
+
const mock: WeatherOperations = {
|
|
116
|
+
GetCityWeatherByZIP: async (args) => ({
|
|
117
|
+
response: { GetCityWeatherByZIPResult: { Success: true } },
|
|
118
|
+
headers: {},
|
|
119
|
+
}),
|
|
120
|
+
// ...other operations
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The gateway plugin accepts any `WeatherOperations` implementation, so you can pass the mock directly:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
app.register(weatherGateway, { client: mock });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
See [Testing Guide](testing.md) for full integration test patterns.
|