@techspokes/typescript-wsdl-client 0.11.6 → 0.14.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,38 @@ export type CompiledAlias = {
85
90
  tsType: string;
86
91
  declared: string;
87
92
  jsdoc?: string;
93
+ doc?: string;
94
+ };
95
+ export type CompiledWsdlPartDoc = {
96
+ name?: string;
97
+ element?: QName;
98
+ type?: QName;
99
+ doc?: string;
100
+ };
101
+ export type CompiledWsdlMessageDoc = {
102
+ name: string;
103
+ doc?: string;
104
+ parts?: CompiledWsdlPartDoc[];
105
+ };
106
+ export type CompiledWsdlBindingDoc = {
107
+ name: string;
108
+ type?: QName;
109
+ doc?: string;
110
+ };
111
+ export type CompiledWsdlPortDoc = {
112
+ name: string;
113
+ binding?: QName;
114
+ doc?: string;
115
+ };
116
+ export type CompiledWsdlServiceDoc = {
117
+ name: string;
118
+ doc?: string;
119
+ ports?: CompiledWsdlPortDoc[];
120
+ };
121
+ export type CompiledWsdlDocs = {
122
+ bindings?: CompiledWsdlBindingDoc[];
123
+ messages?: CompiledWsdlMessageDoc[];
124
+ services?: CompiledWsdlServiceDoc[];
88
125
  };
