@techspokes/typescript-wsdl-client 1.0.7 → 1.1.2
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 +5 -0
- package/dist/app/generateApp.d.ts.map +1 -1
- package/dist/app/generateApp.js +5 -4
- package/dist/client/generateClient.d.ts +1 -0
- package/dist/client/generateClient.d.ts.map +1 -1
- package/dist/client/generateClient.js +13 -18
- package/dist/client/generateOperations.d.ts +1 -0
- package/dist/client/generateOperations.d.ts.map +1 -1
- package/dist/client/generateOperations.js +3 -8
- package/dist/client/generateTypes.d.ts +1 -0
- package/dist/client/generateTypes.d.ts.map +1 -1
- package/dist/client/generateTypes.js +3 -8
- package/dist/client/generateUtils.d.ts +1 -0
- package/dist/client/generateUtils.d.ts.map +1 -1
- package/dist/client/generateUtils.js +13 -9
- package/dist/compiler/schemaCompiler.d.ts.map +1 -1
- package/dist/compiler/schemaCompiler.js +18 -7
- package/dist/gateway/generators.d.ts.map +1 -1
- package/dist/gateway/generators.js +9 -8
- package/dist/generation/preamble.d.ts +17 -0
- package/dist/generation/preamble.d.ts.map +1 -0
- package/dist/generation/preamble.js +73 -0
- package/dist/generation/writeGeneratedSource.d.ts +11 -0
- package/dist/generation/writeGeneratedSource.d.ts.map +1 -0
- package/dist/generation/writeGeneratedSource.js +24 -0
- package/dist/test/generateTests.d.ts.map +1 -1
- package/dist/test/generateTests.js +12 -11
- package/docs/api-reference.md +2 -0
- package/docs/architecture.md +10 -0
- package/docs/cli-reference.md +2 -0
- package/docs/file-naming-and-path-organization.md +6 -0
- package/docs/generated-code.md +100 -0
- package/docs/output-anatomy.md +4 -0
- package/docs/releases/README.md +13 -5
- package/docs/releases/v1.1.0.md +42 -0
- package/docs/releases/v1.1.1.md +44 -0
- package/docs/releases/v1.1.2.md +42 -0
- package/docs/supported-patterns.md +5 -0
- package/docs/testing.md +2 -0
- package/docs/troubleshooting.md +8 -0
- package/package.json +10 -5
- package/src/generation/preambles/app/typescript.preamble +3 -0
- package/src/generation/preambles/test/typescript.preamble +3 -0
- package/src/generation/preambles/typescript.preamble +3 -0
package/README.md
CHANGED
|
@@ -55,6 +55,8 @@ npx wsdl-tsc client \
|
|
|
55
55
|
|
|
56
56
|
This produces `types.ts`, `client.ts`, `operations.ts`, and `utils.ts` in the output directory.
|
|
57
57
|
|
|
58
|
+
Generated TypeScript includes an ESLint suppression preamble. See [generated-code linting guidance](docs/generated-code.md#generated-preambles-and-eslint) for strict policies, path exclusions, and editable scaffold ownership.
|
|
59
|
+
|
|
58
60
|
### Generate an OpenAPI spec
|
|
59
61
|
|
|
60
62
|
```bash
|
|
@@ -226,6 +228,9 @@ See [CLI Reference](docs/cli-reference.md) for all flags and examples.
|
|
|
226
228
|
| [Production Guide](docs/production.md) | CI/CD, validation, logging |
|
|
227
229
|
| [Troubleshooting](docs/troubleshooting.md) | Common issues and debugging |
|
|
228
230
|
| [Release Notes](docs/releases/README.md) | Per-version GitHub release notes used by the draft release workflow |
|
|
231
|
+
| [v1.1.2 Release Notes](docs/releases/v1.1.2.md) | Sequence occurrence bounds and singleton SOAP response normalization |
|
|
232
|
+
| [v1.1.1 Release Notes](docs/releases/v1.1.1.md) | Wrapping sequence occurrence bounds and generated array contracts |
|
|
233
|
+
| [v1.1.0 Release Notes](docs/releases/v1.1.0.md) | Automatic generated TypeScript preambles and consumer lint guidance |
|
|
229
234
|
|
|
230
235
|
### Extend
|
|
231
236
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateApp.d.ts","sourceRoot":"","sources":["../../src/app/generateApp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generateApp.d.ts","sourceRoot":"","sources":["../../src/app/generateApp.ts"],"names":[],"mappings":"AAiCA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAuqBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDzE"}
|
package/dist/app/generateApp.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* - Skip-if-exists protection for scaffold files (override with force option)
|
|
23
23
|
*/
|
|
24
24
|
import fs from "node:fs";
|
|
25
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
25
26
|
import path from "node:path";
|
|
26
27
|
import { deriveClientName } from "../util/tools.js";
|
|
27
28
|
import { info, success } from "../util/cli.js";
|
|
@@ -306,7 +307,7 @@ main().catch((err) => {
|
|
|
306
307
|
process.exit(1);
|
|
307
308
|
});
|
|
308
309
|
`;
|
|
309
|
-
|
|
310
|
+
writeGeneratedSource(filePath, content, "app");
|
|
310
311
|
}
|
|
311
312
|
/**
|
|
312
313
|
* Generates config.ts file
|
|
@@ -397,7 +398,7 @@ export function loadConfig(): AppConfig {
|
|
|
397
398
|
};
|
|
398
399
|
}
|
|
399
400
|
`;
|
|
400
|
-
|
|
401
|
+
writeGeneratedSource(filePath, content, "app");
|
|
401
402
|
}
|
|
402
403
|
function loadOptionalSecurityConfig(filePath) {
|
|
403
404
|
return filePath ? loadSecurityConfigFile(filePath) : undefined;
|
|
@@ -503,7 +504,7 @@ function generateSecurityFile(appDir, opts, force) {
|
|
|
503
504
|
return;
|
|
504
505
|
const upstreamJson = JSON.stringify(securityCfg?.upstream ?? {}, null, 2);
|
|
505
506
|
const content = loadRuntimeTemplate("appSecurity.tpl.txt").replace("__UPSTREAM_JSON__", upstreamJson);
|
|
506
|
-
|
|
507
|
+
writeGeneratedSource(filePath, content, "app");
|
|
507
508
|
}
|
|
508
509
|
/**
|
|
509
510
|
* Generates package.json file (skipped if already exists)
|
|
@@ -528,7 +529,7 @@ function generatePackageJson(appDir, force) {
|
|
|
528
529
|
fastify: "^5.12.5",
|
|
529
530
|
"fastify-plugin": "^6.0.0",
|
|
530
531
|
saxes: "^6.0.0",
|
|
531
|
-
soap: "^1.13.
|
|
532
|
+
soap: "^1.13.1",
|
|
532
533
|
},
|
|
533
534
|
devDependencies: {
|
|
534
535
|
"@types/node": "^26.6.2",
|
|
@@ -15,6 +15,7 @@ import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
|
15
15
|
*
|
|
16
16
|
* @param {string} outFile - Path to the output TypeScript file
|
|
17
17
|
* @param {CompiledCatalog} compiled - The compiled WSDL catalog
|
|
18
|
+
* @throws {Error} If a packaged preamble cannot be loaded or a TypeScript file cannot be written.
|
|
18
19
|
*/
|
|
19
20
|
export declare function generateClient(outFile: string, compiled: CompiledCatalog): void;
|
|
20
21
|
//# sourceMappingURL=generateClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateClient.d.ts","sourceRoot":"","sources":["../../src/client/generateClient.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAKnE
|
|
1
|
+
{"version":3,"file":"generateClient.d.ts","sourceRoot":"","sources":["../../src/client/generateClient.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAKnE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAkaxE"}
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* - Support for custom attribute handling
|
|
13
13
|
* - Consistent error handling and client configuration
|
|
14
14
|
*/
|
|
15
|
-
import
|
|
15
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import { deriveClientName, pascal, pascalToSnakeCase } from "../util/tools.js";
|
|
18
|
-
import {
|
|
18
|
+
import { warn } from "../util/cli.js";
|
|
19
19
|
import { loadRuntimeSource } from "../util/runtimeSource.js";
|
|
20
20
|
/**
|
|
21
21
|
* Generates a TypeScript SOAP client class from a compiled WSDL catalog
|
|
@@ -33,6 +33,7 @@ import { loadRuntimeSource } from "../util/runtimeSource.js";
|
|
|
33
33
|
*
|
|
34
34
|
* @param {string} outFile - Path to the output TypeScript file
|
|
35
35
|
* @param {CompiledCatalog} compiled - The compiled WSDL catalog
|
|
36
|
+
* @throws {Error} If a packaged preamble cannot be loaded or a TypeScript file cannot be written.
|
|
36
37
|
*/
|
|
37
38
|
export function generateClient(outFile, compiled) {
|
|
38
39
|
const isValidIdent = (name) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
@@ -179,6 +180,7 @@ export type ${clientName}Response<ResponseType, HeadersType = Record<string, unk
|
|
|
179
180
|
* @property dataTypes - Metadata for data types used in serialization/deserialization.
|
|
180
181
|
* @property dataTypes.Attributes - Maps type names to lists of property names that should be treated as XML attributes.
|
|
181
182
|
* @property dataTypes.ChildrenTypes - Maps type names to their child element types for recursive processing.
|
|
183
|
+
* @property dataTypes.RepeatedElements - Identifies child properties that must retain their array shape for singleton responses.
|
|
182
184
|
*
|
|
183
185
|
*
|
|
184
186
|
* @note Have fun with the generated client! If TechSpokes made your day (or a week),
|
|
@@ -401,6 +403,7 @@ ${methodsBody}
|
|
|
401
403
|
|
|
402
404
|
// Get child type mapping for recursive processing with correct types
|
|
403
405
|
const childrenTypes: Readonly<Record<string, string>> = (typeName && this.dataTypes?.ChildrenTypes?.[typeName]) || {};
|
|
406
|
+
const repeatedElements: readonly string[] = (typeName && this.dataTypes?.RepeatedElements?.[typeName]) || [];
|
|
404
407
|
const result: any = {};
|
|
405
408
|
|
|
406
409
|
// Preserve text content for mixed XML elements
|
|
@@ -424,31 +427,23 @@ ${methodsBody}
|
|
|
424
427
|
}
|
|
425
428
|
// Recursively convert child elements with their specific type info
|
|
426
429
|
const childType: string | undefined = childrenTypes[k];
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
+
// node-soap can return a scalar when repetition is declared on a wrapping sequence (#141).
|
|
431
|
+
const value = v != null && !Array.isArray(v) && repeatedElements.includes(k) ? [v] : v;
|
|
432
|
+
result[k] = Array.isArray(value)
|
|
433
|
+
? value.map(node => this.fromSoapResult(node, childType))
|
|
434
|
+
: this.fromSoapResult(value, childType);
|
|
430
435
|
}
|
|
431
436
|
|
|
432
437
|
return result;
|
|
433
438
|
}${streamMethodsBlock}
|
|
434
439
|
}
|
|
435
440
|
`;
|
|
436
|
-
|
|
437
|
-
fs.writeFileSync(outFile, classTemplate.replace(`// noinspection JSAnnotator\n\n`, ''), "utf8");
|
|
438
|
-
}
|
|
439
|
-
catch (e) {
|
|
440
|
-
error(`Failed to write client to ${outFile}`);
|
|
441
|
-
}
|
|
441
|
+
writeGeneratedSource(outFile, classTemplate.replace(`// noinspection JSAnnotator\n\n`, ''), "client");
|
|
442
442
|
// If any operation opted into streaming, drop the runtime XML parser
|
|
443
443
|
// alongside the client so the generated class can import it without
|
|
444
444
|
// depending on a `@techspokes/typescript-wsdl-client/runtime/...` subpath.
|
|
445
445
|
if (anyStream) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
fs.writeFileSync(streamXmlOut, loadRuntimeSource("streamXml.ts"), "utf-8");
|
|
449
|
-
}
|
|
450
|
-
catch (e) {
|
|
451
|
-
error(`Failed to emit streamXml.ts next to ${outFile}: ${e instanceof Error ? e.message : String(e)}`);
|
|
452
|
-
}
|
|
446
|
+
const streamXmlOut = path.join(path.dirname(outFile), "streamXml.ts");
|
|
447
|
+
writeGeneratedSource(streamXmlOut, loadRuntimeSource("streamXml.ts"), "client/stream");
|
|
453
448
|
}
|
|
454
449
|
}
|
|
@@ -8,6 +8,7 @@ import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
|
8
8
|
*
|
|
9
9
|
* @param outFile - Path to the output TypeScript file
|
|
10
10
|
* @param compiled - The compiled WSDL catalog
|
|
11
|
+
* @throws {Error} If a packaged preamble cannot be loaded or the TypeScript file cannot be written.
|
|
11
12
|
*/
|
|
12
13
|
export declare function generateOperations(outFile: string, compiled: CompiledCatalog): void;
|
|
13
14
|
//# sourceMappingURL=generateOperations.d.ts.map
|
|
@@ -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;
|
|
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;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CA0FnF"}
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* This standalone interface enables mocking and testing without importing
|
|
6
6
|
* the concrete SOAP client class or its runtime dependencies.
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
8
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
9
9
|
import { deriveClientName, pascal } from "../util/tools.js";
|
|
10
|
-
import { error } from "../util/cli.js";
|
|
11
10
|
import { loadRuntimeSource } from "../util/runtimeSource.js";
|
|
12
11
|
/**
|
|
13
12
|
* Generates an operations.ts file with a fully-typed interface for all SOAP operations
|
|
@@ -18,6 +17,7 @@ import { loadRuntimeSource } from "../util/runtimeSource.js";
|
|
|
18
17
|
*
|
|
19
18
|
* @param outFile - Path to the output TypeScript file
|
|
20
19
|
* @param compiled - The compiled WSDL catalog
|
|
20
|
+
* @throws {Error} If a packaged preamble cannot be loaded or the TypeScript file cannot be written.
|
|
21
21
|
*/
|
|
22
22
|
export function generateOperations(outFile, compiled) {
|
|
23
23
|
const ext = compiled.options.imports ?? "bare";
|
|
@@ -95,10 +95,5 @@ ${typeImport}${streamHelper}/**
|
|
|
95
95
|
*/
|
|
96
96
|
export interface ${clientName}Operations {
|
|
97
97
|
${methods.join("\n")}}\n`;
|
|
98
|
-
|
|
99
|
-
fs.writeFileSync(outFile, content, "utf8");
|
|
100
|
-
}
|
|
101
|
-
catch (e) {
|
|
102
|
-
error(`Failed to write operations interface to ${outFile}`);
|
|
103
|
-
}
|
|
98
|
+
writeGeneratedSource(outFile, content, "client");
|
|
104
99
|
}
|
|
@@ -17,6 +17,7 @@ import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
|
17
17
|
*
|
|
18
18
|
* @param {string} outFile - Path to the output TypeScript file
|
|
19
19
|
* @param {CompiledCatalog} compiled - The compiled WSDL catalog
|
|
20
|
+
* @throws {Error} If a packaged preamble cannot be loaded or the TypeScript file cannot be written.
|
|
20
21
|
*/
|
|
21
22
|
export declare function generateTypes(outFile: string, compiled: CompiledCatalog): void;
|
|
22
23
|
//# sourceMappingURL=generateTypes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateTypes.d.ts","sourceRoot":"","sources":["../../src/client/generateTypes.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAA0D,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"generateTypes.d.ts","sourceRoot":"","sources":["../../src/client/generateTypes.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAA0D,MAAM,+BAA+B,CAAC;AAG5H;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAkSvE"}
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
* - Consistent property ordering and interface structuring
|
|
13
13
|
* - Optional/required markers based on XML schema requirements
|
|
14
14
|
*/
|
|
15
|
-
import
|
|
16
|
-
import { error } from "../util/cli.js";
|
|
15
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
17
16
|
import { hasAttributeWildcards, wildcardAttributeBagName } from "../util/attributeWildcards.js";
|
|
18
17
|
/**
|
|
19
18
|
* Generates TypeScript interfaces and type aliases from a compiled WSDL catalog
|
|
@@ -33,6 +32,7 @@ import { hasAttributeWildcards, wildcardAttributeBagName } from "../util/attribu
|
|
|
33
32
|
*
|
|
34
33
|
* @param {string} outFile - Path to the output TypeScript file
|
|
35
34
|
* @param {CompiledCatalog} compiled - The compiled WSDL catalog
|
|
35
|
+
* @throws {Error} If a packaged preamble cannot be loaded or the TypeScript file cannot be written.
|
|
36
36
|
*/
|
|
37
37
|
export function generateTypes(outFile, compiled) {
|
|
38
38
|
const lines = [];
|
|
@@ -308,10 +308,5 @@ export function generateTypes(outFile, compiled) {
|
|
|
308
308
|
lines.push("}");
|
|
309
309
|
lines.push("");
|
|
310
310
|
}
|
|
311
|
-
|
|
312
|
-
fs.writeFileSync(outFile, lines.join("\n"), "utf8");
|
|
313
|
-
}
|
|
314
|
-
catch (e) {
|
|
315
|
-
error(`Failed to write types to ${outFile}: ${e instanceof Error ? e.message : String(e)}`);
|
|
316
|
-
}
|
|
311
|
+
writeGeneratedSource(outFile, lines.join("\n"), "client");
|
|
317
312
|
}
|
|
@@ -16,6 +16,7 @@ import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
|
16
16
|
* @param {string} outFile - Path to the output TypeScript file
|
|
17
17
|
* @param {CompiledCatalog} compiled - The compiled WSDL catalog containing metadata
|
|
18
18
|
* @throws {Error} If metadata is missing or has an invalid structure
|
|
19
|
+
* @throws {Error} If a packaged preamble cannot be loaded or the TypeScript file cannot be written.
|
|
19
20
|
*/
|
|
20
21
|
export declare function generateUtils(outFile: string, compiled: CompiledCatalog): void;
|
|
21
22
|
//# sourceMappingURL=generateUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateUtils.d.ts","sourceRoot":"","sources":["../../src/client/generateUtils.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"generateUtils.d.ts","sourceRoot":"","sources":["../../src/client/generateUtils.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAGnE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,QAuCvE"}
|
|
@@ -10,9 +10,8 @@
|
|
|
10
10
|
* - A DataTypes interface defining the structure of the metadata
|
|
11
11
|
* - A constant containing the actual metadata mappings extracted from the compiled catalog
|
|
12
12
|
*/
|
|
13
|
-
import
|
|
13
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
14
14
|
import { deriveClientName, pascalToSnakeCase } from "../util/tools.js";
|
|
15
|
-
import { error } from "../util/cli.js";
|
|
16
15
|
/**
|
|
17
16
|
* Generates utility types and constants for XML serialization/deserialization
|
|
18
17
|
*
|
|
@@ -30,6 +29,7 @@ import { error } from "../util/cli.js";
|
|
|
30
29
|
* @param {string} outFile - Path to the output TypeScript file
|
|
31
30
|
* @param {CompiledCatalog} compiled - The compiled WSDL catalog containing metadata
|
|
32
31
|
* @throws {Error} If metadata is missing or has an invalid structure
|
|
32
|
+
* @throws {Error} If a packaged preamble cannot be loaded or the TypeScript file cannot be written.
|
|
33
33
|
*/
|
|
34
34
|
export function generateUtils(outFile, compiled) {
|
|
35
35
|
const clientName = deriveClientName(compiled);
|
|
@@ -41,7 +41,14 @@ export function generateUtils(outFile, compiled) {
|
|
|
41
41
|
if (typeof attrSpec !== "object" || typeof childType !== "object") {
|
|
42
42
|
throw new Error("Invalid metadata structure. Expected objects for Attributes and ChildrenTypes.");
|
|
43
43
|
}
|
|
44
|
-
const
|
|
44
|
+
const repeatedElements = Object.fromEntries(Object.entries(compiled.meta.propMeta ?? {}).sort(([a], [b]) => a.localeCompare(b)).map(([typeName, properties]) => [
|
|
45
|
+
typeName,
|
|
46
|
+
Object.keys(properties).filter(name => {
|
|
47
|
+
const max = properties[name]?.max;
|
|
48
|
+
return max === "unbounded" || (typeof max === "number" && max > 1);
|
|
49
|
+
}).sort(),
|
|
50
|
+
]));
|
|
51
|
+
const metas = JSON.stringify({ Attributes: attrSpec, ChildrenTypes: childType, RepeatedElements: repeatedElements }, null, 2);
|
|
45
52
|
const dataTypes = `/**
|
|
46
53
|
* ${clientName} WSDL data types for proper serialization/deserialization.
|
|
47
54
|
* Used to distinguish between XML attributes and elements during conversion.
|
|
@@ -51,13 +58,10 @@ export interface ${clientName}DataTypes {
|
|
|
51
58
|
Attributes: Record<string, readonly string[]>;
|
|
52
59
|
/** Maps type names to their child element types for recursive processing */
|
|
53
60
|
ChildrenTypes: Record<string, Readonly<Record<string, string>>>;
|
|
61
|
+
/** Maps type names to repeated child properties; optional for custom metadata compatibility. */
|
|
62
|
+
RepeatedElements?: Record<string, readonly string[]>;
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
export const ${clientConstant}_DATA_TYPES: ${clientName}DataTypes = ${metas} as const;\n`;
|
|
57
|
-
|
|
58
|
-
fs.writeFileSync(outFile, dataTypes, "utf8");
|
|
59
|
-
}
|
|
60
|
-
catch (e) {
|
|
61
|
-
error(`Failed to write utils to ${outFile}: ${e instanceof Error ? e.message : String(e)}`);
|
|
62
|
-
}
|
|
66
|
+
writeGeneratedSource(outFile, dataTypes, "client");
|
|
63
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaCompiler.d.ts","sourceRoot":"","sources":["../../src/compiler/schemaCompiler.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schemaCompiler.d.ts","sourceRoot":"","sources":["../../src/compiler/schemaCompiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -596,18 +596,29 @@ export function compileCatalog(cat, options, streamConfig) {
|
|
|
596
596
|
};
|
|
597
597
|
const collectParticles = (ownerTypeName, node) => {
|
|
598
598
|
const out = [];
|
|
599
|
-
|
|
600
|
-
const
|
|
601
|
-
|
|
599
|
+
const one = { min: 1, max: 1 };
|
|
600
|
+
const combine = (a, b) => ({
|
|
601
|
+
min: a.min * b.min,
|
|
602
|
+
max: a.max === "unbounded" || b.max === "unbounded" ? "unbounded" : a.max * b.max,
|
|
603
|
+
});
|
|
604
|
+
const recurse = (groupNode, inherited = one, inheritSequenceOccurs = true) => {
|
|
602
605
|
for (const e of getChildrenWithLocalName(groupNode, "element")) {
|
|
603
606
|
const particle = compileElementParticle(ownerTypeName, e);
|
|
604
|
-
if (particle)
|
|
605
|
-
|
|
607
|
+
if (!particle)
|
|
608
|
+
continue;
|
|
609
|
+
// @constraints Preserve disabled particles until the content model can represent their absence (#145).
|
|
610
|
+
out.push(particle.max === 0 ? particle : { ...particle, ...combine(inherited, particle) });
|
|
606
611
|
}
|
|
607
|
-
// recurse into nested compositor groups
|
|
608
612
|
for (const comp of ["sequence", "all", "choice"]) {
|
|
609
613
|
for (const sub of getChildrenWithLocalName(groupNode, comp)) {
|
|
610
|
-
|
|
614
|
+
const own = readOccurrence(sub);
|
|
615
|
+
if (inheritSequenceOccurs && comp === "sequence" && own.max !== 0) {
|
|
616
|
+
recurse(sub, combine(inherited, own), true);
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
// @constraints Choice, all, and disabled subtrees keep their previous flattened bounds (#145).
|
|
620
|
+
recurse(sub, one, false);
|
|
621
|
+
}
|
|
611
622
|
}
|
|
612
623
|
}
|
|
613
624
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* All emitters follow deterministic generation rules for diff-friendly output.
|
|
12
12
|
*/
|
|
13
13
|
import fs from "node:fs";
|
|
14
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
14
15
|
import path from "node:path";
|
|
15
16
|
import { flattenAllOf, measureSchemaRefComplexity, rewriteSchemaRefs, slugName, } from "./helpers.js";
|
|
16
17
|
import { detectArrayWrappers as detectArrayWrappersShared } from "../util/catalogMeta.js";
|
|
@@ -292,7 +293,7 @@ export function emitSchemasModule(outDir, modelsDir, versionSlug, serviceSlug) {
|
|
|
292
293
|
schemasTs += ` fastify.addSchema(s as any);\n`;
|
|
293
294
|
schemasTs += ` }\n`;
|
|
294
295
|
schemasTs += `}\n`;
|
|
295
|
-
|
|
296
|
+
writeGeneratedSource(path.join(outDir, "schemas.ts"), schemasTs, "gateway");
|
|
296
297
|
}
|
|
297
298
|
/**
|
|
298
299
|
* Emits individual route files and routes.ts aggregator module
|
|
@@ -360,7 +361,7 @@ import type { FastifyInstance } from "fastify";
|
|
|
360
361
|
routeTs += ` }\n`;
|
|
361
362
|
routeTs += ` });\n`;
|
|
362
363
|
routeTs += `}\n`;
|
|
363
|
-
|
|
364
|
+
writeGeneratedSource(path.join(routesDir, `${routeFileBase}.ts`), routeTs, "gateway/routes");
|
|
364
365
|
});
|
|
365
366
|
const routeFnName = `registerRoutes_${slugName(versionSlug)}_${slugName(serviceSlug)}`;
|
|
366
367
|
routesTs += `\nexport async function ${routeFnName}(fastify: FastifyInstance) {\n`;
|
|
@@ -369,7 +370,7 @@ import type { FastifyInstance } from "fastify";
|
|
|
369
370
|
routesTs += ` await ${fnName}(fastify);\n`;
|
|
370
371
|
});
|
|
371
372
|
routesTs += `}\n`;
|
|
372
|
-
|
|
373
|
+
writeGeneratedSource(path.join(outDir, "routes.ts"), routesTs, "gateway/routes");
|
|
373
374
|
}
|
|
374
375
|
/**
|
|
375
376
|
* Emits runtime.ts module with envelope builders and error handling utilities
|
|
@@ -647,7 +648,7 @@ export function createGatewayErrorHandler_${vSlug}_${sSlug}() {
|
|
|
647
648
|
}
|
|
648
649
|
`;
|
|
649
650
|
const streamSection = opts?.hasStreams ? buildStreamRuntimeSection() : "";
|
|
650
|
-
|
|
651
|
+
writeGeneratedSource(path.join(outDir, "runtime.ts"), runtimeTs + unwrapSection + streamSection, "gateway/runtime");
|
|
651
652
|
}
|
|
652
653
|
/**
|
|
653
654
|
* Returns the streaming helpers block for runtime.ts.
|
|
@@ -822,7 +823,7 @@ export default fp(${sSlug}GatewayPlugin, {
|
|
|
822
823
|
// Named export for convenience
|
|
823
824
|
export { ${sSlug}GatewayPlugin };
|
|
824
825
|
`;
|
|
825
|
-
|
|
826
|
+
writeGeneratedSource(path.join(outDir, "plugin.ts"), pluginTs, "gateway");
|
|
826
827
|
}
|
|
827
828
|
/**
|
|
828
829
|
* Emits a type-check fixture that verifies plugin-client type compatibility
|
|
@@ -861,7 +862,7 @@ function _assertClientCompatible(client: ${clientMeta.className}): void {
|
|
|
861
862
|
}
|
|
862
863
|
void _assertClientCompatible;
|
|
863
864
|
`;
|
|
864
|
-
|
|
865
|
+
writeGeneratedSource(path.join(outDir, "_typecheck.ts"), content, "gateway");
|
|
865
866
|
}
|
|
866
867
|
/**
|
|
867
868
|
* Emits individual route files with full handler implementations
|
|
@@ -973,7 +974,7 @@ ${handlerBody}
|
|
|
973
974
|
});
|
|
974
975
|
}
|
|
975
976
|
`;
|
|
976
|
-
|
|
977
|
+
writeGeneratedSource(path.join(routesDir, `${routeFileBase}.ts`), routeTs, "gateway/routes");
|
|
977
978
|
});
|
|
978
979
|
// Generate routes.ts aggregator module
|
|
979
980
|
const routeFnName = `registerRoutes_${vSlug}_${sSlug}`;
|
|
@@ -991,5 +992,5 @@ export async function ${routeFnName}(fastify: FastifyInstance): Promise<void> {
|
|
|
991
992
|
}).join("\n");
|
|
992
993
|
routesTs += ` // Register all routes\n${routeCalls}\n`;
|
|
993
994
|
routesTs += `}\n`;
|
|
994
|
-
|
|
995
|
+
writeGeneratedSource(path.join(outDir, "routes.ts"), routesTs, "gateway/routes");
|
|
995
996
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an internal resolver with an isolated cache for immutable resources.
|
|
3
|
+
* @param root - Absolute resource root; production uses only the module-relative packaged root.
|
|
4
|
+
* @returns Resolver selecting the nearest nonempty preamble, never concatenating resources.
|
|
5
|
+
* @throws If a scope is unsafe or a required/selected resource cannot be read.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createPreambleResolver(root?: string): (artifact: string) => string;
|
|
8
|
+
export declare const resolvePreamble: (artifact: string) => string;
|
|
9
|
+
/**
|
|
10
|
+
* Prefixes a fresh complete source body, preserving its shebang and remaining bytes.
|
|
11
|
+
* @param body - Generator body, not an existing output file.
|
|
12
|
+
* @param preamble - Validated comment-only resource.
|
|
13
|
+
* @returns BOM-free source with one supplied preamble and a separating blank line.
|
|
14
|
+
* @constraints Embedded fragments must not pass through this composer separately.
|
|
15
|
+
*/
|
|
16
|
+
export declare function composeGeneratedSource(body: string, preamble: string): string;
|
|
17
|
+
//# sourceMappingURL=preamble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preamble.d.ts","sourceRoot":"","sources":["../../src/generation/preamble.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,GAAE,MAAqB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAmChG;AAED,eAAO,MAAM,eAAe,aArCoD,MAAM,KAAK,MAqCpC,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO7E"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves trusted packaged TypeScript preambles by logical artifact scope.
|
|
3
|
+
* @since 1.1.0
|
|
4
|
+
* @constraints Resource content is validated by package tooling, without a runtime TypeScript dependency.
|
|
5
|
+
*/
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
const packagedRoot = fileURLToPath(new URL("../../src/generation/preambles/", import.meta.url));
|
|
10
|
+
/**
|
|
11
|
+
* Creates an internal resolver with an isolated cache for immutable resources.
|
|
12
|
+
* @param root - Absolute resource root; production uses only the module-relative packaged root.
|
|
13
|
+
* @returns Resolver selecting the nearest nonempty preamble, never concatenating resources.
|
|
14
|
+
* @throws If a scope is unsafe or a required/selected resource cannot be read.
|
|
15
|
+
*/
|
|
16
|
+
export function createPreambleResolver(root = packagedRoot) {
|
|
17
|
+
const absoluteRoot = path.resolve(root);
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
function readResource(file, optional) {
|
|
20
|
+
try {
|
|
21
|
+
if (!fs.statSync(file).isFile())
|
|
22
|
+
throw new Error("Resource is not a regular file");
|
|
23
|
+
const content = fs.readFileSync(file, "utf8").replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
|
|
24
|
+
if (!content.trim())
|
|
25
|
+
throw new Error("Resource is empty");
|
|
26
|
+
return content;
|
|
27
|
+
}
|
|
28
|
+
catch (cause) {
|
|
29
|
+
if (optional && cause.code === "ENOENT")
|
|
30
|
+
return undefined;
|
|
31
|
+
throw new Error(`Could not load TypeScript preamble ${file}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return (artifact) => {
|
|
35
|
+
if (!/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/.test(artifact)) {
|
|
36
|
+
throw new Error(`Invalid preamble artifact scope: ${artifact}`);
|
|
37
|
+
}
|
|
38
|
+
const cached = cache.get(artifact);
|
|
39
|
+
if (cached !== undefined)
|
|
40
|
+
return cached;
|
|
41
|
+
const rootFile = path.join(absoluteRoot, "typescript.preamble");
|
|
42
|
+
const fallback = cache.get("") ?? readResource(rootFile, false);
|
|
43
|
+
cache.set("", fallback);
|
|
44
|
+
const segments = artifact.split("/");
|
|
45
|
+
while (segments.length > 0) {
|
|
46
|
+
const selected = readResource(path.join(absoluteRoot, ...segments, "typescript.preamble"), true);
|
|
47
|
+
if (selected !== undefined) {
|
|
48
|
+
cache.set(artifact, selected);
|
|
49
|
+
return selected;
|
|
50
|
+
}
|
|
51
|
+
segments.pop();
|
|
52
|
+
}
|
|
53
|
+
cache.set(artifact, fallback);
|
|
54
|
+
return fallback;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export const resolvePreamble = createPreambleResolver();
|
|
58
|
+
/**
|
|
59
|
+
* Prefixes a fresh complete source body, preserving its shebang and remaining bytes.
|
|
60
|
+
* @param body - Generator body, not an existing output file.
|
|
61
|
+
* @param preamble - Validated comment-only resource.
|
|
62
|
+
* @returns BOM-free source with one supplied preamble and a separating blank line.
|
|
63
|
+
* @constraints Embedded fragments must not pass through this composer separately.
|
|
64
|
+
*/
|
|
65
|
+
export function composeGeneratedSource(body, preamble) {
|
|
66
|
+
const source = body.replace(/^\uFEFF/, "");
|
|
67
|
+
const header = preamble.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n").replace(/\n+$/, "") + "\n\n";
|
|
68
|
+
if (!source.startsWith("#!"))
|
|
69
|
+
return header + source;
|
|
70
|
+
const shebang = source.match(/^#![^\r\n]*(?:\r\n|\r|\n|$)/)[0];
|
|
71
|
+
const separator = /[\r\n]$/.test(shebang) ? "" : "\n";
|
|
72
|
+
return shebang + separator + header + source.slice(shebang.length);
|
|
73
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes a generated TypeScript file after resolving its packaged preamble.
|
|
3
|
+
* @param filePath - Destination whose parent directory already exists.
|
|
4
|
+
* @param content - Fresh complete source body.
|
|
5
|
+
* @param artifact - Logical scope, independent of the consumer output directory.
|
|
6
|
+
* @returns Nothing.
|
|
7
|
+
* @throws If resource resolution, composition, or writing fails.
|
|
8
|
+
* @constraints Call only after any scaffold skip/force guard.
|
|
9
|
+
*/
|
|
10
|
+
export declare function writeGeneratedSource(filePath: string, content: string, artifact: string): void;
|
|
11
|
+
//# sourceMappingURL=writeGeneratedSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeGeneratedSource.d.ts","sourceRoot":"","sources":["../../src/generation/writeGeneratedSource.ts"],"names":[],"mappings":"AAOA;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAO9F"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applies output policy once at the complete TypeScript file boundary.
|
|
3
|
+
* @since 1.1.0
|
|
4
|
+
*/
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { composeGeneratedSource, resolvePreamble } from "./preamble.js";
|
|
7
|
+
/**
|
|
8
|
+
* Writes a generated TypeScript file after resolving its packaged preamble.
|
|
9
|
+
* @param filePath - Destination whose parent directory already exists.
|
|
10
|
+
* @param content - Fresh complete source body.
|
|
11
|
+
* @param artifact - Logical scope, independent of the consumer output directory.
|
|
12
|
+
* @returns Nothing.
|
|
13
|
+
* @throws If resource resolution, composition, or writing fails.
|
|
14
|
+
* @constraints Call only after any scaffold skip/force guard.
|
|
15
|
+
*/
|
|
16
|
+
export function writeGeneratedSource(filePath, content, artifact) {
|
|
17
|
+
try {
|
|
18
|
+
const source = composeGeneratedSource(content, resolvePreamble(artifact));
|
|
19
|
+
fs.writeFileSync(filePath, source, "utf8");
|
|
20
|
+
}
|
|
21
|
+
catch (cause) {
|
|
22
|
+
throw new Error(`Failed to generate ${filePath} (${artifact} preamble): ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateTests.d.ts","sourceRoot":"","sources":["../../src/test/generateTests.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generateTests.d.ts","sourceRoot":"","sources":["../../src/test/generateTests.ts"],"names":[],"mappings":"AAkCA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAuBD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiK7E"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* 5. For each file: skip-if-exists check, then write
|
|
13
13
|
*/
|
|
14
14
|
import fs from "node:fs";
|
|
15
|
+
import { writeGeneratedSource } from "../generation/writeGeneratedSource.js";
|
|
15
16
|
import path from "node:path";
|
|
16
17
|
import { info, success } from "../util/cli.js";
|
|
17
18
|
import { resolveClientMeta, resolveOperationMeta, slugName } from "../gateway/helpers.js";
|
|
@@ -33,11 +34,11 @@ function shouldWriteTestFile(filePath, force) {
|
|
|
33
34
|
/**
|
|
34
35
|
* Writes a test file if it should be written (skip-if-exists with force override).
|
|
35
36
|
*/
|
|
36
|
-
function writeTestFile(filePath, content, force) {
|
|
37
|
+
function writeTestFile(filePath, content, force, artifact = "test") {
|
|
37
38
|
if (!shouldWriteTestFile(filePath, force))
|
|
38
39
|
return;
|
|
39
40
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
40
|
-
|
|
41
|
+
writeGeneratedSource(filePath, content, artifact);
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
44
|
* Generates a complete Vitest test suite for the generated gateway artifacts.
|
|
@@ -117,25 +118,25 @@ export async function generateTests(opts) {
|
|
|
117
118
|
// Emit vitest.config.ts
|
|
118
119
|
writeTestFile(path.join(testDir, "vitest.config.ts"), emitVitestConfig(), force);
|
|
119
120
|
// Emit helpers/mock-client.ts
|
|
120
|
-
writeTestFile(path.join(testDir, "helpers", "mock-client.ts"), emitMockClientHelper(testDir, clientDir, importsMode, clientMeta, operations, mocks), force);
|
|
121
|
+
writeTestFile(path.join(testDir, "helpers", "mock-client.ts"), emitMockClientHelper(testDir, clientDir, importsMode, clientMeta, operations, mocks), force, "test/helpers");
|
|
121
122
|
// Emit helpers/test-app.ts
|
|
122
|
-
writeTestFile(path.join(testDir, "helpers", "test-app.ts"), emitTestAppHelper(testDir, gatewayDir, importsMode, clientMeta), force);
|
|
123
|
+
writeTestFile(path.join(testDir, "helpers", "test-app.ts"), emitTestAppHelper(testDir, gatewayDir, importsMode, clientMeta), force, "test/helpers");
|
|
123
124
|
// Emit gateway/routes.test.ts
|
|
124
|
-
writeTestFile(path.join(testDir, "gateway", "routes.test.ts"), emitRoutesTest(testDir, importsMode, operations, mocks), force);
|
|
125
|
+
writeTestFile(path.join(testDir, "gateway", "routes.test.ts"), emitRoutesTest(testDir, importsMode, operations, mocks), force, "test/gateway");
|
|
125
126
|
// Emit gateway/errors.test.ts
|
|
126
|
-
writeTestFile(path.join(testDir, "gateway", "errors.test.ts"), emitErrorsTest(testDir, importsMode, operations, mocks), force);
|
|
127
|
+
writeTestFile(path.join(testDir, "gateway", "errors.test.ts"), emitErrorsTest(testDir, importsMode, operations, mocks), force, "test/gateway");
|
|
127
128
|
// Emit gateway/envelope.test.ts
|
|
128
|
-
writeTestFile(path.join(testDir, "gateway", "envelope.test.ts"), emitEnvelopeTest(testDir, importsMode, operations, mocks), force);
|
|
129
|
+
writeTestFile(path.join(testDir, "gateway", "envelope.test.ts"), emitEnvelopeTest(testDir, importsMode, operations, mocks), force, "test/gateway");
|
|
129
130
|
// Emit gateway/validation.test.ts
|
|
130
|
-
writeTestFile(path.join(testDir, "gateway", "validation.test.ts"), emitValidationTest(testDir, importsMode, operations, mocks, catalog), force);
|
|
131
|
+
writeTestFile(path.join(testDir, "gateway", "validation.test.ts"), emitValidationTest(testDir, importsMode, operations, mocks, catalog), force, "test/gateway");
|
|
131
132
|
// Emit runtime/classify-error.test.ts
|
|
132
|
-
writeTestFile(path.join(testDir, "runtime", "classify-error.test.ts"), emitClassifyErrorTest(testDir, gatewayDir, importsMode), force);
|
|
133
|
+
writeTestFile(path.join(testDir, "runtime", "classify-error.test.ts"), emitClassifyErrorTest(testDir, gatewayDir, importsMode), force, "test/runtime");
|
|
133
134
|
// Emit runtime/envelope-builders.test.ts
|
|
134
|
-
writeTestFile(path.join(testDir, "runtime", "envelope-builders.test.ts"), emitEnvelopeBuildersTest(testDir, gatewayDir, importsMode), force);
|
|
135
|
+
writeTestFile(path.join(testDir, "runtime", "envelope-builders.test.ts"), emitEnvelopeBuildersTest(testDir, gatewayDir, importsMode), force, "test/runtime");
|
|
135
136
|
// Emit runtime/unwrap.test.ts (conditional: only when ArrayOf* wrappers exist)
|
|
136
137
|
const unwrapContent = emitUnwrapTest(testDir, gatewayDir, importsMode, catalog);
|
|
137
138
|
if (unwrapContent) {
|
|
138
|
-
writeTestFile(path.join(testDir, "runtime", "unwrap.test.ts"), unwrapContent, force);
|
|
139
|
+
writeTestFile(path.join(testDir, "runtime", "unwrap.test.ts"), unwrapContent, force, "test/runtime");
|
|
139
140
|
}
|
|
140
141
|
success(`Test suite generated in ${testDir}`);
|
|
141
142
|
}
|
package/docs/api-reference.md
CHANGED
|
@@ -4,6 +4,8 @@ All CLI commands are available as TypeScript functions. This document covers eac
|
|
|
4
4
|
|
|
5
5
|
See the main [README](../README.md) for installation, CLI usage, and project overview.
|
|
6
6
|
|
|
7
|
+
All file-producing APIs automatically apply [TypeScript preambles](generated-code.md#generated-preambles-and-eslint). Signatures and options are unchanged; existing scaffold skip/force behavior still applies. Resource and TypeScript file-write failures propagate to callers.
|
|
8
|
+
|
|
7
9
|
## compileWsdlToProject
|
|
8
10
|
|
|
9
11
|
Generate a TypeScript SOAP client from WSDL.
|
package/docs/architecture.md
CHANGED
|
@@ -4,6 +4,16 @@ Internal architecture of the wsdl-tsc code generator for contributors.
|
|
|
4
4
|
|
|
5
5
|
See [CONTRIBUTING](../CONTRIBUTING.md) for development setup and [README](../README.md) for user documentation.
|
|
6
6
|
|
|
7
|
+
## Generated Source Policy
|
|
8
|
+
|
|
9
|
+
Complete TypeScript writes pass through `src/generation/writeGeneratedSource.ts` after any scaffold ownership guard. Runtime/template loaders remain fragment loaders; provenance and documentation are preserved when the final body receives its preamble.
|
|
10
|
+
|
|
11
|
+
`src/generation/preamble.ts` resolves trusted raw resources relative to this package's module location, never the consumer working directory. Logical scopes use nearest-resource fallback: `gateway/routes/typescript.preamble`, then `gateway/typescript.preamble`, then the required root `typescript.preamble`. One resource wins; resources are not concatenated. App and test overrides describe editable scaffolds.
|
|
12
|
+
|
|
13
|
+
Successful resource resolutions are cached per resolver and logical scope for the process lifetime. A missing optional resource falls back, but a broken selected resource or missing required root fails generation. The writer preserves shebang placement and body text while normalizing preamble line endings and removing leading BOMs.
|
|
14
|
+
|
|
15
|
+
Package validation uses the development TypeScript compiler to reject non-comment content and compiler-control directives. The generator runtime does not load that compiler. Raw `.preamble` files are included in npm packages, and `package:smoke` verifies installed generation outside the checkout during full CI. No custom resource roots or new public options are exposed.
|
|
16
|
+
|
|
7
17
|
## Pipeline Overview
|
|
8
18
|
|
|
9
19
|
```text
|
package/docs/cli-reference.md
CHANGED
|
@@ -8,6 +8,8 @@ Generation paths are explicit. Examples use the git-ignored `.generated/` direct
|
|
|
8
8
|
|
|
9
9
|
The tool provides six commands for different integration scenarios.
|
|
10
10
|
|
|
11
|
+
TypeScript outputs automatically receive [generated preambles](generated-code.md#generated-preambles-and-eslint), including app/test scaffolds when actually written. Command syntax is unchanged and there is no preamble flag. `compile` and `openapi` data outputs remain unchanged.
|
|
12
|
+
|
|
11
13
|
| Command | Purpose | Typical Use Case |
|
|
12
14
|
|---------|---------|------------------|
|
|
13
15
|
| pipeline | Full pipeline: client + OpenAPI + gateway + app | CI/CD automation, complete stack generation |
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Contributor guide for naming files and organizing fixture paths. See the root [README.md](../README.md) for the authoritative documentation index.
|
|
4
4
|
|
|
5
|
+
## Preamble Resources
|
|
6
|
+
|
|
7
|
+
Raw comment-only headers live under `src/generation/preambles/` with the filename `typescript.preamble`. Subdirectories express logical artifact scopes rather than consumer output paths. See [generated source policy](architecture.md#generated-source-policy) for fallback and packaging rules.
|
|
8
|
+
|
|
9
|
+
Package-smoke tarballs and logs belong in `tmp/preflight/package/`; the isolated consumer installation uses a verified temporary directory outside the checkout to prove that package resources resolve independently.
|
|
10
|
+
|
|
5
11
|
## Purpose
|
|
6
12
|
|
|
7
13
|
Paths should classify files before a reader opens them. The left side of a path carries the broadest concept; each segment to the right narrows the classification until the filename states the exact artifact purpose.
|
package/docs/generated-code.md
CHANGED
|
@@ -4,6 +4,106 @@ Guide to using the TypeScript SOAP clients and types generated by wsdl-tsc.
|
|
|
4
4
|
|
|
5
5
|
See [README](../README.md) for quick start and [Concepts](concepts.md) for type modeling details.
|
|
6
6
|
|
|
7
|
+
## Generated Preambles and ESLint
|
|
8
|
+
|
|
9
|
+
Every newly written TypeScript client, gateway, app, and generated-test file starts with `/* eslint-disable */`. This includes conditional streaming/security helpers, stub routes, and gateway typecheck fixtures. CLI and programmatic generation use the same defaults with no new flags or required arguments.
|
|
10
|
+
|
|
11
|
+
Generator-owned client and gateway files receive this preamble:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
/* eslint-disable */
|
|
15
|
+
// Generated by @techspokes/typescript-wsdl-client.
|
|
16
|
+
// Do not edit manually. Regenerate with wsdl-tsc.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Editable app and test scaffolds receive distinct ownership guidance:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
/* eslint-disable */
|
|
23
|
+
// Scaffold generated by @techspokes/typescript-wsdl-client.
|
|
24
|
+
// Customize this file. Remove eslint-disable when adopting it as maintained source.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Existing scaffolds are not rewritten unless their existing `--force-init` or `--force-test` option explicitly requests regeneration. Remove the directive when adopting a scaffold as maintained source, and keep that source outside globally ignored generated directories. JSON, YAML, Markdown, configuration data, and environment files do not receive preambles.
|
|
28
|
+
|
|
29
|
+
### Suppression Versus Exclusion
|
|
30
|
+
|
|
31
|
+
The directive suppresses ESLint rule reports when inline configuration is allowed; ESLint still parses the file. It cannot fix syntax errors, missing TypeScript parsers, or parser project-configuration errors. TypeScript compilation and checking remain enabled.
|
|
32
|
+
|
|
33
|
+
`noInlineConfig: true` or `--no-inline-config` prevents the suppression from taking effect. An otherwise clean file may produce an unused-disable warning or error under `reportUnusedDisableDirectives`. Keep corporate lint policies for maintained source and globally ignore disposable generated paths when those policies conflict with the directive.
|
|
34
|
+
|
|
35
|
+
### Ignore Generated Directories
|
|
36
|
+
|
|
37
|
+
For projects using `eslint`, `@eslint/js`, and `typescript-eslint`, this flat configuration excludes generated client and gateway directories:
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
// eslint.config.mjs
|
|
41
|
+
import js from "@eslint/js";
|
|
42
|
+
import { defineConfig, globalIgnores } from "eslint/config";
|
|
43
|
+
import tseslint from "typescript-eslint";
|
|
44
|
+
|
|
45
|
+
export default defineConfig([
|
|
46
|
+
globalIgnores([".generated/client/**", ".generated/gateway/**"]),
|
|
47
|
+
js.configs.recommended,
|
|
48
|
+
tseslint.configs.recommended,
|
|
49
|
+
]);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Add the ignore entry to an existing configuration while retaining its presets, plugins, parser, and rules. Use `.generated/**` only when that entire directory is disposable; adopted app/test scaffolds should remain linted. Monorepos can scope generated paths explicitly, for example `packages/*/.generated/client/**`.
|
|
53
|
+
|
|
54
|
+
An ignores-only entry also works as a separate item in the configuration array:
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
const generatedIgnores = {
|
|
58
|
+
ignores: [".generated/client/**", ".generated/gateway/**"],
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Do not add `files`, `rules`, or `languageOptions` to this entry and expect it to remain a global exclusion. Modern flat configuration does not automatically load `.eslintignore`; the generator does not create or rewrite consumer ESLint configuration.
|
|
63
|
+
|
|
64
|
+
### Mixed Source Directories
|
|
65
|
+
|
|
66
|
+
When generated output shares a directory with maintained code, add an explicit ignore entry instead of broad patterns such as `**/client.ts`:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
import { globalIgnores } from "eslint/config";
|
|
70
|
+
|
|
71
|
+
const generatedIgnores = globalIgnores([
|
|
72
|
+
"src/integrations/weather/client.ts",
|
|
73
|
+
"src/integrations/weather/types.ts",
|
|
74
|
+
"src/integrations/weather/operations.ts",
|
|
75
|
+
"src/integrations/weather/utils.ts",
|
|
76
|
+
"src/integrations/weather/gateway/**",
|
|
77
|
+
]);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Include any conditional generated helpers, such as `streamXml.ts`, in your explicit paths. Dedicated generated directories make this easier to maintain.
|
|
81
|
+
|
|
82
|
+
### Strict Policies and Hooks
|
|
83
|
+
|
|
84
|
+
Global ignores can coexist with this separate policy entry for maintained source:
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
const inlineConfigPolicy = {
|
|
88
|
+
linterOptions: {
|
|
89
|
+
noInlineConfig: true,
|
|
90
|
+
reportUnusedDisableDirectives: "error",
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For a single invocation, use `npx eslint . --ignore-pattern ".generated/client/**" --ignore-pattern ".generated/gateway/**"`. Normal configuration patterns are relative to the configuration file; CLI patterns and patterns from an alternate `--config` resolve against the working directory.
|
|
96
|
+
|
|
97
|
+
Hooks that pass ignored files explicitly may produce warnings. With the ignore configuration already installed, use:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx eslint --max-warnings 0 --no-warn-ignored .generated/client/client.ts src/app.ts
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`--no-warn-ignored` does not create exclusions or hide lint failures in `src/app.ts`. It does not suppress unused-disable diagnostics on files ESLint actually lints.
|
|
104
|
+
|
|
105
|
+
See ESLint's [ignore documentation](https://eslint.org/docs/latest/use/configure/ignore) and [configuration documentation](https://eslint.org/docs/latest/use/configure/configuration-files) for pattern and policy details.
|
|
106
|
+
|
|
7
107
|
## Client Construction
|
|
8
108
|
|
|
9
109
|
```typescript
|
package/docs/output-anatomy.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
This document describes each file produced by the generator, what it contains, and how to work with it. For CLI flags that control output, see [CLI Reference](cli-reference.md).
|
|
4
4
|
|
|
5
|
+
## TypeScript File Preambles
|
|
6
|
+
|
|
7
|
+
All complete emitted TypeScript files receive one [generated preamble](generated-code.md#generated-preambles-and-eslint), including optional helpers and `_typecheck.ts`. App and generated-test scaffolds use editable-source wording and retain their existing skip/force behavior. Data outputs and existing consumer source remain unchanged.
|
|
8
|
+
|
|
5
9
|
## Generation Flow
|
|
6
10
|
|
|
7
11
|
The pipeline follows this sequence: WSDL source is parsed and compiled into a catalog, then each emitter reads the catalog and produces its output.
|
package/docs/releases/README.md
CHANGED
|
@@ -59,11 +59,19 @@ When an abandoned major or minor candidate contains the complete launch narrativ
|
|
|
59
59
|
|
|
60
60
|
The supported release path keeps final-form tags immutable:
|
|
61
61
|
|
|
62
|
-
1.
|
|
63
|
-
2.
|
|
64
|
-
3. Push the
|
|
65
|
-
4.
|
|
66
|
-
5.
|
|
62
|
+
1. Prepare versions, changelog, release notes, and the documentation index before pushing the release PR.
|
|
63
|
+
2. Run release preflight on the final uncommitted tree and commit that exact validated tree.
|
|
64
|
+
3. Push the PR and require Node 24 and Node 26 checks on its final head before merging.
|
|
65
|
+
4. Verify the merged main tree matches the validated tree and require CI on the merged commit.
|
|
66
|
+
5. Tag the validated merged main commit and push the tag to start the draft workflow.
|
|
67
|
+
6. Verify the draft, release notes, uploaded skill ZIP, checksum manifest, and artifact verification results.
|
|
68
|
+
7. Clean up task-owned merged branches and temporary outputs, then hand the draft to the maintainer.
|
|
69
|
+
8. The maintainer reviews the draft in their own browser and clicks Publish.
|
|
70
|
+
9. The guarded package workflow publishes to npmjs with provenance.
|
|
71
|
+
|
|
72
|
+
The agent stops after draft verification and cleanup. Agents must never access GitHub through a browser, publish a release, or dispatch package publication. Use authenticated git and GitHub CLI commands for preparation and verification. Preserve unrelated work, contributor-owned branches, immutable release tags, and abandonment markers during cleanup.
|
|
73
|
+
|
|
74
|
+
If the merged tree differs from the preflight-validated tree, stop before tagging and prepare a newly validated candidate. Do not rerun preflight for an unchanged validated tree.
|
|
67
75
|
|
|
68
76
|
Manual package dispatch is a recovery path after the GitHub Release is published. It enforces the same tag, marker, reachability, draft, and prerelease checks.
|
|
69
77
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# TypeScript WSDL Client v1.1.0
|
|
2
|
+
|
|
3
|
+
## Generated TypeScript with explicit lint ownership
|
|
4
|
+
|
|
5
|
+
This minor release adds automatic ESLint suppression preambles to newly emitted TypeScript and documents path exclusions for consumers with restrictive lint policies.
|
|
6
|
+
|
|
7
|
+
## What This Improves
|
|
8
|
+
|
|
9
|
+
Regenerated client and gateway files carry their ESLint directive automatically, eliminating repeated manual edits. App and generated-test scaffolds use distinct wording that explains when to remove suppression as those files become maintained source.
|
|
10
|
+
|
|
11
|
+
Preambles are packaged resources selected by logical artifact scope and applied at the final file-write boundary. Resource validation and installed-package consumer tests ensure the behavior works outside the repository checkout, including conditional helpers and programmatic generation.
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- Add one preamble to every complete generated TypeScript file, including streaming helpers and stub routes.
|
|
16
|
+
- Preserve existing app/test files unless their existing force option requests regeneration.
|
|
17
|
+
- Propagate TypeScript generation failures instead of logging write failures as successful generation.
|
|
18
|
+
- Document consumer global ignores, strict inline policies, parser limitations, and hook behavior.
|
|
19
|
+
- Verify real ESLint suppression alongside maintained-source controls and installed-package tests.
|
|
20
|
+
|
|
21
|
+
## Upgrade Notes
|
|
22
|
+
|
|
23
|
+
CLI syntax, public API signatures, catalog semantics, and runtime behavior are unchanged. Regeneration adds a comment preamble to TypeScript output; existing editable scaffolds retain their current contents unless explicitly regenerated.
|
|
24
|
+
|
|
25
|
+
`/* eslint-disable */` suppresses rule reports only when inline configuration is allowed. It does not bypass parsing or TypeScript checking, and clean files may produce unused-disable diagnostics. Use the [consumer ESLint guidance](../generated-code.md#generated-preambles-and-eslint) to exclude generated paths while keeping maintained-source policies intact.
|
|
26
|
+
|
|
27
|
+
Remove the suppression when adopting an app or test scaffold as maintained source, and keep adopted files outside ignored generated directories. No runtime or schema migration is required.
|
|
28
|
+
|
|
29
|
+
## Validation
|
|
30
|
+
|
|
31
|
+
- Generated-file, resource-validation, and ESLint tests passed on Node 24 and Node 26.
|
|
32
|
+
- Full CI, generated-artifact conformance, and pipeline smoke validation passed.
|
|
33
|
+
- Installed tarball generation, consumer typechecking, and generated tests passed outside the checkout.
|
|
34
|
+
- NPM package contents and comment-only resources were validated.
|
|
35
|
+
- The agent skill artifact was validated and packaged with the new consumer guidance.
|
|
36
|
+
- Release preflight passed against the target tag.
|
|
37
|
+
|
|
38
|
+
## Notes
|
|
39
|
+
|
|
40
|
+
Release tag: `v1.1.0`.
|
|
41
|
+
|
|
42
|
+
Implements [issue #142](https://github.com/TechSpokes/typescript-wsdl-client/issues/142).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# TypeScript WSDL Client v1.1.1
|
|
2
|
+
|
|
3
|
+
## Correct array types from wrapping sequences
|
|
4
|
+
|
|
5
|
+
This patch preserves occurrence bounds declared on wrapping `xs:sequence` nodes when generating element types. See the [project overview](../../README.md) for the generation pipeline.
|
|
6
|
+
|
|
7
|
+
## What This Improves
|
|
8
|
+
|
|
9
|
+
A sequence with `maxOccurs="2"` around an address element now generates `address: AddressType[]` instead of a scalar address. Sequences with `minOccurs="0"` and repeated bounds generate optional arrays, including finite limits and `unbounded`.
|
|
10
|
+
|
|
11
|
+
The corrected catalog metadata flows into client types, OpenAPI schemas, and gateway responses. Consumer fixtures verify that both addresses survive the existing array-wrapper flattening behavior.
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- Preserve occurrence bounds through uninterrupted sequence ancestry, including nested sequences.
|
|
16
|
+
- Verify required and optional arrays in generated TypeScript and OpenAPI schemas.
|
|
17
|
+
- Preserve repeated response items through gateway wrapper flattening.
|
|
18
|
+
- Check the regression through the installed package CLI and consumer TypeScript compilation.
|
|
19
|
+
- Refresh the soap runtime and generated app floor to 1.13.1 and Vitest tooling to 5.0.2.
|
|
20
|
+
|
|
21
|
+
## Upgrade Notes
|
|
22
|
+
|
|
23
|
+
Update the package and regenerate your clients, OpenAPI specifications, and gateways from their WSDL sources. Review the generated diff: affected scalar properties become arrays, and properties inside optional sequences can become optional. Adapt consuming code to these corrected types.
|
|
24
|
+
|
|
25
|
+
Corrected array metadata can activate existing OpenAPI wrapper flattening, changing an affected REST object wrapper into an array. Review REST payload schemas and consumers when regenerating gateways; existing wrapper-flattening options retain their meanings.
|
|
26
|
+
|
|
27
|
+
This patch preserves the previous behavior across `xs:choice`, `xs:all`, zero-maximum sequence subtrees, disabled elements, and wildcards. It adds no finite-array-length or sequence-order runtime enforcement, CLI options, or catalog fields. See [supported patterns](../supported-patterns.md#fully-supported) for the compatibility boundary.
|
|
28
|
+
|
|
29
|
+
## Validation
|
|
30
|
+
|
|
31
|
+
- Focused occurrence and unchanged choice-mode regression tests passed.
|
|
32
|
+
- Full CI, generated-artifact conformance, and pipeline smoke validation passed.
|
|
33
|
+
- Installed package generation and consumer TypeScript checks passed, including rejection of scalar addresses.
|
|
34
|
+
- NPM package contents were validated.
|
|
35
|
+
- The agent skill artifact was validated and packaged with its checksum manifest.
|
|
36
|
+
- Release preflight passed against the target tag.
|
|
37
|
+
|
|
38
|
+
## Notes
|
|
39
|
+
|
|
40
|
+
Release tag: `v1.1.1`.
|
|
41
|
+
|
|
42
|
+
This candidate was abandoned before publication. Singleton SOAP responses could remain scalar and fail gateway serialization despite generated array contracts. The immutable tag and abandonment marker retain its release identity.
|
|
43
|
+
|
|
44
|
+
Fixes [issue #141](https://github.com/TechSpokes/typescript-wsdl-client/issues/141) through [PR #145](https://github.com/TechSpokes/typescript-wsdl-client/pull/145). Thanks to [BCsabaEngine](https://github.com/BCsabaEngine) for the original diagnosis and contribution.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# TypeScript WSDL Client v1.1.2
|
|
2
|
+
|
|
3
|
+
## Consistent arrays from wrapping sequences
|
|
4
|
+
|
|
5
|
+
This patch corrects generated array contracts and singleton SOAP response conversion for wrapping sequences. See the [project overview](../../README.md) for the generation pipeline.
|
|
6
|
+
|
|
7
|
+
## What This Improves
|
|
8
|
+
|
|
9
|
+
An element inside a repeated `xs:sequence` now receives the sequence's occurrence bounds in the compiled catalog and generated types. A single returned address becomes a one-element array, and multiple addresses retain their order. Generated REST gateways can serialize both responses successfully.
|
|
10
|
+
|
|
11
|
+
The generated client uses existing catalog metadata to normalize repeated properties, so direct client consumers receive the same correction as gateways. Optional properties remain absent when omitted, and existing null handling is preserved.
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- Propagate occurrence bounds through uninterrupted sequences, including nested sequences.
|
|
16
|
+
- Normalize singleton primitive and complex responses to their declared array shape.
|
|
17
|
+
- Preserve inherited and aliased type metadata during response conversion.
|
|
18
|
+
- Verify real SOAP responses with REST wrapper flattening enabled and disabled.
|
|
19
|
+
- Exercise the correction through an installed package and its generated client.
|
|
20
|
+
|
|
21
|
+
## Upgrade Notes
|
|
22
|
+
|
|
23
|
+
Update the package and regenerate clients, OpenAPI specifications, and gateways. Review affected scalar properties that become arrays and required properties that become optional. Corrected array metadata can also activate existing REST wrapper flattening, changing an object wrapper into an array.
|
|
24
|
+
|
|
25
|
+
This release retains previous sequence-boundary handling for `xs:choice`, `xs:all`, zero-maximum sequences, disabled elements, and wildcards. It adds no finite-array-length or sequence-order validation and no CLI options or catalog fields. The generated metadata interface adds an optional `RepeatedElements` map; custom metadata without that map retains its previous behavior.
|
|
26
|
+
|
|
27
|
+
Version 1.1.1 was abandoned before publication. This release includes its sequence compiler correction and dependency maintenance, together with the runtime correction discovered during final review.
|
|
28
|
+
|
|
29
|
+
## Validation
|
|
30
|
+
|
|
31
|
+
- Real SOAP transport tests cover singleton and repeated responses and optional request omission.
|
|
32
|
+
- Generated client and gateway tests cover both REST wrapper representations.
|
|
33
|
+
- Full CI, conformance, and pipeline smoke validation passed.
|
|
34
|
+
- Installed package generation, TypeScript contracts, and SOAP response conversion passed.
|
|
35
|
+
- NPM package contents and the agent skill artifact were validated.
|
|
36
|
+
- Release preflight passed against the target tag.
|
|
37
|
+
|
|
38
|
+
## Notes
|
|
39
|
+
|
|
40
|
+
Release tag: `v1.1.2`.
|
|
41
|
+
|
|
42
|
+
The sequence compiler correction originated in [PR #145](https://github.com/TechSpokes/typescript-wsdl-client/pull/145) for [issue #141](https://github.com/TechSpokes/typescript-wsdl-client/issues/141). Thanks to [BCsabaEngine](https://github.com/BCsabaEngine) for the original diagnosis and contribution.
|
|
@@ -9,6 +9,7 @@ The rows below are backed by committed conformance fixtures under `test/conforma
|
|
|
9
9
|
<!-- support-matrix:start -->
|
|
10
10
|
| Capability ID | Status | Public contract |
|
|
11
11
|
|---|---|---|
|
|
12
|
+
| `sequence-occurrence-wrappers` | supported | Wrapping sequences with nonzero maxima propagate element bounds and optionality without crossing choice or all boundaries. |
|
|
12
13
|
| `weather-document-literal-soap` | supported | The canonical weather WSDL compiles through client, OpenAPI, gateway, generated-test, and app artifacts with document-literal SOAP operations. |
|
|
13
14
|
| `sequence-baseline-complex` | supported | Complex type sequences support nested complex references, repeated elements, optional fields, and all-optional request wrappers. |
|
|
14
15
|
| `simple-restriction-list` | supported | Named simple type restrictions, enumerations, and `xs:list` declarations emit aligned TypeScript aliases and OpenAPI schemas. |
|
|
@@ -32,6 +33,10 @@ The rows below are backed by committed conformance fixtures under `test/conforma
|
|
|
32
33
|
|
|
33
34
|
These patterns are handled end-to-end: WSDL parsing, TypeScript type generation, OpenAPI schema output, and gateway code generation.
|
|
34
35
|
|
|
36
|
+
Wrapping sequence bounds propagate through uninterrupted sequence ancestry to element array types and optionality. Traversal through `xs:choice`, `xs:all`, or a sequence with `maxOccurs="0"` retains the previous flattened behavior; wildcard and disabled-element handling are unchanged. This does not enforce sequence ordering or finite array lengths at runtime.
|
|
37
|
+
|
|
38
|
+
Generated clients normalize present, non-null singleton responses into arrays for repeated element properties. Real SOAP transport regressions cover singleton and multiple items, omitted optional request fields, and gateway serialization with wrapper flattening enabled and disabled. Regenerate clients to receive this runtime correction; omitted optional response properties remain absent.
|
|
39
|
+
|
|
35
40
|
- Complex types with `<xs:sequence>`, `<xs:all>`, and `<xs:choice>` compositors, including recursive nesting
|
|
36
41
|
- Simple content with attributes using the `$value` pattern to preserve text content alongside attribute properties
|
|
37
42
|
- Named simple type restrictions and enumerations emitted as TypeScript aliases and OpenAPI scalar schemas
|
package/docs/testing.md
CHANGED
|
@@ -4,6 +4,8 @@ Guide to running and writing tests for wsdl-tsc development and for testing gene
|
|
|
4
4
|
|
|
5
5
|
See [README](../README.md) for quick start and [CONTRIBUTING](../CONTRIBUTING.md) for development setup.
|
|
6
6
|
|
|
7
|
+
Generated test files receive an [editable scaffold preamble](generated-code.md#generated-preambles-and-eslint). Remove its ESLint suppression when adopting the tests as maintained source; existing files are preserved unless `--force-test` is used. Full local CI includes `package:smoke`, which installs a tarball outside the checkout and validates generation, consumer compilation, and generated tests.
|
|
8
|
+
|
|
7
9
|
## Test Architecture
|
|
8
10
|
|
|
9
11
|
The project uses three layers of testing:
|
package/docs/troubleshooting.md
CHANGED
|
@@ -4,6 +4,14 @@ Common issues and debugging guidance for wsdl-tsc.
|
|
|
4
4
|
|
|
5
5
|
See [README](../README.md) for quick start and [CLI Reference](cli-reference.md) for command details.
|
|
6
6
|
|
|
7
|
+
## Generated Files and ESLint
|
|
8
|
+
|
|
9
|
+
If the generated directive appears ineffective, check `noInlineConfig` and `--no-inline-config`. Unused-disable diagnostics can occur on files with no rule violations. Parser or TypeScript project errors are not rule reports and cannot be suppressed by the header.
|
|
10
|
+
|
|
11
|
+
Use the [generated-code ESLint guidance](generated-code.md#generated-preambles-and-eslint) for global exclusions that preserve maintained-source policies, explicit-file hook warnings, and scaffold adoption. Do not disable TypeScript checking or weaken lint policy globally to accommodate generated output.
|
|
12
|
+
|
|
13
|
+
A missing, empty, or unreadable packaged preamble fails generation with the resource and destination path. Reinstall the intact package; do not edit `node_modules` or patch generated files to work around a damaged installation.
|
|
14
|
+
|
|
7
15
|
## Common Issues
|
|
8
16
|
|
|
9
17
|
| Symptom | Resolution |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@techspokes/typescript-wsdl-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Turn legacy WSDL/SOAP services into typed TypeScript clients, OpenAPI 3.1 specs, and production-ready Fastify REST gateways. Built for enterprise SOAP modernization.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wsdl",
|
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
"LICENSE",
|
|
58
58
|
"llms.txt",
|
|
59
59
|
"src/runtime/*.ts",
|
|
60
|
-
"src/runtime/*.tpl.txt"
|
|
60
|
+
"src/runtime/*.tpl.txt",
|
|
61
|
+
"src/generation/preambles/**/*.preamble"
|
|
61
62
|
],
|
|
62
63
|
"scripts": {
|
|
63
64
|
"dev": "tsx src/cli.ts",
|
|
@@ -95,30 +96,34 @@
|
|
|
95
96
|
"skill:validate": "node scripts/validate-agent-skill.mjs",
|
|
96
97
|
"skill:package": "node scripts/build-agent-skill.mjs",
|
|
97
98
|
"package:validate": "node scripts/validate-npm-package.mjs",
|
|
99
|
+
"package:smoke": "node scripts/smoke-npm-package.mjs",
|
|
98
100
|
"release:preflight": "node scripts/release-preflight.mjs",
|
|
99
101
|
"release:publish-check": "npm run clean && npm run build && npm run typecheck && npm run skill:validate && npm run package:validate",
|
|
100
|
-
"ci": "npm run clean && npm run build && npm run typecheck && npm run skill:validate && npm run package:validate && npm run docs:validate && vitest run && npm run smoke:pipeline",
|
|
102
|
+
"ci": "npm run clean && npm run build && npm run typecheck && npm run skill:validate && npm run package:validate && npm run docs:validate && vitest run && npm run smoke:pipeline && npm run package:smoke",
|
|
101
103
|
"ci:github": "npm run clean && npm run build && npm run typecheck && npm run skill:validate && npm run package:validate && npm run docs:validate && npm run test:github && npm run smoke:pipeline",
|
|
102
104
|
"ci:github:node26": "npm run clean && npm run build && npm run typecheck && npm run test:unit && npm run smoke:pipeline",
|
|
103
105
|
"examples:regenerate": "tsx src/cli.ts pipeline --wsdl-source examples/minimal/weather.wsdl --client-dir examples/generated-output/client --openapi-file examples/generated-output/openapi.json --gateway-dir examples/generated-output/gateway --gateway-service-name weather --gateway-version-prefix v1 --openapi-format json"
|
|
104
106
|
},
|
|
105
107
|
"devDependencies": {
|
|
108
|
+
"@eslint/js": "^10.0.1",
|
|
106
109
|
"@types/js-yaml": "^4.0.9",
|
|
107
110
|
"@types/node": "^26.6.2",
|
|
108
111
|
"@types/yargs": "^17.0.35",
|
|
112
|
+
"eslint": "^10.11.0",
|
|
109
113
|
"fastify": "^5.12.5",
|
|
110
114
|
"fastify-plugin": "^6.0.0",
|
|
111
115
|
"rimraf": "^6.1.3",
|
|
112
116
|
"tsx": "^4.23.15",
|
|
113
117
|
"typescript": "^6.0.3",
|
|
114
|
-
"
|
|
118
|
+
"typescript-eslint": "^8.70.1",
|
|
119
|
+
"vitest": "^5.0.2"
|
|
115
120
|
},
|
|
116
121
|
"dependencies": {
|
|
117
122
|
"@apidevtools/swagger-parser": "^13.1.0",
|
|
118
123
|
"fast-xml-parser": "^5.11.1",
|
|
119
124
|
"js-yaml": "^5.4.2",
|
|
120
125
|
"saxes": "^6.0.0",
|
|
121
|
-
"soap": "^1.13.
|
|
126
|
+
"soap": "^1.13.1",
|
|
122
127
|
"yargs": "^18.2.0"
|
|
123
128
|
},
|
|
124
129
|
"funding": {
|