@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 +2 -1
- package/dist/client/generateClient.d.ts.map +1 -1
- package/dist/client/generateClient.js +9 -1
- package/dist/client/generateOperations.d.ts.map +1 -1
- package/dist/client/generateOperations.js +11 -1
- package/dist/client/generateTypes.d.ts.map +1 -1
- package/dist/client/generateTypes.js +49 -6
- package/dist/compiler/schemaCompiler.d.ts +39 -0
- package/dist/compiler/schemaCompiler.d.ts.map +1 -1
- package/dist/compiler/schemaCompiler.js +191 -14
- package/dist/gateway/generateGateway.d.ts.map +1 -1
- package/dist/gateway/generateGateway.js +4 -0
- package/dist/gateway/generators.d.ts +2 -0
- package/dist/gateway/generators.d.ts.map +1 -1
- package/dist/gateway/generators.js +35 -2
- package/dist/gateway/helpers.d.ts +5 -0
- package/dist/gateway/helpers.d.ts.map +1 -1
- package/dist/gateway/helpers.js +21 -0
- package/dist/openapi/generatePaths.d.ts.map +1 -1
- package/dist/openapi/generatePaths.js +19 -2
- package/dist/openapi/generateSchemas.d.ts.map +1 -1
- package/dist/openapi/generateSchemas.js +29 -5
- package/dist/test/generators.d.ts.map +1 -1
- package/dist/test/generators.js +15 -1
- package/docs/architecture.md +3 -1
- package/docs/concepts.md +12 -0
- package/docs/generated-code.md +34 -3
- package/docs/testing.md +11 -9
- package/package.json +7 -7
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
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 = {
|
|
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({
|
|
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({
|
|
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,
|
|
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":"AAcA,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,eAAe,EAAyE,MAAM,cAAc,CAAC;AAG3I;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6IAA6I;IAC7I,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;
|
|
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 +=
|
|
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":"AAAA;;;;;;;;;;;GAWG;AAIH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAClC,CAAC;CACH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAqBxF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,GAAG,EACX,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,OAAO,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,GAAG,CA4GL;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,CAcxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,GAAG,CAiB3E;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,aAAa,CAAC,EAAE,GAAG,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,GAAG,EACb,SAAS,EAAE,GAAG,EACd,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,sBAAsB,CAmFxB;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/gateway/helpers.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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;
|
|
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 {
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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;
|
|
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"}
|
package/dist/test/generators.js
CHANGED
|
@@ -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
|
-
|
|
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({
|
package/docs/architecture.md
CHANGED
|
@@ -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
|
|
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 |
|
package/docs/generated-code.md
CHANGED
|
@@ -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
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
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.
|
|
12
|
-
2.
|
|
13
|
-
3.
|
|
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
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
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.
|
|
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.
|
|
79
|
+
"@types/node": "^25.3.3",
|
|
80
80
|
"@types/yargs": "^17.0.35",
|
|
81
|
-
"fastify": "^5.7.
|
|
81
|
+
"fastify": "^5.7.4",
|
|
82
82
|
"fastify-plugin": "^5.1.0",
|
|
83
|
-
"rimraf": "^6.1.
|
|
83
|
+
"rimraf": "^6.1.3",
|
|
84
84
|
"tsx": "^4.21.0",
|
|
85
|
-
"typescript": "^5.9.
|
|
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.
|
|
90
|
+
"fast-xml-parser": "^5.4.2",
|
|
91
91
|
"js-yaml": "^4.1.1",
|
|
92
|
-
"soap": "^1.
|
|
92
|
+
"soap": "^1.7.1",
|
|
93
93
|
"yargs": "^18.0.0"
|
|
94
94
|
},
|
|
95
95
|
"funding": {
|