@techspokes/typescript-wsdl-client 0.11.6 → 0.13.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 CHANGED
@@ -13,6 +13,7 @@ Generate type-safe TypeScript SOAP clients, OpenAPI 3.1 specs, and production-re
13
13
  - OpenAPI 3.1 specs that mirror your TypeScript types
14
14
  - REST gateway over SOAP with automatic request/response transformation
15
15
  - CI-friendly deterministic output for safe regeneration in version control
16
+ - WSDL/XSD documentation propagated into generated comments and OpenAPI descriptions
16
17
 
17
18
  ## Quick Start
18
19
 
@@ -57,7 +58,7 @@ curl -X POST http://localhost:3000/get-weather-information \
57
58
 
58
59
  | Output | Files | Purpose |
59
60
  |--------|-------|---------|
60
- | TypeScript Client | client.ts, types.ts, utils.ts | Typed SOAP operations |
61
+ | TypeScript Client | client.ts, types.ts, utils.ts, operations.ts | Typed SOAP operations and mockable operations interface |
61
62
  | OpenAPI 3.1 Spec | openapi.json or .yaml | REST API documentation |
62
63
  | Fastify Gateway | plugin.ts, routes/, schemas/ | Production REST handlers |
63
64
  | Catalog | catalog.json | Compiled WSDL (debuggable, cacheable) |