89
126
  /**
90
127
  * Complete compiled catalog with all types, aliases, operations and metadata
@@ -117,10 +154,12 @@ export type CompiledCatalog = {
117
154
  security?: string[];
118
155
  inputTypeName?: string;
119
156
  outputTypeName?: string;
157
+ doc?: string;
120
158
  }>;
121
159
  wsdlTargetNS: string;
122
160
  wsdlUri: string;
123
161
  serviceName?: string;
162
+ wsdlDocs?: CompiledWsdlDocs;
124
163
  };
125
164
  /**
126
165
  * Compile a WSDL catalog into an internal representation (CompiledCatalog).
@@ -1 +1 @@
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;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;IACf,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;KACtB,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;KACtB,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;CAChB,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;KACzB,CAAC,CAAC;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAiGF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAooB1F"}
1
+ {"version":3,"file":"schemaCompiler.d.ts","sourceRoot":"","sources":["../../src/compiler/schemaCompiler.ts"],"names":[],"mappings":"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"}
@@ -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
  }
@@ -595,6 +684,8 @@ export function compileCatalog(cat, options) {
595
684
  const defs = cat.wsdlXml["wsdl:definitions"] || cat.wsdlXml["definitions"];
596
685
  const tns = defs?.["@_targetNamespace"] || "";
597
686
  const bindingDefs = normalizeArray(defs?.["wsdl:binding"] || defs?.["binding"]);
687
+ const msgDefs = normalizeArray(defs?.["wsdl:message"] || defs?.["message"]);
688
+ const serviceDefs = normalizeArray(defs?.["wsdl:service"] || defs?.["service"]);
598
689
  const soapBinding = bindingDefs.find(b => Object.keys(b).some(k => k === "soap:binding" || k === "soap12:binding")) || bindingDefs[0];
599
690
  if (!soapBinding) {
600
691
  throw new WsdlCompilationError("No SOAP binding found in the WSDL document.", {
@@ -623,7 +714,6 @@ export function compileCatalog(cat, options) {
623
714
  const action = soapOp?.["@_soapAction"] || soapOp?.["@_soapActionURI"] || soapOp?.["@_soapActionUrl"] || "";
624
715
  bOps.set(name, action);
625
716
  }
626
- const msgDefs = normalizeArray(defs?.["wsdl:message"] || defs?.["message"]);
627
717
  const findMessage = (qstr) => {
628
718
  if (!qstr)
629
719
  return undefined;
@@ -642,6 +732,85 @@ export function compileCatalog(cat, options) {
642
732
  const q = resolveQName(el, tns, cat.prefixMap);
643
733
  return { ns: q.ns, local: q.local };
644
734
  };
735
+ const messageDocs = msgDefs
736
+ .map((msg) => {
737
+ const name = msg?.["@_name"];
738
+ if (!name)
739
+ return undefined;
740
+ const doc = extractDirectDocumentation(msg);
741
+ const parts = getChildrenWithLocalName(msg, "part")
742
+ .map((part) => {
743
+ const partName = part?.["@_name"];
744
+ const partElement = part?.["@_element"];
745
+ const partType = part?.["@_type"];
746
+ const partDoc = extractDirectDocumentation(part);
747
+ const element = partElement ? resolveQName(partElement, tns, cat.prefixMap) : undefined;
748
+ const type = partType ? resolveQName(partType, tns, cat.prefixMap) : undefined;
749
+ if (!partName && !element && !type && !partDoc)
750
+ return undefined;
751
+ return {
752
+ ...(partName ? { name: partName } : {}),
753
+ ...(element ? { element: { ns: element.ns, local: element.local } } : {}),
754
+ ...(type ? { type: { ns: type.ns, local: type.local } } : {}),
755
+ ...(partDoc ? { doc: partDoc } : {}),
756
+ };
757
+ })
758
+ .filter((x) => x != null)
759
+ .sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
760
+ return {
761
+ name,
762
+ ...(doc ? { doc } : {}),
763
+ ...(parts.length ? { parts } : {}),
764
+ };
765
+ })
766
+ .filter((x) => x != null)
767
+ .sort((a, b) => a.name.localeCompare(b.name));
768
+ const bindingDocs = bindingDefs
769
+ .map((binding) => {
770
+ const name = binding?.["@_name"];
771
+ if (!name)
772
+ return undefined;
773
+ const typeLabel = binding?.["@_type"];
774
+ const type = typeLabel ? resolveQName(typeLabel, tns, cat.prefixMap) : undefined;
775
+ const doc = extractDirectDocumentation(binding);
776
+ return {
777
+ name,
778
+ ...(type ? { type: { ns: type.ns, local: type.local } } : {}),
779
+ ...(doc ? { doc } : {}),
780
+ };
781
+ })
782
+ .filter((x) => x != null)
783
+ .sort((a, b) => a.name.localeCompare(b.name));
784
+ const serviceDocs = serviceDefs
785
+ .map((service) => {
786
+ const name = service?.["@_name"];
787
+ if (!name)
788
+ return undefined;
789
+ const doc = extractDirectDocumentation(service);
790
+ const ports = getChildrenWithLocalName(service, "port")
791
+ .map((port) => {
792
+ const portName = port?.["@_name"];
793
+ const bindingLabel = port?.["@_binding"];
794
+ const binding = bindingLabel ? resolveQName(bindingLabel, tns, cat.prefixMap) : undefined;
795
+ const portDoc = extractDirectDocumentation(port);
796
+ if (!portName)
797
+ return undefined;
798
+ return {
799
+ name: portName,
800
+ ...(binding ? { binding: { ns: binding.ns, local: binding.local } } : {}),
801
+ ...(portDoc ? { doc: portDoc } : {}),
802
+ };
803
+ })
804
+ .filter((x) => x != null)
805
+ .sort((a, b) => a.name.localeCompare(b.name));
806
+ return {
807
+ name,
808
+ ...(doc ? { doc } : {}),
809
+ ...(ports.length ? { ports } : {}),
810
+ };
811
+ })
812
+ .filter((x) => x != null)
813
+ .sort((a, b) => a.name.localeCompare(b.name));
645
814
  // build operations list
646
815
  const ops = (pOps
647
816
  .map(po => {
@@ -652,10 +821,11 @@ export function compileCatalog(cat, options) {
652
821
  const outMsg = findMessage(getFirstWithLocalName(po, "output")?.["@_message"]);
653
822
  const inputElement = elementOfMessage(inMsg);
654
823
  const outputElement = elementOfMessage(outMsg);
824
+ const doc = extractDirectDocumentation(po);
655
825
  // Derive TypeScript type names from element local names
656
826
  const inputTypeName = inputElement ? pascal(inputElement.local) : undefined;
657
827
  const outputTypeName = outputElement ? pascal(outputElement.local) : undefined;
658
- return { name, soapAction: bOps.get(name) || "", inputElement, outputElement, inputTypeName, outputTypeName };
828
+ return { name, soapAction: bOps.get(name) || "", inputElement, outputElement, inputTypeName, outputTypeName, doc };
659
829
  })
660
830
  .filter((x) => x != null));
661
831
  // --- WS-Policy: scan for security requirements (inline policies only) ---
@@ -671,7 +841,6 @@ export function compileCatalog(cat, options) {
671
841
  // --- Service discovery (for client naming) ---
672
842
  let serviceName;
673
843
  const soapBindingName = soapBinding?.["@_name"];
674
- const serviceDefs = normalizeArray(defs?.["wsdl:service"] || defs?.["service"]);
675
844
  const serviceUsingBinding = serviceDefs.find(s => {
676
845
  const ports = getChildrenWithLocalName(s, "port");
677
846
  return ports.some(p => {
@@ -683,6 +852,13 @@ export function compileCatalog(cat, options) {
683
852
  });
684
853
  });
685
854
  serviceName = serviceUsingBinding?.["@_name"] || serviceDefs[0]?.["@_name"];
855
+ const wsdlDocs = (bindingDocs.length || messageDocs.length || serviceDocs.length)
856
+ ? {
857
+ ...(bindingDocs.length ? { bindings: bindingDocs } : {}),
858
+ ...(messageDocs.length ? { messages: messageDocs } : {}),
859
+ ...(serviceDocs.length ? { services: serviceDocs } : {}),
860
+ }
861
+ : undefined;
686
862
  return {
687
863
  options: options,
688
864
  types: typesList,
@@ -691,6 +867,7 @@ export function compileCatalog(cat, options) {
691
867
  operations: ops,
692
868
  wsdlTargetNS: defs?.["@_targetNamespace"] || "",
693
869
  serviceName,
694
- wsdlUri: cat.wsdlUri
870
+ wsdlUri: cat.wsdlUri,
871
+ ...(wsdlDocs ? { wsdlDocs } : {}),
695
872
  };
696
873
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generateGateway.d.ts","sourceRoot":"","sources":["../../src/gateway/generateGateway.ts"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAE/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyJjF"}
1
+ {"version":3,"file":"generateGateway.d.ts","sourceRoot":"","sources":["../../src/gateway/generateGateway.ts"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAE/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6JjF"}
@@ -155,12 +155,16 @@ export async function generateGateway(opts) {
155
155
  const operationId = opDef?.operationId || op.operationSlug;
156
156
  // Resolve full operation metadata from catalog
157
157
  const resolved = resolveOperationMeta(operationId, op.operationSlug, op.method, op.path, catalog?.operations);
158
+ const openApiSummary = typeof opDef?.summary === "string" ? opDef.summary : undefined;
159
+ const openApiDescription = typeof opDef?.description === "string" ? opDef.description : undefined;
158
160
  return {
159
161
  ...op,
160
162
  operationId: resolved.operationId,
161
163
  clientMethodName: resolved.clientMethodName,
162
164
  requestTypeName: resolved.requestTypeName,
163
165
  responseTypeName: resolved.responseTypeName,
166
+ summary: openApiSummary ?? resolved.summary,
167
+ description: openApiDescription ?? resolved.description,
164
168
  };
165
169
  });
166
170
  // Step 4: Emit schemas.ts module
@@ -36,6 +36,8 @@ export interface OperationMetadata {
36
36
  clientMethodName?: string;
37
37
  requestTypeName?: string;
38
38
  responseTypeName?: string;
39
+ summary?: string;
40
+ description?: string;
39
41
  /** When true, response schema is omitted from route registration to avoid fast-json-stringify stack overflow on deeply nested $ref graphs */
