@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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +245 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +94 -0
  6. package/dist/compiler/schemaCompiler.d.ts +50 -0
  7. package/dist/compiler/schemaCompiler.d.ts.map +1 -0
  8. package/dist/compiler/schemaCompiler.js +372 -0
  9. package/dist/config.d.ts +13 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +7 -0
  12. package/dist/emit/clientEmitter.d.ts +6 -0
  13. package/dist/emit/clientEmitter.d.ts.map +1 -0
  14. package/dist/emit/clientEmitter.js +31 -0
  15. package/dist/emit/metaEmitter.d.ts +4 -0
  16. package/dist/emit/metaEmitter.d.ts.map +1 -0
  17. package/dist/emit/metaEmitter.js +9 -0
  18. package/dist/emit/opsEmitter.d.ts +4 -0
  19. package/dist/emit/opsEmitter.d.ts.map +1 -0
  20. package/dist/emit/opsEmitter.js +13 -0
  21. package/dist/emit/runtimeEmitter.d.ts +2 -0
  22. package/dist/emit/runtimeEmitter.d.ts.map +1 -0
  23. package/dist/emit/runtimeEmitter.js +90 -0
  24. package/dist/emit/typesEmitter.d.ts +11 -0
  25. package/dist/emit/typesEmitter.d.ts.map +1 -0
  26. package/dist/emit/typesEmitter.js +91 -0
  27. package/dist/index.d.ts +11 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +46 -0
  30. package/dist/loader/fetch.d.ts +5 -0
  31. package/dist/loader/fetch.d.ts.map +1 -0
  32. package/dist/loader/fetch.js +19 -0
  33. package/dist/loader/wsdlLoader.d.ts +14 -0
  34. package/dist/loader/wsdlLoader.d.ts.map +1 -0
  35. package/dist/loader/wsdlLoader.js +88 -0
  36. package/dist/util/xml.d.ts +13 -0
  37. package/dist/util/xml.d.ts.map +1 -0
  38. package/dist/util/xml.js +40 -0
  39. package/dist/xsd/primitives.d.ts +8 -0
  40. package/dist/xsd/primitives.d.ts.map +1 -0
  41. package/dist/xsd/primitives.js +116 -0
  42. package/package.json +74 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TechSpokes, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # TypeScript WSDL Client
