ts-procedures 6.0.2 → 6.2.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/agent_config/bin/setup.mjs +2 -2
- package/agent_config/claude-code/skills/ts-procedures/SKILL.md +2 -0
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +2 -0
- package/agent_config/claude-code/skills/ts-procedures-kotlin/SKILL.md +106 -0
- package/agent_config/claude-code/skills/ts-procedures-swift/SKILL.md +119 -0
- package/agent_config/copilot/copilot-instructions.md +3 -0
- package/agent_config/cursor/cursorrules +3 -0
- package/agent_config/lib/install-claude.mjs +1 -1
- package/build/codegen/bin/cli.d.ts +39 -0
- package/build/codegen/bin/cli.js +164 -0
- package/build/codegen/bin/cli.js.map +1 -1
- package/build/codegen/bin/cli.test.js +180 -1
- package/build/codegen/bin/cli.test.js.map +1 -1
- package/build/codegen/index.d.ts +36 -0
- package/build/codegen/index.js +8 -0
- package/build/codegen/index.js.map +1 -1
- package/build/codegen/pipeline.d.ts +22 -4
- package/build/codegen/pipeline.js +44 -86
- package/build/codegen/pipeline.js.map +1 -1
- package/build/codegen/pipeline.test.js +162 -0
- package/build/codegen/pipeline.test.js.map +1 -1
- package/build/codegen/targets/_shared/error-schemas.d.ts +10 -0
- package/build/codegen/targets/_shared/error-schemas.js +17 -0
- package/build/codegen/targets/_shared/error-schemas.js.map +1 -0
- package/build/codegen/targets/_shared/error-schemas.test.d.ts +1 -0
- package/build/codegen/targets/_shared/error-schemas.test.js +38 -0
- package/build/codegen/targets/_shared/error-schemas.test.js.map +1 -0
- package/build/codegen/targets/_shared/indent.d.ts +6 -0
- package/build/codegen/targets/_shared/indent.js +13 -0
- package/build/codegen/targets/_shared/indent.js.map +1 -0
- package/build/codegen/targets/_shared/indent.test.d.ts +1 -0
- package/build/codegen/targets/_shared/indent.test.js +21 -0
- package/build/codegen/targets/_shared/indent.test.js.map +1 -0
- package/build/codegen/targets/_shared/pascal-case.d.ts +6 -0
- package/build/codegen/targets/_shared/pascal-case.js +13 -0
- package/build/codegen/targets/_shared/pascal-case.js.map +1 -0
- package/build/codegen/targets/_shared/pascal-case.test.d.ts +1 -0
- package/build/codegen/targets/_shared/pascal-case.test.js +25 -0
- package/build/codegen/targets/_shared/pascal-case.test.js.map +1 -0
- package/build/codegen/targets/_shared/path-utils.d.ts +12 -0
- package/build/codegen/targets/_shared/path-utils.js +20 -0
- package/build/codegen/targets/_shared/path-utils.js.map +1 -0
- package/build/codegen/targets/_shared/path-utils.test.d.ts +1 -0
- package/build/codegen/targets/_shared/path-utils.test.js +42 -0
- package/build/codegen/targets/_shared/path-utils.test.js.map +1 -0
- package/build/codegen/targets/_shared/pick-defined.d.ts +11 -0
- package/build/codegen/targets/_shared/pick-defined.js +21 -0
- package/build/codegen/targets/_shared/pick-defined.js.map +1 -0
- package/build/codegen/targets/_shared/pick-defined.test.d.ts +1 -0
- package/build/codegen/targets/_shared/pick-defined.test.js +25 -0
- package/build/codegen/targets/_shared/pick-defined.test.js.map +1 -0
- package/build/codegen/targets/_shared/route-slots.d.ts +17 -0
- package/build/codegen/targets/_shared/route-slots.js +17 -0
- package/build/codegen/targets/_shared/route-slots.js.map +1 -0
- package/build/codegen/targets/_shared/route-slots.test.d.ts +1 -0
- package/build/codegen/targets/_shared/route-slots.test.js +43 -0
- package/build/codegen/targets/_shared/route-slots.test.js.map +1 -0
- package/build/codegen/targets/_shared/target-run.d.ts +27 -0
- package/build/codegen/targets/_shared/target-run.js +2 -0
- package/build/codegen/targets/_shared/target-run.js.map +1 -0
- package/build/codegen/targets/_shared/write-files.d.ts +24 -0
- package/build/codegen/targets/_shared/write-files.js +35 -0
- package/build/codegen/targets/_shared/write-files.js.map +1 -0
- package/build/codegen/targets/_shared/write-files.test.d.ts +1 -0
- package/build/codegen/targets/_shared/write-files.test.js +79 -0
- package/build/codegen/targets/_shared/write-files.test.js.map +1 -0
- package/build/codegen/targets/kotlin/ajsc-adapter.d.ts +6 -4
- package/build/codegen/targets/kotlin/ajsc-adapter.js +12 -7
- package/build/codegen/targets/kotlin/ajsc-adapter.js.map +1 -1
- package/build/codegen/targets/kotlin/ajsc-adapter.test.js +20 -2
- package/build/codegen/targets/kotlin/ajsc-adapter.test.js.map +1 -1
- package/build/codegen/targets/kotlin/e2e-compile.test.js +41 -9
- package/build/codegen/targets/kotlin/e2e-compile.test.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-route-kotlin.d.ts +6 -2
- package/build/codegen/targets/kotlin/emit-route-kotlin.js +18 -28
- package/build/codegen/targets/kotlin/emit-route-kotlin.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-route-kotlin.test.js +120 -1
- package/build/codegen/targets/kotlin/emit-route-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-scope-kotlin.d.ts +4 -1
- package/build/codegen/targets/kotlin/emit-scope-kotlin.js +12 -11
- package/build/codegen/targets/kotlin/emit-scope-kotlin.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js +39 -0
- package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/format-kotlin.d.ts +0 -1
- package/build/codegen/targets/kotlin/format-kotlin.js +0 -7
- package/build/codegen/targets/kotlin/format-kotlin.js.map +1 -1
- package/build/codegen/targets/kotlin/format-kotlin.test.js +1 -8
- package/build/codegen/targets/kotlin/format-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/integration.test.js +27 -10
- package/build/codegen/targets/kotlin/integration.test.js.map +1 -1
- package/build/codegen/targets/kotlin/probe-unsupported-unions.test.d.ts +1 -0
- package/build/codegen/targets/kotlin/probe-unsupported-unions.test.js +50 -0
- package/build/codegen/targets/kotlin/probe-unsupported-unions.test.js.map +1 -0
- package/build/codegen/targets/kotlin/run.d.ts +11 -0
- package/build/codegen/targets/kotlin/run.js +51 -0
- package/build/codegen/targets/kotlin/run.js.map +1 -0
- package/build/codegen/targets/swift/access-level.test.d.ts +1 -0
- package/build/codegen/targets/swift/access-level.test.js +98 -0
- package/build/codegen/targets/swift/access-level.test.js.map +1 -0
- package/build/codegen/targets/swift/ajsc-adapter.d.ts +27 -0
- package/build/codegen/targets/swift/ajsc-adapter.js +38 -0
- package/build/codegen/targets/swift/ajsc-adapter.js.map +1 -0
- package/build/codegen/targets/swift/ajsc-adapter.test.d.ts +1 -0
- package/build/codegen/targets/swift/ajsc-adapter.test.js +37 -0
- package/build/codegen/targets/swift/ajsc-adapter.test.js.map +1 -0
- package/build/codegen/targets/swift/e2e-compile.test.d.ts +1 -0
- package/build/codegen/targets/swift/e2e-compile.test.js +57 -0
- package/build/codegen/targets/swift/e2e-compile.test.js.map +1 -0
- package/build/codegen/targets/swift/emit-route-swift.d.ts +15 -0
- package/build/codegen/targets/swift/emit-route-swift.js +64 -0
- package/build/codegen/targets/swift/emit-route-swift.js.map +1 -0
- package/build/codegen/targets/swift/emit-route-swift.test.d.ts +1 -0
- package/build/codegen/targets/swift/emit-route-swift.test.js +258 -0
- package/build/codegen/targets/swift/emit-route-swift.test.js.map +1 -0
- package/build/codegen/targets/swift/emit-scope-swift.d.ts +13 -0
- package/build/codegen/targets/swift/emit-scope-swift.js +36 -0
- package/build/codegen/targets/swift/emit-scope-swift.js.map +1 -0
- package/build/codegen/targets/swift/emit-scope-swift.test.d.ts +1 -0
- package/build/codegen/targets/swift/emit-scope-swift.test.js +136 -0
- package/build/codegen/targets/swift/emit-scope-swift.test.js.map +1 -0
- package/build/codegen/targets/swift/format-swift.d.ts +2 -0
- package/build/codegen/targets/swift/format-swift.js +10 -0
- package/build/codegen/targets/swift/format-swift.js.map +1 -0
- package/build/codegen/targets/swift/format-swift.test.d.ts +1 -0
- package/build/codegen/targets/swift/format-swift.test.js +14 -0
- package/build/codegen/targets/swift/format-swift.test.js.map +1 -0
- package/build/codegen/targets/swift/integration.test.d.ts +1 -0
- package/build/codegen/targets/swift/integration.test.js +53 -0
- package/build/codegen/targets/swift/integration.test.js.map +1 -0
- package/build/codegen/targets/swift/run.d.ts +11 -0
- package/build/codegen/targets/swift/run.js +47 -0
- package/build/codegen/targets/swift/run.js.map +1 -0
- package/build/codegen/targets/ts/run.d.ts +4 -0
- package/build/codegen/targets/ts/run.js +86 -0
- package/build/codegen/targets/ts/run.js.map +1 -0
- package/build/codegen/test-helpers/golden.d.ts +15 -0
- package/build/codegen/test-helpers/golden.js +30 -0
- package/build/codegen/test-helpers/golden.js.map +1 -0
- package/build/codegen/test-helpers/golden.test.d.ts +1 -0
- package/build/codegen/test-helpers/golden.test.js +76 -0
- package/build/codegen/test-helpers/golden.test.js.map +1 -0
- package/docs/codegen-kotlin.md +176 -0
- package/docs/codegen-swift.md +314 -0
- package/docs/superpowers/plans/2026-04-25-ajsc-v7-kotlin-polish.md +1993 -0
- package/docs/superpowers/specs/2026-04-24-kotlin-swift-codegen-design.md +1 -1
- package/docs/superpowers/specs/2026-04-25-ajsc-v7-kotlin-polish-design.md +314 -0
- package/docs/superpowers/specs/2026-04-25-swift-codegen-design.md +264 -0
- package/package.json +2 -2
- package/src/codegen/__fixtures__/users-envelope.json +144 -0
- package/src/codegen/bin/cli.test.ts +200 -1
- package/src/codegen/bin/cli.ts +187 -0
- package/src/codegen/index.ts +50 -0
- package/src/codegen/pipeline.test.ts +175 -0
- package/src/codegen/pipeline.ts +58 -101
- package/src/codegen/targets/_shared/error-schemas.test.ts +42 -0
- package/src/codegen/targets/_shared/error-schemas.ts +17 -0
- package/src/codegen/targets/_shared/indent.test.ts +25 -0
- package/src/codegen/targets/_shared/indent.ts +12 -0
- package/src/codegen/targets/_shared/pascal-case.test.ts +30 -0
- package/src/codegen/targets/_shared/pascal-case.ts +12 -0
- package/src/codegen/targets/_shared/path-utils.test.ts +51 -0
- package/src/codegen/targets/_shared/path-utils.ts +21 -0
- package/src/codegen/targets/_shared/pick-defined.test.ts +48 -0
- package/src/codegen/targets/_shared/pick-defined.ts +23 -0
- package/src/codegen/targets/_shared/route-slots.test.ts +55 -0
- package/src/codegen/targets/_shared/route-slots.ts +32 -0
- package/src/codegen/targets/_shared/target-run.ts +28 -0
- package/src/codegen/targets/_shared/write-files.test.ts +110 -0
- package/src/codegen/targets/_shared/write-files.ts +53 -0
- package/src/codegen/targets/kotlin/__fixtures__/users-golden.kt +121 -0
- package/src/codegen/targets/kotlin/__snapshots__/probe-unsupported-unions.test.ts.snap +27 -0
- package/src/codegen/targets/kotlin/ajsc-adapter.test.ts +47 -0
- package/src/codegen/targets/kotlin/ajsc-adapter.ts +66 -0
- package/src/codegen/targets/kotlin/e2e-compile.test.ts +86 -0
- package/src/codegen/targets/kotlin/emit-route-kotlin.test.ts +239 -0
- package/src/codegen/targets/kotlin/emit-route-kotlin.ts +89 -0
- package/src/codegen/targets/kotlin/emit-scope-kotlin.test.ts +112 -0
- package/src/codegen/targets/kotlin/emit-scope-kotlin.ts +60 -0
- package/src/codegen/targets/kotlin/format-kotlin.test.ts +26 -0
- package/src/codegen/targets/kotlin/format-kotlin.ts +13 -0
- package/src/codegen/targets/kotlin/integration.test.ts +77 -0
- package/src/codegen/targets/kotlin/probe-unsupported-unions.test.ts +64 -0
- package/src/codegen/targets/kotlin/run.ts +78 -0
- package/src/codegen/targets/swift/__fixtures__/users-golden.swift +123 -0
- package/src/codegen/targets/swift/access-level.test.ts +108 -0
- package/src/codegen/targets/swift/ajsc-adapter.test.ts +47 -0
- package/src/codegen/targets/swift/ajsc-adapter.ts +67 -0
- package/src/codegen/targets/swift/e2e-compile.test.ts +66 -0
- package/src/codegen/targets/swift/emit-route-swift.test.ts +300 -0
- package/src/codegen/targets/swift/emit-route-swift.ts +90 -0
- package/src/codegen/targets/swift/emit-scope-swift.test.ts +164 -0
- package/src/codegen/targets/swift/emit-scope-swift.ts +59 -0
- package/src/codegen/targets/swift/format-swift.test.ts +23 -0
- package/src/codegen/targets/swift/format-swift.ts +9 -0
- package/src/codegen/targets/swift/integration.test.ts +80 -0
- package/src/codegen/targets/swift/run.ts +74 -0
- package/src/codegen/targets/ts/run.ts +117 -0
- package/src/codegen/test-helpers/golden.test.ts +80 -0
- package/src/codegen/test-helpers/golden.ts +34 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1",
|
|
3
|
+
"basePath": "/api",
|
|
4
|
+
"headers": [],
|
|
5
|
+
"routes": [
|
|
6
|
+
{
|
|
7
|
+
"kind": "api",
|
|
8
|
+
"name": "GetUser",
|
|
9
|
+
"scope": "users",
|
|
10
|
+
"method": "GET",
|
|
11
|
+
"fullPath": "/users/:id",
|
|
12
|
+
"schema": {
|
|
13
|
+
"input": {
|
|
14
|
+
"pathParams": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": { "id": { "type": "string" } },
|
|
17
|
+
"required": ["id"]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"returnType": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"id": { "type": "string" },
|
|
24
|
+
"name": { "type": "string" },
|
|
25
|
+
"created-at": { "type": "string", "format": "date-time" },
|
|
26
|
+
"address": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"properties": {
|
|
29
|
+
"street": { "type": "string" },
|
|
30
|
+
"city": { "type": "string" }
|
|
31
|
+
},
|
|
32
|
+
"required": ["street", "city"]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"required": ["id", "name", "created-at", "address"]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"errors": ["NotFound"]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"kind": "api",
|
|
42
|
+
"name": "CreateUser",
|
|
43
|
+
"scope": "users",
|
|
44
|
+
"method": "POST",
|
|
45
|
+
"fullPath": "/users",
|
|
46
|
+
"schema": {
|
|
47
|
+
"input": {
|
|
48
|
+
"body": {
|
|
49
|
+
"oneOf": [
|
|
50
|
+
{
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"kind": { "const": "guest" },
|
|
54
|
+
"displayName": { "type": "string" }
|
|
55
|
+
},
|
|
56
|
+
"required": ["kind", "displayName"]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"type": "object",
|
|
60
|
+
"properties": {
|
|
61
|
+
"kind": { "const": "registered" },
|
|
62
|
+
"email": { "type": "string" },
|
|
63
|
+
"name": { "type": "string" }
|
|
64
|
+
},
|
|
65
|
+
"required": ["kind", "email", "name"]
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"returnType": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"properties": { "id": { "type": "string" } },
|
|
73
|
+
"required": ["id"]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"errors": ["ValidationError"]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"kind": "api",
|
|
80
|
+
"name": "ListUsers",
|
|
81
|
+
"scope": "users",
|
|
82
|
+
"method": "GET",
|
|
83
|
+
"fullPath": "/users",
|
|
84
|
+
"schema": {
|
|
85
|
+
"input": {
|
|
86
|
+
"query": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"properties": {
|
|
89
|
+
"status": { "type": "string", "enum": ["active", "inactive"] },
|
|
90
|
+
"limit": { "type": "integer" }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"returnType": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"properties": {
|
|
97
|
+
"items": {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"properties": {
|
|
102
|
+
"id": { "type": "string" },
|
|
103
|
+
"name": { "type": "string" }
|
|
104
|
+
},
|
|
105
|
+
"required": ["id", "name"]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"required": ["items"]
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"errors": []
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"errors": [
|
|
116
|
+
{
|
|
117
|
+
"name": "NotFound",
|
|
118
|
+
"statusCode": 404,
|
|
119
|
+
"description": "Resource not found",
|
|
120
|
+
"schema": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"properties": {
|
|
123
|
+
"name": { "const": "NotFound" },
|
|
124
|
+
"message": { "type": "string" }
|
|
125
|
+
},
|
|
126
|
+
"required": ["name", "message"]
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "ValidationError",
|
|
131
|
+
"statusCode": 400,
|
|
132
|
+
"description": "Input failed validation",
|
|
133
|
+
"schema": {
|
|
134
|
+
"type": "object",
|
|
135
|
+
"properties": {
|
|
136
|
+
"name": { "const": "ValidationError" },
|
|
137
|
+
"message": { "type": "string" },
|
|
138
|
+
"field": { "type": "string" }
|
|
139
|
+
},
|
|
140
|
+
"required": ["name", "message"]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import { vi } from 'vitest'
|
|
3
|
+
import { parseArgs, loadConfigFile, extractConfigPath, printPostRunHints, warnIfKotlinNoOpFlags, type CodegenConfig } from './cli.js'
|
|
3
4
|
|
|
4
5
|
describe('parseArgs', () => {
|
|
5
6
|
it('parses --url and --out', () => {
|
|
@@ -293,3 +294,201 @@ describe('config file support', () => {
|
|
|
293
294
|
await expect(loadConfigFile('/nonexistent/config.json')).rejects.toThrow('Failed to load config')
|
|
294
295
|
})
|
|
295
296
|
})
|
|
297
|
+
|
|
298
|
+
describe('cli — kotlin target', () => {
|
|
299
|
+
it('parses --target kotlin and --kotlin-package from CLI flags', () => {
|
|
300
|
+
const args = parseArgs(
|
|
301
|
+
['--target', 'kotlin', '--kotlin-package', 'com.example.api', '--out', 'out', '--file', 'env.json'],
|
|
302
|
+
)
|
|
303
|
+
expect(args.target).toBe('kotlin')
|
|
304
|
+
expect(args.kotlin?.package).toBe('com.example.api')
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
it('reads kotlin.package from config when no CLI flag is provided', () => {
|
|
308
|
+
const config: CodegenConfig = {
|
|
309
|
+
target: 'kotlin',
|
|
310
|
+
kotlin: { package: 'com.example.api' },
|
|
311
|
+
outDir: 'out',
|
|
312
|
+
file: 'env.json',
|
|
313
|
+
}
|
|
314
|
+
const args = parseArgs(['--out', 'out', '--file', 'env.json'], config)
|
|
315
|
+
expect(args.target).toBe('kotlin')
|
|
316
|
+
expect(args.kotlin?.package).toBe('com.example.api')
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('CLI flag overrides config value', () => {
|
|
320
|
+
const config: CodegenConfig = {
|
|
321
|
+
target: 'kotlin',
|
|
322
|
+
kotlin: { package: 'old.pkg' },
|
|
323
|
+
outDir: 'out',
|
|
324
|
+
file: 'env.json',
|
|
325
|
+
}
|
|
326
|
+
const args = parseArgs(['--kotlin-package', 'new.pkg', '--out', 'out', '--file', 'env.json'], config)
|
|
327
|
+
expect(args.kotlin?.package).toBe('new.pkg')
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('errors when target is kotlin and no package is provided', () => {
|
|
331
|
+
expect(() =>
|
|
332
|
+
parseArgs(['--target', 'kotlin', '--out', 'out', '--file', 'env.json']),
|
|
333
|
+
).toThrow(/--kotlin-package/)
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
it('--target ts is the default', () => {
|
|
337
|
+
const args = parseArgs(['--out', 'out', '--file', 'env.json'])
|
|
338
|
+
expect(args.target ?? 'ts').toBe('ts')
|
|
339
|
+
})
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
describe('cli — kotlin-serializer flag', () => {
|
|
343
|
+
it('parses --kotlin-serializer kotlinx', () => {
|
|
344
|
+
const args = parseArgs(['--target', 'kotlin', '--kotlin-package', 'p', '--kotlin-serializer', 'kotlinx', '--out', 'o', '--file', 'e.json'])
|
|
345
|
+
expect(args.kotlin?.serializer).toBe('kotlinx')
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
it('parses --kotlin-serializer none', () => {
|
|
349
|
+
const args = parseArgs(['--target', 'kotlin', '--kotlin-package', 'p', '--kotlin-serializer', 'none', '--out', 'o', '--file', 'e.json'])
|
|
350
|
+
expect(args.kotlin?.serializer).toBe('none')
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('reads kotlin.serializer from config', () => {
|
|
354
|
+
const args = parseArgs(['--out', 'o', '--file', 'e.json'], {
|
|
355
|
+
target: 'kotlin', kotlin: { package: 'p', serializer: 'none' }, outDir: 'o', file: 'e.json',
|
|
356
|
+
} as CodegenConfig)
|
|
357
|
+
expect(args.kotlin?.serializer).toBe('none')
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
it('CLI overrides config', () => {
|
|
361
|
+
const args = parseArgs(['--kotlin-serializer', 'kotlinx', '--out', 'o', '--file', 'e.json'], {
|
|
362
|
+
target: 'kotlin', kotlin: { package: 'p', serializer: 'none' }, outDir: 'o', file: 'e.json',
|
|
363
|
+
} as CodegenConfig)
|
|
364
|
+
expect(args.kotlin?.serializer).toBe('kotlinx')
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
it('throws on invalid value', () => {
|
|
368
|
+
expect(() => parseArgs(['--target', 'kotlin', '--kotlin-package', 'p', '--kotlin-serializer', 'bogus', '--out', 'o', '--file', 'e.json']))
|
|
369
|
+
.toThrow(/--kotlin-serializer/)
|
|
370
|
+
})
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
describe('cli — unsupported-unions flag', () => {
|
|
374
|
+
it('parses --unsupported-unions throw', () => {
|
|
375
|
+
const args = parseArgs(['--unsupported-unions', 'throw', '--out', 'o', '--file', 'e.json'])
|
|
376
|
+
expect(args.unsupportedUnions).toBe('throw')
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
it('parses --unsupported-unions fallback', () => {
|
|
380
|
+
const args = parseArgs(['--unsupported-unions', 'fallback', '--out', 'o', '--file', 'e.json'])
|
|
381
|
+
expect(args.unsupportedUnions).toBe('fallback')
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
it('reads unsupportedUnions from config', () => {
|
|
385
|
+
const args = parseArgs(['--out', 'o', '--file', 'e.json'], {
|
|
386
|
+
unsupportedUnions: 'fallback', outDir: 'o', file: 'e.json',
|
|
387
|
+
} as CodegenConfig)
|
|
388
|
+
expect(args.unsupportedUnions).toBe('fallback')
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
it('CLI overrides config', () => {
|
|
392
|
+
const args = parseArgs(['--unsupported-unions', 'throw', '--out', 'o', '--file', 'e.json'], {
|
|
393
|
+
unsupportedUnions: 'fallback', outDir: 'o', file: 'e.json',
|
|
394
|
+
} as CodegenConfig)
|
|
395
|
+
expect(args.unsupportedUnions).toBe('throw')
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it('throws on invalid value', () => {
|
|
399
|
+
expect(() => parseArgs(['--unsupported-unions', 'bogus', '--out', 'o', '--file', 'e.json']))
|
|
400
|
+
.toThrow(/--unsupported-unions/)
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
it('default is undefined when not set', () => {
|
|
404
|
+
const args = parseArgs(['--out', 'o', '--file', 'e.json'])
|
|
405
|
+
expect(args.unsupportedUnions).toBeUndefined()
|
|
406
|
+
})
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
describe('cli — printPostRunHints', () => {
|
|
410
|
+
it('prints a setup-guide pointer for the kotlin target', () => {
|
|
411
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
|
|
412
|
+
try {
|
|
413
|
+
printPostRunHints({ target: 'kotlin' })
|
|
414
|
+
const matched = logSpy.mock.calls.some((c) => String(c[0]).includes('docs/codegen-kotlin.md'))
|
|
415
|
+
expect(matched).toBe(true)
|
|
416
|
+
} finally {
|
|
417
|
+
logSpy.mockRestore()
|
|
418
|
+
}
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
it('prints nothing for the ts target', () => {
|
|
422
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
|
|
423
|
+
try {
|
|
424
|
+
printPostRunHints({ target: 'ts' })
|
|
425
|
+
expect(logSpy).not.toHaveBeenCalled()
|
|
426
|
+
} finally {
|
|
427
|
+
logSpy.mockRestore()
|
|
428
|
+
}
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
it('prints nothing when target is undefined (default ts)', () => {
|
|
432
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
|
|
433
|
+
try {
|
|
434
|
+
printPostRunHints({})
|
|
435
|
+
expect(logSpy).not.toHaveBeenCalled()
|
|
436
|
+
} finally {
|
|
437
|
+
logSpy.mockRestore()
|
|
438
|
+
}
|
|
439
|
+
})
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
describe('cli — warnIfKotlinNoOpFlags', () => {
|
|
443
|
+
it('warns when --unsupported-unions is set with --target kotlin', () => {
|
|
444
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
445
|
+
try {
|
|
446
|
+
warnIfKotlinNoOpFlags({ target: 'kotlin', unsupportedUnions: 'fallback' })
|
|
447
|
+
const matched = warnSpy.mock.calls.some((c) => String(c[0]).includes('--unsupported-unions is currently a no-op'))
|
|
448
|
+
expect(matched).toBe(true)
|
|
449
|
+
} finally {
|
|
450
|
+
warnSpy.mockRestore()
|
|
451
|
+
}
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
it('warns when --unsupported-unions is set to throw with --target kotlin', () => {
|
|
455
|
+
// Even 'throw' is a no-op since ajsc never throws on Kotlin untagged oneOf.
|
|
456
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
457
|
+
try {
|
|
458
|
+
warnIfKotlinNoOpFlags({ target: 'kotlin', unsupportedUnions: 'throw' })
|
|
459
|
+
expect(warnSpy).toHaveBeenCalled()
|
|
460
|
+
} finally {
|
|
461
|
+
warnSpy.mockRestore()
|
|
462
|
+
}
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
it('does not warn when --unsupported-unions is unset', () => {
|
|
466
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
467
|
+
try {
|
|
468
|
+
warnIfKotlinNoOpFlags({ target: 'kotlin' })
|
|
469
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
470
|
+
} finally {
|
|
471
|
+
warnSpy.mockRestore()
|
|
472
|
+
}
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
it('does not warn for the ts target even when --unsupported-unions is set', () => {
|
|
476
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
477
|
+
try {
|
|
478
|
+
warnIfKotlinNoOpFlags({ target: 'ts', unsupportedUnions: 'fallback' })
|
|
479
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
480
|
+
} finally {
|
|
481
|
+
warnSpy.mockRestore()
|
|
482
|
+
}
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
it('does not warn when target is undefined', () => {
|
|
486
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
487
|
+
try {
|
|
488
|
+
warnIfKotlinNoOpFlags({ unsupportedUnions: 'fallback' })
|
|
489
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
490
|
+
} finally {
|
|
491
|
+
warnSpy.mockRestore()
|
|
492
|
+
}
|
|
493
|
+
})
|
|
494
|
+
})
|
package/src/codegen/bin/cli.ts
CHANGED
|
@@ -22,6 +22,10 @@ export interface CodegenConfig {
|
|
|
22
22
|
selfContained?: boolean
|
|
23
23
|
serviceName?: string
|
|
24
24
|
cleanOutDir?: boolean
|
|
25
|
+
target?: 'ts' | 'kotlin' | 'swift'
|
|
26
|
+
kotlin?: { package: string; serializer?: 'kotlinx' | 'none' }
|
|
27
|
+
swift?: { serializer?: 'codable' | 'none'; accessLevel?: 'public' | 'internal' }
|
|
28
|
+
unsupportedUnions?: 'throw' | 'fallback'
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export interface ParsedArgs {
|
|
@@ -37,6 +41,10 @@ export interface ParsedArgs {
|
|
|
37
41
|
selfContained: boolean
|
|
38
42
|
serviceName?: string
|
|
39
43
|
cleanOutDir: boolean
|
|
44
|
+
target?: 'ts' | 'kotlin' | 'swift'
|
|
45
|
+
kotlin?: { package: string; serializer?: 'kotlinx' | 'none' }
|
|
46
|
+
swift?: { serializer?: 'codable' | 'none'; accessLevel?: 'public' | 'internal' }
|
|
47
|
+
unsupportedUnions?: 'throw' | 'fallback'
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
// ---------------------------------------------------------------------------
|
|
@@ -88,6 +96,12 @@ export function parseArgs(argv: string[], config?: CodegenConfig): ParsedArgs {
|
|
|
88
96
|
let selfContained = config?.selfContained ?? true
|
|
89
97
|
let serviceName: string | undefined = config?.serviceName
|
|
90
98
|
let cleanOutDir = config?.cleanOutDir ?? false
|
|
99
|
+
let target: 'ts' | 'kotlin' | 'swift' | undefined = config?.target
|
|
100
|
+
let kotlinPackage: string | undefined = config?.kotlin?.package
|
|
101
|
+
let kotlinSerializer: 'kotlinx' | 'none' | undefined = config?.kotlin?.serializer
|
|
102
|
+
let swiftSerializer: 'codable' | 'none' | undefined = config?.swift?.serializer
|
|
103
|
+
let swiftAccessLevel: 'public' | 'internal' | undefined = config?.swift?.accessLevel
|
|
104
|
+
let unsupportedUnions: 'throw' | 'fallback' | undefined = config?.unsupportedUnions
|
|
91
105
|
let configPath: string | undefined
|
|
92
106
|
|
|
93
107
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -137,6 +151,43 @@ export function parseArgs(argv: string[], config?: CodegenConfig): ParsedArgs {
|
|
|
137
151
|
cleanOutDir = true
|
|
138
152
|
} else if (arg === '--no-clean-out-dir') {
|
|
139
153
|
cleanOutDir = false
|
|
154
|
+
} else if (arg === '--target') {
|
|
155
|
+
const val = argv[++i]
|
|
156
|
+
if (val === 'ts' || val === 'kotlin' || val === 'swift') {
|
|
157
|
+
target = val
|
|
158
|
+
} else {
|
|
159
|
+
throw new Error(`Invalid --target value: ${val ?? '(missing)'} (expected 'ts', 'kotlin', or 'swift')`)
|
|
160
|
+
}
|
|
161
|
+
} else if (arg === '--kotlin-package') {
|
|
162
|
+
kotlinPackage = argv[++i]
|
|
163
|
+
} else if (arg === '--kotlin-serializer') {
|
|
164
|
+
const val = argv[++i]
|
|
165
|
+
if (val === 'kotlinx' || val === 'none') {
|
|
166
|
+
kotlinSerializer = val
|
|
167
|
+
} else {
|
|
168
|
+
throw new Error(`Invalid --kotlin-serializer value: ${val ?? '(missing)'} (expected 'kotlinx' or 'none')`)
|
|
169
|
+
}
|
|
170
|
+
} else if (arg === '--swift-serializer') {
|
|
171
|
+
const val = argv[++i]
|
|
172
|
+
if (val === 'codable' || val === 'none') {
|
|
173
|
+
swiftSerializer = val
|
|
174
|
+
} else {
|
|
175
|
+
throw new Error(`Invalid --swift-serializer value: ${val ?? '(missing)'} (expected 'codable' or 'none')`)
|
|
176
|
+
}
|
|
177
|
+
} else if (arg === '--swift-access-level') {
|
|
178
|
+
const val = argv[++i]
|
|
179
|
+
if (val === 'public' || val === 'internal') {
|
|
180
|
+
swiftAccessLevel = val
|
|
181
|
+
} else {
|
|
182
|
+
throw new Error(`Invalid --swift-access-level value: ${val ?? '(missing)'} (expected 'public' or 'internal')`)
|
|
183
|
+
}
|
|
184
|
+
} else if (arg === '--unsupported-unions') {
|
|
185
|
+
const val = argv[++i]
|
|
186
|
+
if (val === 'throw' || val === 'fallback') {
|
|
187
|
+
unsupportedUnions = val
|
|
188
|
+
} else {
|
|
189
|
+
throw new Error(`Invalid --unsupported-unions value: ${val ?? '(missing)'} (expected 'throw' or 'fallback')`)
|
|
190
|
+
}
|
|
140
191
|
} else if (arg === '--config') {
|
|
141
192
|
configPath = argv[++i]
|
|
142
193
|
}
|
|
@@ -145,6 +196,14 @@ export function parseArgs(argv: string[], config?: CodegenConfig): ParsedArgs {
|
|
|
145
196
|
// configPath is consumed by the caller (main) before parseArgs is called with the loaded config.
|
|
146
197
|
// When called from main, config is already loaded. When called directly (tests), configPath is ignored.
|
|
147
198
|
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Validation — fails fast on user-controllable errors before envelope resolve.
|
|
201
|
+
// Runtime checks (emitter availability, etc.) happen later in pipeline.ts;
|
|
202
|
+
// those guards are aimed at non-CLI callers (direct API consumers, tests).
|
|
203
|
+
// The CLI resolves emitters before invoking `runPipeline`, so users only ever
|
|
204
|
+
// see flag-shape errors from this block, not pipeline-internal throws.
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
|
|
148
207
|
if (outDir === undefined) {
|
|
149
208
|
throw new Error('Missing required argument: --out <dir>')
|
|
150
209
|
}
|
|
@@ -153,6 +212,15 @@ export function parseArgs(argv: string[], config?: CodegenConfig): ParsedArgs {
|
|
|
153
212
|
throw new Error('Missing required input source: provide --url <url> or --file <path>')
|
|
154
213
|
}
|
|
155
214
|
|
|
215
|
+
// Kotlin target requires a package; surface this before any I/O happens.
|
|
216
|
+
if (target === 'kotlin' && (kotlinPackage === undefined || kotlinPackage === '')) {
|
|
217
|
+
throw new Error('Missing required argument: --kotlin-package <pkg> (required when --target kotlin)')
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Swift target currently has no required flags. If that changes, add the
|
|
221
|
+
// guard here so the failure mode stays consistent (flag-shape errors fire
|
|
222
|
+
// from parseArgs; runtime/emitter wiring errors fire from pipeline.ts).
|
|
223
|
+
|
|
156
224
|
return {
|
|
157
225
|
url,
|
|
158
226
|
file,
|
|
@@ -166,6 +234,24 @@ export function parseArgs(argv: string[], config?: CodegenConfig): ParsedArgs {
|
|
|
166
234
|
selfContained,
|
|
167
235
|
...(serviceName !== undefined ? { serviceName } : {}),
|
|
168
236
|
cleanOutDir,
|
|
237
|
+
...(target !== undefined ? { target } : {}),
|
|
238
|
+
...(kotlinPackage !== undefined
|
|
239
|
+
? {
|
|
240
|
+
kotlin: {
|
|
241
|
+
package: kotlinPackage,
|
|
242
|
+
...(kotlinSerializer !== undefined ? { serializer: kotlinSerializer } : {}),
|
|
243
|
+
},
|
|
244
|
+
}
|
|
245
|
+
: {}),
|
|
246
|
+
...(swiftSerializer !== undefined || swiftAccessLevel !== undefined
|
|
247
|
+
? {
|
|
248
|
+
swift: {
|
|
249
|
+
...(swiftSerializer !== undefined ? { serializer: swiftSerializer } : {}),
|
|
250
|
+
...(swiftAccessLevel !== undefined ? { accessLevel: swiftAccessLevel } : {}),
|
|
251
|
+
},
|
|
252
|
+
}
|
|
253
|
+
: {}),
|
|
254
|
+
...(unsupportedUnions !== undefined ? { unsupportedUnions } : {}),
|
|
169
255
|
}
|
|
170
256
|
}
|
|
171
257
|
|
|
@@ -201,6 +287,29 @@ async function runWithWatch(parsed: ParsedArgs): Promise<void> {
|
|
|
201
287
|
cleanOutDir: parsed.cleanOutDir,
|
|
202
288
|
}
|
|
203
289
|
|
|
290
|
+
// Resolve the kotlin emitter once at watch start; it's stateless and reused per tick.
|
|
291
|
+
const kotlinWiring =
|
|
292
|
+
parsed.target === 'kotlin'
|
|
293
|
+
? {
|
|
294
|
+
target: 'kotlin' as const,
|
|
295
|
+
kotlinPackage: parsed.kotlin!.package,
|
|
296
|
+
kotlinEmitter: await (
|
|
297
|
+
await import('../targets/kotlin/ajsc-adapter.js')
|
|
298
|
+
).resolveProductionKotlinEmitter(),
|
|
299
|
+
}
|
|
300
|
+
: {}
|
|
301
|
+
|
|
302
|
+
// Resolve the swift emitter once at watch start; it's stateless and reused per tick.
|
|
303
|
+
const swiftWiring =
|
|
304
|
+
parsed.target === 'swift'
|
|
305
|
+
? {
|
|
306
|
+
target: 'swift' as const,
|
|
307
|
+
swiftEmitter: await (
|
|
308
|
+
await import('../targets/swift/ajsc-adapter.js')
|
|
309
|
+
).resolveProductionSwiftEmitter(),
|
|
310
|
+
}
|
|
311
|
+
: {}
|
|
312
|
+
|
|
204
313
|
let lastHash: string | undefined
|
|
205
314
|
|
|
206
315
|
const run = async (): Promise<void> => {
|
|
@@ -226,6 +335,12 @@ async function runWithWatch(parsed: ParsedArgs): Promise<void> {
|
|
|
226
335
|
selfContained: parsed.selfContained,
|
|
227
336
|
serviceName: parsed.serviceName,
|
|
228
337
|
cleanOutDir: parsed.cleanOutDir,
|
|
338
|
+
...(parsed.kotlin?.serializer !== undefined ? { kotlinSerializer: parsed.kotlin.serializer } : {}),
|
|
339
|
+
...(parsed.unsupportedUnions !== undefined ? { unsupportedUnions: parsed.unsupportedUnions } : {}),
|
|
340
|
+
...(parsed.swift?.serializer !== undefined ? { swiftSerializer: parsed.swift.serializer } : {}),
|
|
341
|
+
...(parsed.swift?.accessLevel !== undefined ? { swiftAccessLevel: parsed.swift.accessLevel } : {}),
|
|
342
|
+
...kotlinWiring,
|
|
343
|
+
...swiftWiring,
|
|
229
344
|
})
|
|
230
345
|
console.log(`[ts-procedures-codegen] Generated client files → ${parsed.outDir}`)
|
|
231
346
|
} catch (err) {
|
|
@@ -243,6 +358,45 @@ async function runWithWatch(parsed: ParsedArgs): Promise<void> {
|
|
|
243
358
|
// Main
|
|
244
359
|
// ---------------------------------------------------------------------------
|
|
245
360
|
|
|
361
|
+
const KOTLIN_SETUP_GUIDE_URL =
|
|
362
|
+
'https://bitbucket.org/thermsio/ts-procedures/src/master/docs/codegen-kotlin.md'
|
|
363
|
+
|
|
364
|
+
const SWIFT_SETUP_GUIDE_URL =
|
|
365
|
+
'https://bitbucket.org/thermsio/ts-procedures/src/master/docs/codegen-swift.md'
|
|
366
|
+
|
|
367
|
+
export function printPostRunHints(parsed: { target?: 'ts' | 'kotlin' | 'swift' }): void {
|
|
368
|
+
if (parsed.target === 'kotlin') {
|
|
369
|
+
console.log(`[ts-procedures-codegen] Kotlin setup guide: ${KOTLIN_SETUP_GUIDE_URL}`)
|
|
370
|
+
}
|
|
371
|
+
if (parsed.target === 'swift') {
|
|
372
|
+
console.log(`[ts-procedures-codegen] Swift setup guide: ${SWIFT_SETUP_GUIDE_URL}`)
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Warns about flags that are currently no-ops for the Kotlin target.
|
|
378
|
+
*
|
|
379
|
+
* Scope is intentionally Kotlin-only — the param type omits `'swift'` so a
|
|
380
|
+
* reader can tell at a glance this function will never act on swift. Other
|
|
381
|
+
* targets get their own warner if/when they grow no-op flags. The call site
|
|
382
|
+
* narrows `parsed.target` before invoking.
|
|
383
|
+
*
|
|
384
|
+
* Currently: `--unsupported-unions` is a no-op because ajsc v7.2's Kotlin
|
|
385
|
+
* emitter silently emits an empty data class for untagged oneOf regardless
|
|
386
|
+
* of the flag (see docs/codegen-kotlin.md#untagged-unions).
|
|
387
|
+
*/
|
|
388
|
+
export function warnIfKotlinNoOpFlags(parsed: {
|
|
389
|
+
target?: 'ts' | 'kotlin'
|
|
390
|
+
unsupportedUnions?: 'throw' | 'fallback'
|
|
391
|
+
}): void {
|
|
392
|
+
if (parsed.target === 'kotlin' && parsed.unsupportedUnions !== undefined) {
|
|
393
|
+
console.warn(
|
|
394
|
+
'[ts-procedures-codegen] Note: --unsupported-unions is currently a no-op for --target kotlin ' +
|
|
395
|
+
'(ajsc v7.2 emits an empty data class regardless). See docs/codegen-kotlin.md#untagged-unions.',
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
246
400
|
async function main(): Promise<void> {
|
|
247
401
|
const argv = process.argv.slice(2)
|
|
248
402
|
const configPath = extractConfigPath(argv)
|
|
@@ -251,6 +405,15 @@ async function main(): Promise<void> {
|
|
|
251
405
|
console.log(`[ts-procedures-codegen] Loaded config from ${configPath ?? DEFAULT_CONFIG_NAME}`)
|
|
252
406
|
}
|
|
253
407
|
const parsed = parseArgs(argv, config)
|
|
408
|
+
// The warner is intentionally Kotlin-only; pass the relevant fields and
|
|
409
|
+
// narrow `target` away from 'swift' here so the function's param type can
|
|
410
|
+
// stay tight.
|
|
411
|
+
if (parsed.target !== 'swift') {
|
|
412
|
+
warnIfKotlinNoOpFlags({
|
|
413
|
+
target: parsed.target,
|
|
414
|
+
...(parsed.unsupportedUnions !== undefined ? { unsupportedUnions: parsed.unsupportedUnions } : {}),
|
|
415
|
+
})
|
|
416
|
+
}
|
|
254
417
|
|
|
255
418
|
const source = parsed.url ?? parsed.file!
|
|
256
419
|
console.log(`[ts-procedures-codegen] Reading docs from ${source}...`)
|
|
@@ -258,6 +421,23 @@ async function main(): Promise<void> {
|
|
|
258
421
|
if (parsed.watch) {
|
|
259
422
|
await runWithWatch(parsed)
|
|
260
423
|
} else {
|
|
424
|
+
const kotlinWiring =
|
|
425
|
+
parsed.target === 'kotlin'
|
|
426
|
+
? {
|
|
427
|
+
target: 'kotlin' as const,
|
|
428
|
+
kotlinPackage: parsed.kotlin!.package,
|
|
429
|
+
kotlinEmitter: await (await import('../targets/kotlin/ajsc-adapter.js')).resolveProductionKotlinEmitter(),
|
|
430
|
+
}
|
|
431
|
+
: {}
|
|
432
|
+
|
|
433
|
+
const swiftWiring =
|
|
434
|
+
parsed.target === 'swift'
|
|
435
|
+
? {
|
|
436
|
+
target: 'swift' as const,
|
|
437
|
+
swiftEmitter: await (await import('../targets/swift/ajsc-adapter.js')).resolveProductionSwiftEmitter(),
|
|
438
|
+
}
|
|
439
|
+
: {}
|
|
440
|
+
|
|
261
441
|
const result = await generateClient({
|
|
262
442
|
url: parsed.url,
|
|
263
443
|
file: parsed.file,
|
|
@@ -269,11 +449,18 @@ async function main(): Promise<void> {
|
|
|
269
449
|
selfContained: parsed.selfContained,
|
|
270
450
|
serviceName: parsed.serviceName,
|
|
271
451
|
cleanOutDir: parsed.cleanOutDir,
|
|
452
|
+
...(parsed.kotlin?.serializer !== undefined ? { kotlinSerializer: parsed.kotlin.serializer } : {}),
|
|
453
|
+
...(parsed.unsupportedUnions !== undefined ? { unsupportedUnions: parsed.unsupportedUnions } : {}),
|
|
454
|
+
...(parsed.swift?.serializer !== undefined ? { swiftSerializer: parsed.swift.serializer } : {}),
|
|
455
|
+
...(parsed.swift?.accessLevel !== undefined ? { swiftAccessLevel: parsed.swift.accessLevel } : {}),
|
|
456
|
+
...kotlinWiring,
|
|
457
|
+
...swiftWiring,
|
|
272
458
|
})
|
|
273
459
|
if (parsed.dryRun) {
|
|
274
460
|
console.log(`[ts-procedures-codegen] Dry run complete — ${result.length} files would be generated`)
|
|
275
461
|
} else {
|
|
276
462
|
console.log(`[ts-procedures-codegen] Generated ${result.length} files → ${parsed.outDir}`)
|
|
463
|
+
printPostRunHints(parsed)
|
|
277
464
|
}
|
|
278
465
|
}
|
|
279
466
|
}
|