40
42
  skipResponseSchema?: boolean;
41
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"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"}
@@ -56,6 +56,29 @@ export function emitModelSchemas(schemas, modelsDir, versionSlug, serviceSlug) {
56
56
  }
57
57
  return schemaIdByName;
58
58
  }
59
+ function normalizeDocCommentText(value) {
60
+ const normalized = String(value ?? "")
61
+ .replace(/\r\n?/g, "\n")
62
+ .split("\n")
63
+ .map(line => line.trim())
64
+ .filter(Boolean)
65
+ .join(" ")
66
+ .replace(/\s+/g, " ")
67
+ .trim();
68
+ if (!normalized)
69
+ return undefined;
70
+ return normalized.replace(/\*\//g, "* /");
71
+ }
72
+ function buildOperationDocLines(op) {
73
+ const summary = normalizeDocCommentText(op.summary);
74
+ const description = normalizeDocCommentText(op.description);
75
+ let out = "";
76
+ if (summary)
77
+ out += ` * Summary: ${summary}\n`;
78
+ if (description)
79
+ out += ` * Description: ${description}\n`;
80
+ return out;
81
+ }
59
82
  /**
60
83
  * Emits Fastify-compatible operation schema files
61
84
  *
@@ -197,6 +220,8 @@ export function emitOperationSchemas(doc, opsDir, versionSlug, serviceSlug, sche
197
220
  operationSlug,
198
221
  method: lowerMethod,
199
222
  path: p,
223
+ summary: normalizeDocCommentText(typeof operation.summary === "string" ? operation.summary : undefined),
224
+ description: normalizeDocCommentText(typeof operation.description === "string" ? operation.description : undefined),
200
225
  skipResponseSchema,
201
226
  });
202
227
  }
@@ -269,8 +294,15 @@ export function emitRouteFiles(outDir, routesDir, versionSlug, serviceSlug, oper
269
294
  routesTs += `import { ${fnName} } from "./routes/${routeFileBase}${suffix}";\n`;
270
295
  // Generate individual route file
271
296
  // Note: op.path comes from OpenAPI and already includes any base path
297
+ const operationDocLines = buildOperationDocLines(op);
272
298
  let routeTs = "";
273
- routeTs += `import type { FastifyInstance } from "fastify";\n`;
299
+ routeTs += `/**
300
+ * Route: ${op.method.toUpperCase()} ${op.path}
301
+ * Operation: ${op.operationId || op.operationSlug}
302
+ ${operationDocLines} * Auto-generated - do not edit manually.
303
+ */
304
+ import type { FastifyInstance } from "fastify";
305
+ `;
274
306
  routeTs += `import schema from "../schemas/operations/${op.operationSlug}.json" with { type: "json" };\n\n`;
275
307
  routeTs += `export async function ${fnName}(fastify: FastifyInstance) {\n`;
276
308
  if (op.skipResponseSchema) {
@@ -780,10 +812,11 @@ export function emitRouteFilesWithHandlers(outDir, routesDir, versionSlug, servi
780
812
  const schemaLine = op.skipResponseSchema
781
813
  ? " schema: routeSchema,"
782
814
  : " schema,";
815
+ const operationDocLines = buildOperationDocLines(op);
783
816
  let routeTs = `/**
784
817
  * Route: ${op.method.toUpperCase()} ${op.path}
785
818
  * Operation: ${op.operationId || op.operationSlug}
786
- * Request Type: ${reqTypeName}
819
+ ${operationDocLines} * Request Type: ${reqTypeName}
787
820
  * Response Type: ${resTypeName} (wrapped in envelope)
788
821
  * Auto-generated - do not edit manually.
789
822
  */
@@ -174,6 +174,8 @@ export interface ResolvedOperationMeta {
174
174
  clientMethodName: string;
175
175
  requestTypeName?: string;
176
176
  responseTypeName?: string;
177
+ summary?: string;
178
+ description?: string;
177
179
  }
178
180
  /**
179
181
  * Options for resolving client metadata
@@ -221,6 +223,9 @@ export declare function resolveOperationMeta(operationId: string, operationSlug:
221
223
  name: string;
222
224
  inputTypeName?: string;
223
225
  outputTypeName?: string;
226
+ summary?: string;
227
+ description?: string;
228
+ doc?: string;
224
229
  }>): ResolvedOperationMeta;
225
230
  /**
226
231
  * Measures the $ref graph complexity of a schema component.
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"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"}
@@ -418,6 +418,8 @@ export function resolveOperationMeta(operationId, operationSlug, method, path, c
418
418
  // Use catalog type names if available, otherwise derive by convention
419
419
  const requestTypeName = catalogOp?.inputTypeName ?? pascal(operationId);
420
420
  const responseTypeName = catalogOp?.outputTypeName ?? pascal(operationId);
421
+ const description = normalizeOperationText(catalogOp?.description ?? catalogOp?.doc);
422
+ const summary = normalizeOperationText(catalogOp?.summary) ?? deriveSummaryFromText(description);
421
423
  return {
422
424
  operationId,
423
425
  operationSlug,
@@ -426,8 +428,27 @@ export function resolveOperationMeta(operationId, operationSlug, method, path, c
426
428
  clientMethodName: operationId, // Client methods use the original operation name
427
429
  requestTypeName,
428
430
  responseTypeName,
431
+ ...(summary ? { summary } : {}),
432
+ ...(description ? { description } : {}),
429
433
  };
430
434
  }
435
+ function normalizeOperationText(value) {
436
+ const normalized = String(value ?? "")
437
+ .replace(/\r\n?/g, "\n")
438
+ .split("\n")
439
+ .map(line => line.trim())
440
+ .filter(Boolean)
441
+ .join(" ")
442
+ .replace(/\s+/g, " ")
443
+ .trim();
444
+ return normalized || undefined;
445
+ }
446
+ function deriveSummaryFromText(value) {
447
+ if (!value)
448
+ return undefined;
449
+ const firstSentence = value.match(/^(.+?[.!?])(?:\s|$)/);
450
+ return firstSentence ? firstSentence[1].trim() : value;
451
+ }
431
452
  /**
432
453
  * Measures the $ref graph complexity of a schema component.
433
454
  *
@@ -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,uBAkElF"}
@@ -40,10 +40,20 @@ export function generatePaths(compiled, opts) {
40
40
  }
41
41
  },
42
42
  };
43
- if (override.summary)
43
+ if (override.summary) {
44
44
  operationObject.summary = override.summary;
45
- if (override.description)
45
+ }
46
+ else if (op.doc) {
47
+ const derivedSummary = deriveSummaryFromDoc(op.doc);
48
+ if (derivedSummary)
49
+ operationObject.summary = derivedSummary;
50
+ }
51
+ if (override.description) {
46
52
  operationObject.description = override.description;
53
+ }
54
+ else if (op.doc) {
55
+ operationObject.description = op.doc;
56
+ }
47
57
  if (override.deprecated)
48
58
  operationObject.deprecated = true;
49
59
  if (parameters.length)
@@ -57,6 +67,13 @@ export function generatePaths(compiled, opts) {
57
67
  }
58
68
  return paths;
59
69
  }
70
+ function deriveSummaryFromDoc(doc) {
71
+ const normalized = String(doc ?? "").replace(/\s+/g, " ").trim();
72
+ if (!normalized)
73
+ return undefined;
74
+ const firstSentence = normalized.match(/^(.+?[.!?])(?:\s|$)/);
75
+ return firstSentence ? firstSentence[1].trim() : normalized;
76
+ }
60
77
  function normalizeBase(base) {
61
78
  if (!base.startsWith("/"))
62
79
  base = "/" + base;
@@ -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
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/test/generators.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,UAAU,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAGnD,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAErH;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAkBzC;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CA+CR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,UAAU,GACrB,MAAM,CAsCR;AAED;;;;;;;GAOG;AAEH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CA4CR;AAED;;;;;;;GAOG;AAEH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CAiIR;AAED;;GAEG;AAEH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CAuER;AAED;;GAEG;AAEH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,GAClC,MAAM,CAoCR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAChC,MAAM,CAgFR;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAChC,MAAM,CAgDR;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,OAAO,EAAE,eAAe,GACvB,MAAM,GAAG,IAAI,CAkEf"}
1
+ {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/test/generators.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,UAAU,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAGnD,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAerH;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAkBzC;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CA+CR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,UAAU,GACrB,MAAM,CAsCR;AAED;;;;;;;GAOG;AAEH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CA8CR;AAED;;;;;;;GAOG;AAEH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CAiIR;AAED;;GAEG;AAEH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,EACnC,KAAK,EAAE,iBAAiB,GACvB,MAAM,CAuER;AAED;;GAEG;AAEH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,qBAAqB,EAAE,GAClC,MAAM,CAoCR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAChC,MAAM,CAgFR;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAChC,MAAM,CAgDR;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,OAAO,EAAE,eAAe,GACvB,MAAM,GAAG,IAAI,CAkEf"}
@@ -10,6 +10,18 @@
10
10
  */
11
11
  import { computeRelativeImport } from "../util/imports.js";
12
12
  import { detectArrayWrappers, detectChildrenTypes } from "../util/catalogMeta.js";
13
+ function formatOperationHint(summary, description) {
14
+ const source = summary || description;
15
+ const normalized = String(source ?? "")
16
+ .replace(/\r\n?/g, "\n")
17
+ .split("\n")
18
+ .map(line => line.trim())
19
+ .filter(Boolean)
20
+ .join(" ")
21
+ .replace(/\s+/g, " ")
22
+ .trim();
23
+ return normalized || undefined;
24
+ }
13
25
  /**
14
26
  * Emits vitest.config.ts content.
15
27
  *
@@ -152,7 +164,9 @@ export function emitRoutesTest(testDir, importsMode, operations, mocks) {
152
164
  const testCases = sortedOps.map((op) => {
153
165
  const mockData = mocks.get(op.operationId);
154
166
  const requestPayload = JSON.stringify(mockData?.request ?? {}, null, 4).replace(/\n/g, "\n ");
155
- return ` it("${op.method.toUpperCase()} ${op.path} returns SUCCESS envelope", async () => {
167
+ const hint = formatOperationHint(op.summary, op.description);
168
+ const hintComment = hint ? ` // ${hint}\n` : "";
169
+ return `${hintComment} it("${op.method.toUpperCase()} ${op.path} returns SUCCESS envelope", async () => {
156
170
  const app = await createTestApp();
157
171
  try {
158
172
  const res = await app.inject({
@@ -83,13 +83,15 @@ CompiledCatalog {
83
83
  }
84
84
  ```
85
85
 
86
+ `CompiledType`, type aliases, and operations may include optional `doc` fields populated from WSDL/XSD documentation nodes. The catalog also carries optional `wsdlDocs` arrays for WSDL bindings, messages, parts, services, and ports. Client emitters consume operation and type docs to generate comments in `types.ts`, `operations.ts`, and `client.ts`. OpenAPI emitters consume the same fields for schema/property descriptions and operation summary and description values.
87
+
86
88
  Data flow through the pipeline:
87
89
 
88
90
  1. schemaCompiler produces CompiledCatalog from WSDL XML
89
91
  2. generateCatalog serializes it to JSON
90
92
  3. Client generators read types[] for TypeScript emission
91
93
  4. OpenAPI generator reads types[] and operations[] for spec generation
92
- 5. Gateway generator reads the OpenAPI spec (not the catalog directly)
94
+ 5. Gateway generator reads the OpenAPI spec, then enriches operation metadata from catalog operation docs when available
93
95
 
94
96
  ## Extension Points
95
97
 
package/docs/concepts.md CHANGED
@@ -67,6 +67,18 @@ 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, OpenAPI, gateway, and generated-test emitters and do not change runtime behavior.
71
+
72
+ The catalog also stores optional `wsdlDocs` metadata for selected WSDL nodes:
73
+
74
+ - `bindings[]`
75
+ - `messages[]`
76
+ - `messages[].parts[]`
77
+ - `services[]`
78
+ - `services[].ports[]`
79
+
80
+ OpenAPI uses operation docs for both `description` and default `summary` values. `ops.json` keeps precedence when `summary` or `description` is explicitly provided.
81
+
70
82
  ### Catalog Locations by Command
71
83
 
72
84
  | Command | Location |
@@ -73,6 +73,36 @@ 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
+ - Operation summaries default to the first sentence of `wsdl:documentation`
102
+ - `--openapi-ops-file` `description` overrides operation documentation when provided
103
+ - `--openapi-ops-file` `summary` overrides the default summary when provided
104
+ - Schema and property descriptions come from `xs:annotation/xs:documentation`
105
+
76
106
  ## Gateway Route Handlers
77
107
 
78
108
  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 +129,10 @@ export async function registerRoute_v1_weather_getcityforecastbyzip(fastify: Fas
99
129
 
100
130
  Key features of the generated handlers:
101
131
 
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
132
+ - `Body: T` generic: Fastify infers `request.body` type from the route generic, enabling IDE autocomplete and compile-time checks
133
+ - JSON Schema validation: the `schema` import provides Fastify with request/response validation at runtime, before the handler runs
134
+ - Envelope wrapping: `buildSuccessEnvelope()` wraps the raw SOAP response in the standard `{ status, message, data, error }` envelope
135
+ - Route file header comments include propagated operation summary and description when present
105
136
 
106
137
  See [Gateway Guide](gateway-guide.md) for the full architecture and [CLI Reference](cli-reference.md) for generation flags.
107
138
 
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 `wsdlDocs`, generated TS comments, OpenAPI summary and description precedence, and gateway route comment propagation
43
44
 
44
45
  ### Writing Unit Tests
45
46
 
@@ -78,6 +79,7 @@ Always review the diff before committing updated snapshots.
78
79
  - OpenAPI: `openapi.json`
79
80
  - Gateway core: `plugin.ts`, `routes.ts`, `schemas.ts`, `runtime.ts`, `_typecheck.ts`
80
81
  - Gateway routes: one handler per WSDL operation
82
+ - Gateway route comments: propagated summary and description metadata
81
83
  - Gateway schemas: all model and operation JSON schema files
82
84
  - File inventory: complete listing of generated files
83
85
 
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.14.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": {