Skip to content

Commit 98a9011

Browse files
authored
Merge pull request #103 from doubleaxe/master
feat: new parameter --useWsdlTypeNames to generate interface names from wsdl type names
2 parents 16ff043 + db94bcc commit 98a9011

File tree

7 files changed

+360
-12
lines changed

7 files changed

+360
-12
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ Options:
6363
'PascalCase') [string]
6464
--caseInsensitiveNames Parse WSDL definitions case-insensitively
6565
[boolean]
66+
--useWsdlTypeNames Use wsdl schema type names instead of
67+
parameter names for generated interface
68+
names [boolean]
6669
--maxRecursiveDefinitionName Maximum count of definitions with the same
6770
name but increased suffix. Will throw an
6871
error if exceeded. [number]

src/cli.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const conf = yargs(process.argv.slice(2))
3939
type: "boolean",
4040
description: "Parse WSDL definitions case-insensitively",
4141
})
42+
.option("useWsdlTypeNames", {
43+
type: "boolean",
44+
description: "Use wsdl schema type names instead of parameter names for generated interface names",
45+
})
4246
.option("maxRecursiveDefinitionName", {
4347
type: "number",
4448
description:
@@ -59,7 +63,8 @@ const conf = yargs(process.argv.slice(2))
5963
.option("no-color", {
6064
type: "boolean",
6165
description: "Logs without colors",
62-
}).parseSync();
66+
})
67+
.parseSync();
6368

6469
// Logger section
6570

@@ -123,6 +128,10 @@ if (conf.caseInsensitiveNames) {
123128
options.caseInsensitiveNames = conf.caseInsensitiveNames;
124129
}
125130

131+
if (conf.useWsdlTypeNames) {
132+
options.useWsdlTypeNames = conf.useWsdlTypeNames;
133+
}
134+
126135
if (conf.esm) {
127136
options.esm = conf.esm;
128137
}