2
+
3
+ [![CI](https://github.com/techspokes/typescript-wsdl-client/actions/workflows/ci.yml/badge.svg)](https://github.com/techspokes/typescript-wsdl-client/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@techspokes/typescript-wsdl-client.svg)](https://www.npmjs.com/package/@techspokes/typescript-wsdl-client)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
+
7
+ **TypeScript WSDL → SOAP client generator.**
8
+ Reads WSDL/XSD (with imports) and emits a small, typed client you can compile into your app.
9
+
10
+ * `xs:attribute` support (attributes become first-class fields, not bags)
11
+ * `complexType` (`sequence` / `all` / `choice`)
12
+ * `simpleContent` / `complexContent` (`extension` + `restriction`)
13
+ * Inline **anonymous** types (auto-named, stable)
14
+ * Global `element @ref` resolution
15
+ * Duplicate/local-name **merge** across schemas/namespaces
16
+ * Deterministic metadata (`ATTR_SPEC`, `PROP_META`) for clean JSON ⇄ SOAP mapping
17
+ * ESM **and** CommonJS friendly output
18
+
19
+ Vendor: **[TechSpokes](https://www.techspokes.com)** · Contact: **[contact@techspokes.com](mailto:contact@techspokes.com)**
20
+ Maintainer: **Serge Liatko** ([@sergeliatko](https://github.com/sergeliatko)) · GitHub org: [@techspokes](https://github.com/techspokes)
21
+
22
+ ---
23
+
24
+ ## Quick start
25
+
26
+ Install the generator (dev-time) in your project:
27
+
28
+ ```bash
29
+ npm i -D typescript-wsdl-client
30
+ # your app will use node-soap at runtime:
31
+ npm i soap
32
+ ```
33
+
34
+ Generate into your app (recommended under `src/generated/...`):
35
+
36
+ ```bash
37
+ npx wsdl-tsc --wsdl ./spec/wsdl/MyService.wsdl --out ./src/generated/my --imports js --ops-ts
38
+ ```
39
+
40
+ Use the generated client:
41
+
42
+ ```ts
43
+ // ESM / NodeNext app
44
+ import { createSoapClient } from "./generated/my/runtime.js";
45
+ import { GeneratedSoapClient } from "./generated/my/client.js";
46
+
47
+ const soap = await createSoapClient({ wsdlUrl: "https://example.com/MyService?wsdl" });
48
+ const client = new GeneratedSoapClient(soap, "$attributes"); // attributes key optional
49
+
50
+ const rs = await client.MyOperation({
51
+ MyOperationRQ: {
52
+ MyAttribute: "passed as attribute",
53
+ MyElement: "passed as child element",
54
+ // ...other fields
55
+ // attributes appear as top-level props; child elements as nested objects
56
+ }
57
+ });
58
+
59
+ console.log(rs);
60
+ ```
61
+
62
+ > The generator always emits TypeScript sources (`*.ts`). You compile them with your app.
63
+
64
+ ---
65
+
66
+ ## CLI
67
+
68
+ ```
69
+ wsdl-tsc --wsdl <path-or-url> --out <dir> [options]
70
+ ```
71
+
72
+ **Required**
73
+
74
+ * `--wsdl` — WSDL path or URL
75
+ * `--out` — output directory (created if missing)
76
+
77
+ **Useful options**
78
+
79
+ * `--imports js|ts|bare` (default: `js`)
80
+ How intra-generated imports are written:
81
+
82
+ * `js` → `./file.js` (best for ESM/NodeNext apps)
83
+ * `ts` → `./file.ts` (use with `allowImportingTsExtensions`)
84
+ * `bare` → `./file` (nice for CommonJS builds)
85
+ * `--ops-ts` (default: `true`)
86
+ Emit `operations.ts` instead of JSON.
87
+
88
+ **Primitive mapping (safe defaults)**
89
+
90
+ * `--int64-as string|number|bigint` (default `string`) — `xs:long`, `xs:unsignedLong`
91
+ * `--bigint-as string|number` (default `string`) — `xs:integer` family
92
+ * `--decimal-as string|number` (default `string`) — `xs:decimal` (money/precision)
93
+ * `--date-as string|Date` (default `string`) — `xs:date`, `xs:dateTime`, `xs:time`, `g*`, durations
94
+
95
+ **Other**
96
+
97
+ * `--attributes-key <string>` (default: `$attributes`)
98
+ The key used by the runtime marshaller when serializing attributes.
99
+
100
+ ---
101
+
102
+ ## What gets generated
103
+
104
+ ```
105
+ <out>/
106
+ types.ts # interfaces + type aliases (with @xsd JSDoc: original XML type/occurs)
107
+ client.ts # thin operation wrapper (calls into runtime)
108
+ runtime.ts # small SOAP runtime: createSoapClient, toSoapArgs, fromSoapResult
109
+ meta.ts # ATTR_SPEC, CHILD_TYPE, PROP_META for JSON ⇄ SOAP mapping
110
+ operations.ts # compiled operation metadata (name, soapAction, etc.)
111
+ ```
112
+
113
+ Example: if `User` has `@Id` and `@CreatedAt`, you’ll see:
114
+
115
+ ```ts
116
+ interface User {
117
+ Id?: string;
118
+ CreatedAt?: string; // or Date if you chose --date-as Date
119
+ }
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Using in different app module systems
125
+
126
+ ### ESM / NodeNext (recommended)
127
+
128
+ Service `tsconfig.json`:
129
+
130
+ ```json
131
+ {
132
+ "compilerOptions": {
133
+ "target": "ES2022",
134
+ "module": "NodeNext",
135
+ "moduleResolution": "NodeNext",
136
+ "strict": true,
137
+ "esModuleInterop": true,
138
+ "skipLibCheck": true
139
+ }
140
+ }
141
+ ```
142
+
143
+ Generate with `--imports js` and import `./client.js`, `./runtime.js`.
144
+
145
+ ### CommonJS
146
+
147
+ Keep your app `module: "CommonJS"` and generate with `--imports bare` (imports like `./runtime`).
148
+ TypeScript will compile to `require("./runtime")` cleanly.
149
+
150
+ ---
151
+
152
+ ## Recommended workflow
153
+
154
+ * **Vendor** your WSDL(s) in `spec/wsdl/` for reproducible builds.
155
+ * Generate into `src/generated/<service>/` and **commit the generated files** (deterministic CI/Docker).
156
+ * Build your app (the generated code compiles with it).
157
+
158
+ **Example scripts (app `package.json`):**
159
+
160
+ ```json
161
+ {
162
+ "scripts": {
163
+ "codegen:my": "wsdl-tsc --wsdl ./spec/wsdl/MyService.wsdl --out ./src/generated/my --imports js --ops-ts",
164
+ "prebuild": "npm run codegen:my",
165
+ "build": "tsc -p tsconfig.json"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Programmatic API (optional)
173
+
174
+ ```ts
175
+ import { compileCatalog, xsdToTsPrimitive, type CompilerOptions } from "typescript-wsdl-client";
176
+ import { loadWsdlCatalog } from "typescript-wsdl-client/internal-or-your-loader"; // if you expose it
177
+
178
+ const catalog = await loadWsdlCatalog("./spec/wsdl/MyService.wsdl");
179
+ const compiled = compileCatalog(catalog, {
180
+ primitive: { decimalAs: "string", dateAs: "string" }
181
+ });
182
+ // …write your own emitters or use the built-ins in the CLI.
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Primitive mapping rationale
188
+
189
+ Defaults are **string-first** to avoid precision & timezone surprises:
190
+
191
+ * `xs:decimal` → `string` (money/precision safe)
192
+ * 64-bit integers → `string` (you can opt into `bigint` or `number`)
193
+ * dates/times → `string` (transport-friendly, no implicit tz conversion)
194
+
195
+ Change per your needs with the CLI flags above.
196
+
197
+ ---
198
+
199
+ ## Minimal test you can run
200
+
201
+ ```bash
202
+ # generate from a local WSDL
203
+ npx wsdl-tsc --wsdl ./spec/wsdl/MyService.wsdl --out ./tmp --imports js --ops-ts
204
+
205
+ # quick typecheck of generated output (NodeNext)
206
+ npx tsc --noEmit --module NodeNext --moduleResolution NodeNext --target ES2022 ./tmp/*.ts
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Troubleshooting
212
+
213
+ * **“I don’t see `runtime.ts`”** — You should. Ensure you’re on a recent version and check that the output directory is writable.
214
+ * **“Cannot find './runtime.js'”** — Your app must be `module: "NodeNext"` when using `--imports js`.
215
+ Use `--imports bare` for CommonJS apps.
216
+ * **“node-soap not found”** — Install it in your **app**: `npm i soap`.
217
+
218
+ ---
219
+
220
+ ## Contributing
221
+
222
+ Issues and PRs welcome. Please include a **minimal WSDL/XSD** fixture that reproduces the case.
223
+ Node 20+ supported.
224
+
225
+ - See CONTRIBUTING.md for setup and workflow.
226
+ - See CODE_OF_CONDUCT.md for community expectations.
227
+ - Security reports: see SECURITY.md.
228
+
229
+ ---
230
+
231
+ ## Community
232
+
233
+ - Contributing guide: CONTRIBUTING.md
234
+ - Code of Conduct: CODE_OF_CONDUCT.md
235
+ - Security policy: SECURITY.md
236
+ - Support: SUPPORT.md
237
+ - Roadmap: ROADMAP.md
238
+ - Changelog: CHANGELOG.md
239
+
240
+ ---
241
+
242
+ ## License
243
+
244
+ MIT © TechSpokes.
245
+ *The tool is MIT-licensed. Generated artifacts are owned by you; the tool imposes no license on generated files.*
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ import yargs from "yargs/yargs";
3
+ import { hideBin } from "yargs/helpers";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { loadWsdl } from "./loader/wsdlLoader.js";
7
+ import { compileCatalog } from "./compiler/schemaCompiler.js";
8
+ import { emitRuntime } from "./emit/runtimeEmitter.js";
9
+ import { emitTypes } from "./emit/typesEmitter.js";
10
+ import { emitMeta } from "./emit/metaEmitter.js";
11
+ import { emitOps } from "./emit/opsEmitter.js";
12
+ import { emitClient } from "./emit/clientEmitter.js";
13
+ const argv = await yargs(hideBin(process.argv))
14
+ .scriptName("wsdl-tsc")
15
+ .option("wsdl", {
16
+ type: "string",
17
+ demandOption: true,
18
+ desc: "Path or URL to the WSDL"
19
+ })
20
+ .option("out", {
21
+ type: "string",
22
+ demandOption: true,
23
+ desc: "Output directory for generated files"
24
+ })
25
+ .option("imports", {
26
+ type: "string",
27
+ choices: ["js", "ts", "bare"],
28
+ default: "js",
29
+ desc: "Intra-generated import specifiers: '.js', '.ts', or bare (no extension)",
30
+ })
31
+ .option("ops-ts", {
32
+ type: "boolean",
33
+ default: true,
34
+ desc: "Emit operations.ts instead of JSON",
35
+ })
36
+ .option("attributes-key", {
37
+ type: "string",
38
+ default: "$attributes",
39
+ desc: "Key used by runtime marshaller for XML attributes",
40
+ })
41
+ // Primitive mapping knobs (safe defaults)
42
+ .option("int64-as", {
43
+ type: "string",
44
+ choices: ["string", "number", "bigint"],
45
+ default: "string",
46
+ desc: "How to map xs:long/xs:unsignedLong",
47
+ })
48
+ .option("bigint-as", {
49
+ type: "string",
50
+ choices: ["string", "number"],
51
+ default: "string",
52
+ desc: "How to map xs:integer family (positive/nonNegative/etc.)",
53
+ })
54
+ .option("decimal-as", {
55
+ type: "string",
56
+ choices: ["string", "number"],
57
+ default: "string",
58
+ desc: "How to map xs:decimal (money/precision)",
59
+ })
60
+ .option("date-as", {
61
+ type: "string",
62
+ choices: ["string", "Date"],
63
+ default: "string",
64
+ desc: "How to map date/time/duration types",
65
+ })
66
+ .strict()
67
+ .help()
68
+ .parse();
69
+ const outDir = path.resolve(String(argv.out));
70
+ fs.mkdirSync(outDir, { recursive: true });
71
+ // Load & compile
72
+ const catalog = await loadWsdl(String(argv.wsdl));
73
+ const compiled = compileCatalog(catalog, {
74
+ primitive: {
75
+ int64As: argv["int64-as"],
76
+ bigIntegerAs: argv["bigint-as"],
77
+ decimalAs: argv["decimal-as"],
78
+ dateAs: argv["date-as"],
79
+ },
80
+ });
81
+ // Emit files
82
+ const importExt = argv.imports === "js" ? ".js" : argv.imports === "ts" ? ".ts" : "";
83
+ emitTypes(path.join(outDir, "types.ts"), compiled);
84
+ emitMeta(path.join(outDir, "meta.ts"), compiled);
85
+ emitOps(path.join(outDir, argv["ops-ts"] ? "operations.ts" : "operations.json"), compiled);
86
+ emitRuntime(path.join(outDir, "runtime.ts"));
87
+ emitClient(path.join(outDir, "client.ts"), compiled, {
88
+ // These fields are consumed by our client emitter options shape
89
+ // to keep CLI flexible without exposing full CompilerOptions here.
90
+ // @ts-ignore runtime-only options for emitter
91
+ importExt,
92
+ attributesKey: String(argv["attributes-key"]),
93
+ });
94
+ console.log(`✅ Generated TypeScript client in ${outDir}`);
@@ -0,0 +1,50 @@
1
+ import type { CompilerOptions } from "../config.js";
2
+ import type { WsdlCatalog } from "../loader/wsdlLoader.js";
3
+ export type QName = {
4
+ ns: string;
5
+ local: string;
6
+ };
7
+ export type CompiledType = {
8
+ name: string;
9
+ ns: string;
10
+ attrs: Array<{
11
+ name: string;
12
+ tsType: string;
13
+ use?: "required" | "optional";
14
+ declaredType: string;
15
+ }>;
16
+ elems: Array<{
17
+ name: string;
18
+ tsType: string;
19
+ min: number;
20
+ max: number | "unbounded";
21
+ nillable?: boolean;
22
+ declaredType: string;
23
+ }>;
24
+ jsdoc?: string;
25
+ };
26
+ export type CompiledAlias = {
27
+ name: string;
28
+ ns: string;
29
+ tsType: string;
30
+ declared: string;
31
+ jsdoc?: string;
32
+ };
33
+ export type CompiledCatalog = {
34
+ types: CompiledType[];
35
+ aliases: CompiledAlias[];
36
+ meta: {
37
+ attrSpec: Record<string, string[]>;
38
+ childType: Record<string, Record<string, string>>;
39
+ propMeta: Record<string, Record<string, any>>;
40
+ };
41
+ operations: Array<{
42
+ name: string;
43
+ soapAction: string;
44
+ inputElement?: QName;
45
+ outputElement?: QName;
46
+ }>;
47
+ wsdlTargetNS: string;
48
+ };
49
+ export declare function compileCatalog(cat: WsdlCatalog, _opts: CompilerOptions): CompiledCatalog;
50
+ //# sourceMappingURL=schemaCompiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaCompiler.d.ts","sourceRoot":"","sources":["../../src/compiler/schemaCompiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAU3D,MAAM,MAAM,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;QAC9B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;QAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;KAC/C,CAAC;IACF,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,KAAK,CAAC;QACrB,aAAa,CAAC,EAAE,KAAK,CAAC;KACvB,CAAC,CAAC;IACH,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAoBF,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,GAAG,eAAe,CA+XxF"}