@@ -1 +1 @@
1
- {"version":3,"file":"generateClient.d.ts","sourceRoot":"","sources":["../../src/client/generateClient.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAInE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAsWxE"}
1
+ {"version":3,"file":"generateClient.d.ts","sourceRoot":"","sources":["../../src/client/generateClient.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAInE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QA+WxE"}
@@ -34,6 +34,12 @@ import { error, warn } from "../util/cli.js";
34
34
  */
35
35
  export function generateClient(outFile, compiled) {
36
36
  const isValidIdent = (name) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
37
+ const normalizeDocLines = (text) => String(text)
38
+ .replace(/\r\n?/g, "\n")
39
+ .split("\n")
40
+ .map(line => line.trim())
41
+ .filter(Boolean)
42
+ .map(line => line.replace(/\*\//g, "*\\/"));
37
43
  const reserved = new Set([
38
44
  "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
39
45
  "do", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if",
@@ -61,11 +67,13 @@ export function generateClient(outFile, compiled) {
61
67
  const inTs = inTypeName ? `T.${inTypeName}` : `any`;
62
68
  const outTs = outTypeName ? `T.${outTypeName}` : `any`;
63
69
  const secHints = Array.isArray(op.security) && op.security.length ? op.security : [];
70
+ const opDocLines = op.doc ? normalizeDocLines(op.doc) : [];
71
+ const opDocStr = opDocLines.length ? `\n *\n${opDocLines.map(line => ` * ${line}`).join("\n")}` : "";
64
72
  const secHintsStr = secHints.length ? `\n *\n * Security (WSDL policy hint): ${secHints.join(", ")}` : "";
65
73
  const methodTemplate = `
66
74
 
67
75
  /**
68
- * Calls the ${m} operation of the ${clientName}.${secHintsStr}
76
+ * Calls the ${m} operation of the ${clientName}.${opDocStr}${secHintsStr}
69
77
  *
70
78
  * @param args - The request arguments for the ${m} operation.
71
79
  * @returns A promise resolving to the operation response containing data, headers, response raw XML, and request raw XML.
@@ -1 +1 @@
1
- {"version":3,"file":"generateOperations.d.ts","sourceRoot":"","sources":["../../src/client/generateOperations.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIrE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CA0DnF"}
1
+ {"version":3,"file":"generateOperations.d.ts","sourceRoot":"","sources":["../../src/client/generateOperations.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIrE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAsEnF"}
@@ -22,6 +22,12 @@ export function generateOperations(outFile, compiled) {
22
22
  const ext = compiled.options.imports ?? "bare";
23
23
  const suffix = ext === "bare" ? "" : `.${ext}`;
24
24
  const clientName = deriveClientName(compiled);
25
+ const normalizeDocLines = (text) => String(text)
26
+ .replace(/\r\n?/g, "\n")
27
+ .split("\n")
28
+ .map(line => line.trim())
29
+ .filter(Boolean)
30
+ .map(line => line.replace(/\*\//g, "*\\/"));
25
31
  // Collect type names used in method signatures for the import statement
26
32
  const importedTypes = new Set();
27
33
  const methods = [];
@@ -37,7 +43,11 @@ export function generateOperations(outFile, compiled) {
37
43
  importedTypes.add(inTypeName);
38
44
  if (outTypeName)
39
45
  importedTypes.add(outTypeName);
40
- methods.push(` ${op.name}(\n` +
46
+ const docLines = op.doc ? normalizeDocLines(op.doc) : [];
47
+ const docBlock = docLines.length > 0
48
+ ? ` /**\n${docLines.map(line => ` * ${line}`).join("\n")}\n */\n`
49
+ : "";
50
+ methods.push(`${docBlock} ${op.name}(\n` +
41
51
  ` args: ${inTs}\n` +
42
52
  ` ): Promise<{ response: ${outTs}; headers: unknown }>;\n`);
43
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generateTypes.d.ts","sourceRoot":"","sources":["../../src/client/generateTypes.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAAe,MAAM,+BAA+B,CAAC;AAGjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QA+IvE"}
1
+ {"version":3,"file":"generateTypes.d.ts","sourceRoot":"","sources":["../../src/client/generateTypes.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAAe,MAAM,+BAA+B,CAAC;AAGjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAyLvE"}
@@ -35,6 +35,30 @@ import { error } from "../util/cli.js";
35
35
  */
36
36
  export function generateTypes(outFile, compiled) {
37
37
  const lines = [];
38
+ const normalizeDocLines = (text) => String(text)
39
+ .replace(/\r\n?/g, "\n")
40
+ .split("\n")
41
+ .map(line => line.trim())
42
+ .filter(Boolean)
43
+ .map(line => line.replace(/\*\//g, "*\\/"));
44
+ const emitDocBlock = (indent, docText, xsdTag) => {
45
+ if (!docText && !xsdTag) {
46
+ return;
47
+ }
48
+ lines.push(`${indent}/**`);
49
+ if (docText) {
50
+ for (const line of normalizeDocLines(docText)) {
51
+ lines.push(`${indent} * ${line}`);
52
+ }
53
+ }
54
+ if (xsdTag) {
55
+ if (docText) {
56
+ lines.push(`${indent} *`);
57
+ }
58
+ lines.push(`${indent} * @xsd ${xsdTag}`);
59
+ }
60
+ lines.push(`${indent} */`);
61
+ };
38
62
  // Convenience lookups
39
63
  const typeNames = new Set(compiled.types.map((t) => t.name));
40
64
  const isValidIdent = (name) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
@@ -45,8 +69,14 @@ export function generateTypes(outFile, compiled) {
45
69
  // sort aliases by name to ensure consistent order
46
70
  compiled.aliases.sort((a, b) => a.name.localeCompare(b.name));
47
71
  for (const a of compiled.aliases) {
48
- const ann = a.jsdoc ? `/** @xsd ${a.jsdoc} */\n` : "";
49
- lines.push(`${ann}export type ${a.name} = ${a.tsType};`);
72
+ if (a.doc) {
73
+ emitDocBlock("", a.doc, a.jsdoc);
74
+ lines.push(`export type ${a.name} = ${a.tsType};`);
75
+ }
76
+ else {
77
+ const ann = a.jsdoc ? `/** @xsd ${a.jsdoc} */\n` : "";
78
+ lines.push(`${ann}export type ${a.name} = ${a.tsType};`);
79
+ }
50
80
  lines.push("");
51
81
  }
52
82
  //
@@ -64,6 +94,9 @@ export function generateTypes(outFile, compiled) {
64
94
  typeNames.has(e.tsType));
65
95
  const isSimpleContentExtension = !complexBase && (t.elems?.length || 0) === 1 && valueElems.length === 1;
66
96
  const baseName = complexBase ?? (isSimpleContentExtension ? valueElems[0].tsType : undefined);
97
+ if (t.doc) {
98
+ emitDocBlock("", t.doc);
99
+ }
67
100
  // Header: extend base type if applicable
68
101
  if (baseName) {
69
102
  lines.push(`export interface ${t.name} extends ${baseName} {`);
@@ -108,9 +141,14 @@ export function generateTypes(outFile, compiled) {
108
141
  type: a.declaredType,
109
142
  use: a.use || "optional",
110
143
  };
111
- const ann = ` /** @xsd ${JSON.stringify(annObj)} */`;
112
144
  lines.push("");
113
- lines.push(ann);
145
+ if (a.doc) {
146
+ emitDocBlock(" ", a.doc, JSON.stringify(annObj));
147
+ }
148
+ else {
149
+ const ann = ` /** @xsd ${JSON.stringify(annObj)} */`;
150
+ lines.push(ann);
151
+ }
114
152
  lines.push(` ${emitPropName(a.name)}${opt}: ${a.tsType};`);
115
153
  }
116
154
  //
@@ -153,9 +191,14 @@ export function generateTypes(outFile, compiled) {
153
191
  if ((e.name === "$value") && (1 < elementsToEmit.length)) {
154
192
  lines.push("");
155
193
  }
156
- const ann = ` /** @xsd ${JSON.stringify(annObj)} */`;
157
194
  lines.push("");
158
- lines.push(ann);
195
+ if (e.doc) {
196
+ emitDocBlock(" ", e.doc, JSON.stringify(annObj));
197
+ }
198
+ else {
199
+ const ann = ` /** @xsd ${JSON.stringify(annObj)} */`;
200
+ lines.push(ann);
201
+ }
159
202
  lines.push(` ${emitPropName(e.name)}${opt}: ${e.tsType}${arr};`);
160
203
  }
161
204
  lines.push("}");
@@ -43,6 +43,7 @@ export type CompiledType = {
43
43
  tsType: string;
44
44
  use?: "required" | "optional";
45
45
  declaredType: string;
46
+ doc?: string;
46
47
  }>;
47
48
  elems: Array<{
48
49
  name: string;
@@ -51,14 +52,17 @@ export type CompiledType = {
51
52
  max: number | "unbounded";
52
53
  nillable?: boolean;
53
54
  declaredType: string;
55
+ doc?: string;
54
56
  }>;
55
57
  jsdoc?: string;
58
+ doc?: string;
56
59
  base?: string;
57
60
  localAttrs?: Array<{
58
61
  name: string;
59
62
  tsType: string;
60
63
  use?: "required" | "optional";
61
64
  declaredType: string;
65
+ doc?: string;
62
66
  }>;
63
67
  localElems?: Array<{
64
68
  name: string;
@@ -67,6 +71,7 @@ export type CompiledType = {
67
71
  max: number | "unbounded";
68
72
  nillable?: boolean;
69
73
  declaredType: string;
74
+ doc?: string;
70
75
  }>;
71
76
  };
72
77
  /**
@@ -85,6 +90,7 @@ export type CompiledAlias = {
85
90
  tsType: string;
86
91
  declared: string;
87
92
  jsdoc?: string;
93
+ doc?: string;
88
94
  };
89
95
  /**
90
96
  * Complete compiled catalog with all types, aliases, operations and metadata
@@ -117,6 +123,7 @@ export type CompiledCatalog = {
117
123
  security?: string[];
118
124
  inputTypeName?: string;
119
125
  outputTypeName?: string;
126
+ doc?: string;
120
127
  }>;
121
128
  wsdlTargetNS: string;
122
129
  wsdlUri: string;
@@ -1 +1 @@
1
- {"version":3,"file":"schemaCompiler.d.ts","sourceRoot":"","sources":["../../src/compiler/schemaCompiler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schemaCompiler.d.ts","sourceRoot":"","sources":["../../src/compiler/schemaCompiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AAKzD;;;;;;GAMG;AACH,MAAM,MAAM,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD;;;;;;;;;;;;GAYG;AACH,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;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,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;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;QAC9B,YAAY,EAAE,MAAM,CAAC;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,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;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ,CAAC;AAEF;;;;;;;;;GASG;AACH,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;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,eAAe,CAAC;IACzB,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,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACjD,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;QACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAwJF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CA4qB1F"}
@@ -92,6 +92,57 @@ function collectSecurityFromPolicyNodes(policyNodes) {
92
92
  visit(p);
93
93
  return Array.from(found);
94
94
  }
95
+ function extractNodeText(node) {
96
+ if (node == null) {
97
+ return "";
98
+ }
99
+ if (typeof node === "string" || typeof node === "number" || typeof node === "boolean") {
100
+ return String(node);
101
+ }
102
+ if (Array.isArray(node)) {
103
+ return node.map(extractNodeText).join(" ");
104
+ }
105
+ if (typeof node === "object") {
106
+ const parts = [];
107
+ if (node["#text"] != null) {
108
+ parts.push(extractNodeText(node["#text"]));
109
+ }
110
+ for (const [k, v] of Object.entries(node)) {
111
+ if ("#text" === k || k.startsWith("@_")) {
112
+ continue;
113
+ }
114
+ parts.push(extractNodeText(v));
115
+ }
116
+ return parts.join(" ");
117
+ }
118
+ return "";
119
+ }
120
+ function normalizeDocText(text) {
121
+ const compact = text
122
+ .replace(/\r\n?/g, "\n")
123
+ .split("\n")
124
+ .map(line => line.trim())
125
+ .filter(Boolean)
126
+ .join(" ")
127
+ .replace(/\s+/g, " ")
128
+ .trim();
129
+ return compact || undefined;
130
+ }
131
+ function extractDirectDocumentation(node) {
132
+ const docs = getChildrenWithLocalName(node, "documentation");
133
+ const merged = docs
134
+ .map(extractNodeText)
135
+ .join(" ");
136
+ return normalizeDocText(merged);
137
+ }
138
+ function extractAnnotationDocumentation(node) {
139
+ const annotations = getChildrenWithLocalName(node, "annotation");
140
+ const docs = annotations.flatMap(a => getChildrenWithLocalName(a, "documentation"));
141
+ const merged = docs
142
+ .map(extractNodeText)
143
+ .join(" ");
144
+ return normalizeDocText(merged);
145
+ }
95
146
  /**
96
147
  * Compile a WSDL catalog into an internal representation (CompiledCatalog).
97
148
  * Steps:
@@ -172,7 +223,14 @@ export function compileCatalog(cat, options) {
172
223
  return present;
173
224
  }
174
225
  const { tsType, declared, jsdoc } = compileSimpleTypeNode(sNode, schemaNS, prefixes);
175
- const alias = { name: pascal(name), ns: schemaNS, tsType, declared, jsdoc };
226
+ const alias = {
227
+ name: pascal(name),
228
+ ns: schemaNS,
229
+ tsType,
230
+ declared,
231
+ jsdoc,
232
+ doc: extractAnnotationDocumentation(sNode),
233
+ };
176
234
  aliasMap.set(key, alias);
177
235
  return alias;
178
236
  }
@@ -221,6 +279,7 @@ export function compileCatalog(cat, options) {
221
279
  }
222
280
  inProgress.add(rawKey);
223
281
  const outName = pascal(name);
282
+ const typeDoc = extractAnnotationDocumentation(cnode);
224
283
  const key = `${schemaNS}|${outName}`;
225
284
  // hoisted helpers for merging and collecting
226
285
  const mergeAttrs = (into, list) => {
@@ -267,7 +326,8 @@ export function compileCatalog(cat, options) {
267
326
  name: an,
268
327
  tsType: r.tsType,
269
328
  use: a["@_use"] === "required" ? "required" : "optional",
270
- declaredType: r.declared
329
+ declaredType: r.declared,
330
+ doc: extractAnnotationDocumentation(a),
271
331
  });
272
332
  }
273
333
  else {
@@ -279,7 +339,8 @@ export function compileCatalog(cat, options) {
279
339
  name: an,
280
340
  tsType: r.tsType,
281
341
  use: a["@_use"] === "required" ? "required" : "optional",
282
- declaredType: r.declared
342
+ declaredType: r.declared,
343
+ doc: extractAnnotationDocumentation(a),
283
344
  });
284
345
  }
285
346
  }
@@ -310,18 +371,35 @@ export function compileCatalog(cat, options) {
310
371
  min,
311
372
  max,
312
373
  nillable,
313
- declaredType: `{${schemaNS}}${rec.name}`
374
+ declaredType: `{${schemaNS}}${rec.name}`,
375
+ doc: extractAnnotationDocumentation(e),
314
376
  });
315
377
  }
316
378
  else if (inlineSimple) {
317
379
  const r = compileSimpleTypeNode(inlineSimple, schemaNS, prefixes);
318
- out.push({ name: propName || nameOrRef, tsType: r.tsType, min, max, nillable, declaredType: r.declared });
380
+ out.push({
381
+ name: propName || nameOrRef,
382
+ tsType: r.tsType,
383
+ min,
384
+ max,
385
+ nillable,
386
+ declaredType: r.declared,
387
+ doc: extractAnnotationDocumentation(e),
388
+ });
319
389
  }
320
390
  else {
321
391
  const t = e["@_type"] || e["@_ref"];
322
392
  const q = t ? resolveQName(t, schemaNS, prefixes) : { ns: XS, local: "string" };
323
393
  const r = resolveTypeRef(q, schemaNS, prefixes);
324
- out.push({ name: propName || nameOrRef, tsType: r.tsType, min, max, nillable, declaredType: r.declared });
394
+ out.push({
395
+ name: propName || nameOrRef,
396
+ tsType: r.tsType,
397
+ min,
398
+ max,
399
+ nillable,
400
+ declaredType: r.declared,
401
+ doc: extractAnnotationDocumentation(e),
402
+ });
325
403
  }
326
404
  }
327
405
  // recurse into nested compositor groups
@@ -341,6 +419,9 @@ export function compileCatalog(cat, options) {
341
419
  const newElems = collectParticles(outName, cnode);
342
420
  mergeAttrs(present.attrs, newAttrs);
343
421
  mergeElems(present.elems, newElems);
422
+ if (!present.doc && typeDoc) {
423
+ present.doc = typeDoc;
424
+ }
344
425
  // Remove from inProgress since we're done with this cycle
345
426
  inProgress.delete(rawKey);
346
427
  return present;
@@ -379,6 +460,7 @@ export function compileCatalog(cat, options) {
379
460
  ns: schemaNS,
380
461
  attrs,
381
462
  elems,
463
+ doc: typeDoc,
382
464
  base: baseName,
383
465
  localAttrs: locals,
384
466
  localElems
@@ -409,7 +491,7 @@ export function compileCatalog(cat, options) {
409
491
  declaredType: r.declared,
410
492
  }]);
411
493
  mergeAttrs(attrs, collectAttributes(scNode));
412
- const result = { name: outName, ns: schemaNS, attrs, elems };
494
+ const result = { name: outName, ns: schemaNS, attrs, elems, doc: typeDoc };
413
495
  compiledMap.set(key, result);
414
496
  inProgress.delete(rawKey);
415
497
  return result;
@@ -424,7 +506,7 @@ export function compileCatalog(cat, options) {
424
506
  // Attributes + particles
425
507
  mergeAttrs(attrs, collectAttributes(cnode));
426
508
  mergeElems(elems, collectParticles(outName, cnode));
427
- const result = { name: outName, ns: schemaNS, attrs, elems };
509
+ const result = { name: outName, ns: schemaNS, attrs, elems, doc: typeDoc };
428
510
  compiledMap.set(key, result);
429
511
  inProgress.delete(rawKey);
430
512
  return result;
@@ -432,6 +514,7 @@ export function compileCatalog(cat, options) {
432
514
  // Helper: compile a global element into a surface type (wrapper)
433
515
  function compileElementAsType(name, enode, schemaNS, prefixes) {
434
516
  const outName = pascal(name);
517
+ const elementDoc = extractAnnotationDocumentation(enode);
435
518
  const key = `${schemaNS}|${outName}`;
436
519
  const present = compiledMap.get(key);
437
520
  if (present)
@@ -448,6 +531,7 @@ export function compileCatalog(cat, options) {
448
531
  ns: schemaNS,
449
532
  attrs: [],
450
533
  elems: [{ name: "$value", tsType: r.tsType, min: 0, max: 1, nillable: false, declaredType: r.declared }],
534
+ doc: elementDoc,
451
535
  };
452
536
  compiledMap.set(key, t);
453
537
  return t;
@@ -470,6 +554,7 @@ export function compileCatalog(cat, options) {
470
554
  nillable: false,
471
555
  declaredType: label
472
556
  }],
557
+ doc: elementDoc,
473
558
  };
474
559
  compiledMap.set(key, t);
475
560
  return t;
@@ -485,10 +570,13 @@ export function compileCatalog(cat, options) {
485
570
  const existingAlias = aliasMap.get(aliasKey);
486
571
  const declared = `{${base.ns}}${base.name}`;
487
572
  if (!existingAlias) {
488
- aliasMap.set(aliasKey, { name: outName, ns: schemaNS, tsType: base.name, declared });
573
+ aliasMap.set(aliasKey, { name: outName, ns: schemaNS, tsType: base.name, declared, doc: elementDoc });
489
574
  }
490
575
  else {
491
576
  // if an alias exists but points elsewhere, keep the first one (stable) and ignore
577
+ if (!existingAlias.doc && elementDoc) {
578
+ existingAlias.doc = elementDoc;
579
+ }
492
580
  }
493
581
  }
494
582
  // Return base so callers have a CompiledType, but do not duplicate in compiledMap for wrapper
@@ -509,13 +597,14 @@ export function compileCatalog(cat, options) {
509
597
  nillable: false,
510
598
  declaredType: `{${a.ns}}${q.local}`
511
599
  }],
600
+ doc: elementDoc,
512
601
  };
513
602
  compiledMap.set(key, t);
514
603
  return t;
515
604
  }
516
605
  }
517
606
  // default empty wrapper
518
- const t = { name: outName, ns: schemaNS, attrs: [], elems: [] };
607
+ const t = { name: outName, ns: schemaNS, attrs: [], elems: [], doc: elementDoc };
519
608
  compiledMap.set(key, t);
520
609
  return t;
521
610
  }
@@ -652,10 +741,11 @@ export function compileCatalog(cat, options) {
652
741
  const outMsg = findMessage(getFirstWithLocalName(po, "output")?.["@_message"]);
653
742
  const inputElement = elementOfMessage(inMsg);
654
743
  const outputElement = elementOfMessage(outMsg);
744
+ const doc = extractDirectDocumentation(po);
655
745
  // Derive TypeScript type names from element local names
656
746
  const inputTypeName = inputElement ? pascal(inputElement.local) : undefined;
657
747
  const outputTypeName = outputElement ? pascal(outputElement.local) : undefined;
658
- return { name, soapAction: bOps.get(name) || "", inputElement, outputElement, inputTypeName, outputTypeName };
748
+ return { name, soapAction: bOps.get(name) || "", inputElement, outputElement, inputTypeName, outputTypeName, doc };
659
749
  })
660
750
  .filter((x) => x != null));
661
751
  // --- WS-Policy: scan for security requirements (inline policies only) ---
@@ -1 +1 @@
1
- {"version":3,"file":"generatePaths.d.ts","sourceRoot":"","sources":["../../src/openapi/generatePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAG3C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAC/B,CAAC,MAAM,EAAE,MAAM,GAAG;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAE9B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;IAC9C,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC9C;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,oBAAoB,uBAyDlF"}
1
+ {"version":3,"file":"generatePaths.d.ts","sourceRoot":"","sources":["../../src/openapi/generatePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAG3C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAC/B,CAAC,MAAM,EAAE,MAAM,GAAG;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAE9B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;IAC9C,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC9C;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,oBAAoB,uBA6DlF"}
@@ -42,8 +42,12 @@ export function generatePaths(compiled, opts) {
42
42
  };
43
43
  if (override.summary)
44
44
  operationObject.summary = override.summary;
45
- if (override.description)
45
+ if (override.description) {
46
46
  operationObject.description = override.description;
47
+ }
48
+ else if (op.doc) {
49
+ operationObject.description = op.doc;
50
+ }
47
51
  if (override.deprecated)
48
52
  operationObject.deprecated = true;
49
53
  if (parameters.length)
@@ -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;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"}
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;AAgKpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,sBAAsB,GAAG,iBAAiB,CA+C1G"}
@@ -28,14 +28,24 @@ function primitiveSchema(ts) {
28
28
  function buildAliasSchema(a) {
29
29
  const lit = isLiteralUnion(a.tsType);
30
30
  if (lit) {
31
- return { type: "string", enum: lit };
31
+ return {
32
+ type: "string",
33
+ enum: lit,
34
+ ...(a.doc ? { description: a.doc } : {}),
35
+ };
32
36
  }
33
37
  // If alias wraps primitive
34
38
  if (["string", "number", "boolean", "any"].includes(a.tsType) || a.tsType.endsWith("[]")) {
35
- return primitiveSchema(a.tsType);
39
+ return {
40
+ ...primitiveSchema(a.tsType),
41
+ ...(a.doc ? { description: a.doc } : {}),
42
+ };
36
43
  }
37
44
  // alias of another complex/alias type -> allOf wrapper preserves name
38
- return { allOf: [{ $ref: `#/components/schemas/${a.tsType}` }] };
45
+ return {
46
+ allOf: [{ $ref: `#/components/schemas/${a.tsType}` }],
47
+ ...(a.doc ? { description: a.doc } : {}),
48
+ };
39
49
  }
40
50
  function isArrayWrapper(t) {
41
51
  if (t.attrs.length !== 0)
@@ -80,13 +90,21 @@ function buildComplexSchema(t, closed, knownTypeNames, aliasNames, flattenWrappe
80
90
  const arrayWrap = flattenWrappers ? isArrayWrapper(t) : null;
81
91
  if (arrayWrap) {
82
92
  const item = refOrPrimitive(String(arrayWrap.itemType));
83
- return { type: "array", items: item };
93
+ return {
94
+ type: "array",
95
+ items: item,
96
+ ...(t.doc ? { description: t.doc } : {}),
97
+ };
84
98
  }
85
99
  const properties = {};
86
100
  const required = [];
87
101
  // attributes
88
102
  for (const a of t.attrs) {
89
- properties[a.name] = refOrPrimitive(a.tsType);
103
+ const propSchema = refOrPrimitive(a.tsType);
104
+ if (a.doc) {
105
+ propSchema.description = a.doc;
106
+ }
107
+ properties[a.name] = propSchema;
90
108
  if (a.use === "required")
91
109
  required.push(a.name);
92
110
  }
@@ -100,6 +118,9 @@ function buildComplexSchema(t, closed, knownTypeNames, aliasNames, flattenWrappe
100
118
  if (e.nillable) {
101
119
  schema = { anyOf: [schema, { type: "null" }] };
102
120
  }
121
+ if (e.doc) {
122
+ schema.description = e.doc;
123
+ }
103
124
  properties[e.name] = schema;
104
125
  if (e.name === "$value") {
105
126
  // never required
@@ -130,6 +151,9 @@ function buildComplexSchema(t, closed, knownTypeNames, aliasNames, flattenWrappe
130
151
  if (!closed)
131
152
  delete obj.additionalProperties; // put closed only on leaf part
132
153
  }
154
+ if (t.doc) {
155
+ obj.description = t.doc;
156
+ }
133
157
  return obj;
134
158
  }
135
159
  /**
@@ -83,6 +83,8 @@ CompiledCatalog {
83
83
  }
84
84
  ```
85
85
 
86
+ `CompiledType`, type aliases, and operations may include optional `doc` fields populated from WSDL/XSD documentation nodes. Client emitters consume these values to generate comments in `types.ts`, `operations.ts`, and `client.ts`. OpenAPI emitters consume the same fields for schema, property, and operation `description` values.
87
+
86
88
  Data flow through the pipeline:
87
89
 
88
90
  1. schemaCompiler produces CompiledCatalog from WSDL XML
package/docs/concepts.md CHANGED
@@ -67,6 +67,8 @@ cacheable, and reused across client, OpenAPI, and gateway generation.
67
67
  Inspect types, operations, and metadata as plain JSON. The catalog is
68
68
  automatically placed alongside generated output.
69
69
 
70
+ The catalog stores optional human-readable `doc` fields extracted from WSDL/XSD documentation nodes. These fields are additive metadata used by TypeScript and OpenAPI emitters and do not change runtime behavior.
71
+
70
72
  ### Catalog Locations by Command
71
73
 
72
74
  | Command | Location |
@@ -73,6 +73,34 @@ result.GetCityWeatherByZIPResult.Temperature;
73
73
 
74
74
  Autocomplete and type checking work across all generated interfaces.
75
75
 
76
+ ## Documentation Comments
77
+
78
+ Generated `types.ts`, `operations.ts`, and `client.ts` include source documentation when present in WSDL/XSD.
79
+
80
+ `wsdl:documentation` on operations is emitted as method comments in `operations.ts` and `client.ts`. `xs:annotation/xs:documentation` on complex types, attributes, and elements is emitted as comments in `types.ts`.
81
+
82
+ ```typescript
83
+ /**
84
+ * Thing payload.
85
+ */
86
+ export interface Thing {
87
+ /**
88
+ * Display name.
89
+ *
90
+ * @xsd {"kind":"element","type":"xs:string","occurs":{"min":1,"max":1,"nillable":false}}
91
+ */
92
+ name: string;
93
+ }
94
+ ```
95
+
96
+ The existing `@xsd` metadata annotations are preserved for runtime marshaling and tooling.
97
+
98
+ OpenAPI generation also propagates these docs into `description` fields:
99
+
100
+ - Operation descriptions come from `wsdl:documentation` by default
101
+ - `--openapi-ops-file` `description` overrides operation documentation when provided
102
+ - Schema and property descriptions come from `xs:annotation/xs:documentation`
103
+
76
104
  ## Gateway Route Handlers
77
105
 
78
106
  When generating a Fastify gateway (`--gateway-dir`), each SOAP operation gets a fully typed route handler. The handler imports the request type from the client, uses Fastify's `Body: T` generic for type inference, and wraps the SOAP response in a standard envelope.
@@ -99,9 +127,9 @@ export async function registerRoute_v1_weather_getcityforecastbyzip(fastify: Fas
99
127
 
100
128
  Key features of the generated handlers:
101
129
 
102
- - **`Body: T` generic** Fastify infers `request.body` type from the route generic, enabling IDE autocomplete and compile-time checks
103
- - **JSON Schema validation** the `schema` import provides Fastify with request/response validation at runtime, before the handler runs
104
- - **Envelope wrapping** `buildSuccessEnvelope()` wraps the raw SOAP response in the standard `{ status, message, data, error }` envelope
130
+ - `Body: T` generic: Fastify infers `request.body` type from the route generic, enabling IDE autocomplete and compile-time checks
131
+ - JSON Schema validation: the `schema` import provides Fastify with request/response validation at runtime, before the handler runs
132
+ - Envelope wrapping: `buildSuccessEnvelope()` wraps the raw SOAP response in the standard `{ status, message, data, error }` envelope
105
133
 
106
134
  See [Gateway Guide](gateway-guide.md) for the full architecture and [CLI Reference](cli-reference.md) for generation flags.
107
135
 
package/docs/testing.md CHANGED
@@ -8,9 +8,9 @@ See [README](../README.md) for quick start and [CONTRIBUTING](../CONTRIBUTING.md
8
8
 
9
9
  The project uses three layers of testing:
10
10
 
11
- 1. **Unit tests** Pure function tests for utilities, parsers, and type mapping
12
- 2. **Snapshot tests** Baseline comparisons for all generated pipeline output
13
- 3. **Integration tests** End-to-end gateway tests using Fastify's `inject()` with mock clients
11
+ 1. Unit tests: Pure function tests for utilities, parsers, and type mapping
12
+ 2. Snapshot tests: Baseline comparisons for all generated pipeline output
13
+ 3. Integration tests: End-to-end gateway tests using Fastify's `inject()` with mock clients
14
14
 
15
15
  All tests use [Vitest](https://vitest.dev/) and run in under 3 seconds.
16
16
 
@@ -34,12 +34,13 @@ npm run ci
34
34
 
35
35
  Unit tests cover pure functions with no I/O or side effects:
36
36
 
37
- - **`tools.test.ts`** `pascal()`, `resolveQName()`, `explodePascal()`, `pascalToSnakeCase()`, `normalizeArray()`, `getChildrenWithLocalName()`, `getFirstWithLocalName()`
38
- - **`casing.test.ts`** `toPathSegment()` with kebab, asis, and lower styles
39
- - **`primitives.test.ts`** `xsdToTsPrimitive()` covering all XSD types (string-like, boolean, integers, decimals, floats, dates, any)
40
- - **`errors.test.ts`** `WsdlCompilationError` construction and `toUserMessage()` formatting
41
- - **`schema-alignment.test.ts`** Cross-validates TypeScript types, JSON schemas, and catalog.json for consistency
42
- - **`mock-data.test.ts`** `generateMockPrimitive()`, `generateMockData()`, `generateAllOperationMocks()` with cycle detection and array wrapping
37
+ - `tools.test.ts`: `pascal()`, `resolveQName()`, `explodePascal()`, `pascalToSnakeCase()`, `normalizeArray()`, `getChildrenWithLocalName()`, `getFirstWithLocalName()`
38
+ - `casing.test.ts`: `toPathSegment()` with kebab, asis, and lower styles
39
+ - `primitives.test.ts`: `xsdToTsPrimitive()` covering all XSD types (string-like, boolean, integers, decimals, floats, dates, any)
40
+ - `errors.test.ts`: `WsdlCompilationError` construction and `toUserMessage()` formatting
41
+ - `schema-alignment.test.ts`: Cross-validates TypeScript types, JSON schemas, and catalog.json for consistency
42
+ - `mock-data.test.ts`: `generateMockPrimitive()`, `generateMockData()`, `generateAllOperationMocks()` with cycle detection and array wrapping
43
+ - `wsdl-documentation.test.ts`: verifies doc flow to catalog, generated TS comments, and OpenAPI descriptions with override precedence
43
44
 
44
45
  ### Writing Unit Tests
45
46
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techspokes/typescript-wsdl-client",
3
- "version": "0.11.6",
3
+ "version": "0.13.0",
4
4
  "description": "Generate type-safe TypeScript SOAP clients, OpenAPI 3.1 specs, and production-ready Fastify REST gateways from WSDL/XSD definitions.",
5
5
  "keywords": [
6
6
  "wsdl",
@@ -76,20 +76,20 @@
76
76
  },
77
77
  "devDependencies": {
78
78
  "@types/js-yaml": "^4.0.9",
79
- "@types/node": "^25.2.0",
79
+ "@types/node": "^25.3.3",
80
80
  "@types/yargs": "^17.0.35",
81
- "fastify": "^5.7.0",
81
+ "fastify": "^5.7.4",
82
82
  "fastify-plugin": "^5.1.0",
83
- "rimraf": "^6.1.0",
83
+ "rimraf": "^6.1.3",
84
84
  "tsx": "^4.21.0",
85
- "typescript": "^5.9.0",
85
+ "typescript": "^5.9.3",
86
86
  "vitest": "^4.0.18"
87
87
  },
88
88
  "dependencies": {
89
89
  "@apidevtools/swagger-parser": "^12.1.0",
90
- "fast-xml-parser": "^5.3.0",
90
+ "fast-xml-parser": "^5.4.2",
91
91
  "js-yaml": "^4.1.1",
92
- "soap": "^1.6.0",
92
+ "soap": "^1.7.1",
93
93
  "yargs": "^18.0.0"
94
94
  },
95
95
  "funding": {