src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ export interface Options {
3232
* @default false
3333
*/
3434
caseInsensitiveNames: boolean;
35+
/**
36+
* Use wsdl schema type names instead of parameter names for generated interface names
37+
* @default false
38+
*/
39+
useWsdlTypeNames: boolean;
3540
/**
3641
* Maximum count of definition's with same name but increased suffix. Will throw an error if exceed
3742
* @default 64
@@ -44,7 +49,7 @@ export interface Options {
4449
/**
4550
* Generate imports with .js suffix
4651
*/
47-
esm: boolean
52+
esm: boolean;
4853
/**
4954
* Print verbose logs
5055
* @default false
@@ -67,6 +72,7 @@ export const defaultOptions: Options = {
6772
modelNamePreffix: "",
6873
modelNameSuffix: "",
6974
caseInsensitiveNames: false,
75+
useWsdlTypeNames: false,
7076
maxRecursiveDefinitionName: 64,
7177
modelPropertyNaming: null,
7278
esm: false,

src/parser.ts

Lines changed: 102 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
import * as path from "path";
2-
import { ComplexTypeElement } from "soap/lib/wsdl/elements";
2+
import {
3+
AllElement,
4+
ChoiceElement,
5+
ComplexContentElement,
6+
ComplexTypeElement,
7+
DefinitionsElement,
8+
ElementElement,
9+
ExtensionElement,
10+
SequenceElement,
11+
SimpleContentElement,
12+
SimpleTypeElement,
13+
} from "soap/lib/wsdl/elements";
14+
import { splitQName } from "soap/lib/utils";
315
import { open_wsdl } from "soap/lib/wsdl/index";
416
import { Definition, Method, ParsedWsdl, Port, Service } from "./models/parsed-wsdl";
517
import { changeCase } from "./utils/change-case";
@@ -12,13 +24,15 @@ interface ParserOptions {
1224
modelNameSuffix: string;
1325
maxRecursiveDefinitionName: number;
1426
caseInsensitiveNames: boolean;
27+
useWsdlTypeNames: boolean;
1528
}
1629

1730
const defaultOptions: ParserOptions = {
1831
modelNamePreffix: "",
1932
modelNameSuffix: "",
2033
maxRecursiveDefinitionName: 64,
2134
caseInsensitiveNames: false,
35+
useWsdlTypeNames: false,
2236
};
2337

2438
type VisitedDefinition = {
@@ -53,6 +67,60 @@ function toPrimitiveType(type: string): string {
5367
return NODE_SOAP_PARSED_TYPES[type] || "string";
5468
}
5569

70+
type ElementSchema = ElementElement | ComplexTypeElement | SimpleTypeElement;
71+
72+
function findElementSchemaType(definitions: DefinitionsElement, element: ElementSchema) {
73+
if (!("$type" in element) && !("$ref" in element)) return element;
74+
const type = element.$type || element.$ref;
75+
if (!type) return element;
76+
const { prefix, name: localName } = splitQName(type);
77+
const ns = element.schemaXmlns[prefix] ?? definitions.xmlns[prefix] ?? definitions.xmlns[element.targetNSAlias];
78+
const schema = definitions.schemas[ns];
79+
if (!schema) return element;
80+
const typeElement = schema.complexTypes[localName] ?? schema.types[localName];
81+
return typeElement;
82+
}
83+
84+
function findPropSchemaType(
85+
definitions: DefinitionsElement,
86+
parentElement: ElementSchema | undefined,
87+
propName: string
88+
): ElementSchema | undefined {
89+
if (!parentElement?.children) return undefined;
90+
for (const child of parentElement.children) {
91+
if (
92+
child instanceof ChoiceElement ||
93+
child instanceof SequenceElement ||
94+
child instanceof AllElement ||
95+
child instanceof SimpleContentElement ||
96+
child instanceof ComplexContentElement ||
97+
child instanceof ExtensionElement
98+
) {
99+
return findPropSchemaType(definitions, child, propName);
100+
}
101+
if (child.$name === propName) {
102+
if (
103+
child instanceof ElementElement ||
104+
child instanceof ComplexTypeElement ||
105+
child instanceof SimpleTypeElement
106+
) {
107+
return findElementSchemaType(definitions, child);
108+
}
109+
}
110+
}
111+
return undefined;
112+
}
113+
114+
function getNameFromSchema(element: ElementSchema | undefined) {
115+
if (!element) return undefined;
116+
if ("$type" in element || "$ref" in element) {
117+
const type = element.$type || element.$ref;
118+
const { name: localName } = splitQName(type);
119+
return localName;
120+
}
121+
return element.$name;
122+
}
123+
56124
/**
57125
* parse definition
58126
* @param parsedWsdl context of parsed wsdl
@@ -67,7 +135,9 @@ function parseDefinition(
67135
name: string,
68136
defParts: { [propNameType: string]: any },
69137
stack: string[],
70-
visitedDefs: Array<VisitedDefinition>
138+
visitedDefs: Array<VisitedDefinition>,
139+
definitions: DefinitionsElement,
140+
schema: ElementSchema | undefined
71141
): Definition {
72142
const defName = changeCase(name, { pascalCase: true });
73143

@@ -146,13 +216,17 @@ function parseDefinition(
146216
});
147217
} else {
148218
try {
219+
const propSchema = findPropSchemaType(definitions, schema, stripedPropName);
220+
const guessPropName = getNameFromSchema(propSchema) ?? stripedPropName;
149221
const subDefinition = parseDefinition(
150222
parsedWsdl,
151223
options,
152-
stripedPropName,
224+
guessPropName,
153225
type,
154226
[...stack, propName],
155-
visitedDefs
227+
visitedDefs,
228+
definitions,
229+
propSchema
156230
);
157231
definition.properties.push({
158232
kind: "REFERENCE",
@@ -205,13 +279,17 @@ function parseDefinition(
205279
});
206280
} else {
207281
try {
282+
const propSchema = findPropSchemaType(definitions, schema, propName);
283+
const guessPropName = getNameFromSchema(propSchema) ?? propName;
208284
const subDefinition = parseDefinition(
209285
parsedWsdl,
210286
options,
211-
propName,
287+
guessPropName,
212288
type,
213289
[...stack, propName],
214-
visitedDefs
290+
visitedDefs,
291+
definitions,
292+
propSchema
215293
);
216294
definition.properties.push({
217295
kind: "REFERENCE",
@@ -300,6 +378,9 @@ export async function parseWsdl(wsdlPath: string, options: Partial<ParserOptions
300378
const type = parsedWsdl.findDefinition(
301379
inputMessage.element.$type ?? inputMessage.element.$name
302380
);
381+
const schema = mergedOptions.useWsdlTypeNames
382+
? findElementSchemaType(wsdl.definitions, inputMessage.element)
383+
: undefined;
303384
inputDefinition =
304385
type ??
305386
parseDefinition(
@@ -308,7 +389,9 @@ export async function parseWsdl(wsdlPath: string, options: Partial<ParserOptions
308389
typeName,
309390
inputMessage.parts,
310391
[typeName],
311-
visitedDefinitions
392+
visitedDefinitions,
393+
wsdl.definitions,
394+
schema
312395
);
313396
} else if (inputMessage.parts) {
314397
const type = parsedWsdl.findDefinition(requestParamName);
@@ -320,7 +403,9 @@ export async function parseWsdl(wsdlPath: string, options: Partial<ParserOptions
320403
requestParamName,
321404
inputMessage.parts,
322405
[requestParamName],
323-
visitedDefinitions
406+
visitedDefinitions,
407+
wsdl.definitions,
408+
undefined
324409
);
325410
} else {
326411
Logger.debug(
@@ -340,6 +425,9 @@ export async function parseWsdl(wsdlPath: string, options: Partial<ParserOptions
340425
// TODO: if `$type` not defined, inline type into function declartion (do not create definition file) - wsimport
341426
const typeName = outputMessage.element.$type ?? outputMessage.element.$name;
342427
const type = parsedWsdl.findDefinition(typeName);
428+
const schema = mergedOptions.useWsdlTypeNames
429+
? findElementSchemaType(wsdl.definitions, outputMessage.element)
430+
: undefined;
343431
outputDefinition =
344432
type ??
345433
parseDefinition(
@@ -348,7 +436,9 @@ export async function parseWsdl(wsdlPath: string, options: Partial<ParserOptions
348436
typeName,
349437
outputMessage.parts,
350438
[typeName],
351-
visitedDefinitions
439+
visitedDefinitions,
440+
wsdl.definitions,
441+
schema
352442
);
353443
} else {
354444
const type = parsedWsdl.findDefinition(responseParamName);
@@ -360,7 +450,9 @@ export async function parseWsdl(wsdlPath: string, options: Partial<ParserOptions
360450
responseParamName,
361451
outputMessage.parts,
362452
[responseParamName],
363-
visitedDefinitions
453+
visitedDefinitions,
454+
wsdl.definitions,
455+
undefined
364456
);
365457
}
366458
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import test from "tape";
2+
import { existsSync, rmdirSync } from "fs";
3+
import { parseAndGenerate } from "../../src";
4+
import { Logger } from "../../src/utils/logger";
5+
import { typecheck } from "../utils/tsc";
6+
7+
const target = "jaxws_generated_service";
8+
9+
test(target, async (t) => {
10+
Logger.disabled();
11+
12+
const input = `./test/resources/${target}/TestService.wsdl`;
13+
const outdir = "./test/generated/jaxws_generated_service";
14+
15+
t.test(`${target} - generate wsdl client with default options`, async (t) => {
16+
rmdirSync(outdir, { recursive: true });
17+
await parseAndGenerate(input, outdir);
18+
t.end();
19+
});
20+
21+
t.test(`${target} - check definitions`, async (t) => {
22+
t.equal(existsSync(`${outdir}/testservice/definitions/Request.ts`), true);
23+
t.equal(existsSync(`${outdir}/testservice/definitions/Request1.ts`), true);
24+
t.equal(existsSync(`${outdir}/testservice/definitions/Return.ts`), true);
25+
t.equal(existsSync(`${outdir}/testservice/definitions/TnsaddNumber.ts`), true);
26+
t.equal(existsSync(`${outdir}/testservice/definitions/TnsaddNumberResponse.ts`), true);
27+
t.end();
28+
});
29+
30+
t.test(`${target} - compile`, async (t) => {
31+
await typecheck(`${outdir}/testservice/index.ts`);
32+
t.end();
33+
});
34+
35+
t.test(`${target} - generate wsdl client with useWsdlTypeNames`, async (t) => {
36+
rmdirSync(outdir, { recursive: true });
37+
await parseAndGenerate(input, outdir, { useWsdlTypeNames: true });
38+
t.end();
39+
});
40+
41+
t.test(`${target} - check useWsdlTypeNames definitions`, async (t) => {
42+
t.equal(existsSync(`${outdir}/testservice/definitions/ComplextRecursiveResult.ts`), true);
43+
t.equal(existsSync(`${outdir}/testservice/definitions/ComplextRequest.ts`), true);
44+
t.equal(existsSync(`${outdir}/testservice/definitions/SimpleRequest.ts`), true);
45+
t.equal(existsSync(`${outdir}/testservice/definitions/TnsaddNumber.ts`), true);
46+
t.equal(existsSync(`${outdir}/testservice/definitions/TnsaddNumberResponse.ts`), true);
47+
t.end();
48+
});
49+
50+
t.test(`${target} - compile useWsdlTypeNames`, async (t) => {
51+
await typecheck(`${outdir}/testservice/index.ts`);
52+
t.end();
53+
});
54+
});

0 commit comments

Comments
 (0)