ts-procedures 7.3.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -3
- package/agent_config/claude-code/agents/ts-procedures-architect.md +6 -8
- package/agent_config/claude-code/skills/ts-procedures/SKILL.md +30 -33
- package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +104 -53
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +205 -232
- package/agent_config/claude-code/skills/ts-procedures/patterns.md +80 -153
- package/agent_config/claude-code/skills/ts-procedures-review/SKILL.md +1 -1
- package/agent_config/claude-code/skills/ts-procedures-review/checklist.md +4 -5
- package/agent_config/claude-code/skills/ts-procedures-scaffold/SKILL.md +4 -7
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono.md +223 -0
- package/agent_config/copilot/copilot-instructions.md +34 -48
- package/agent_config/cursor/cursorrules +34 -48
- package/build/client/call.js +4 -1
- package/build/client/call.js.map +1 -1
- package/build/client/call.test.js +23 -0
- package/build/client/call.test.js.map +1 -1
- package/build/client/fetch-adapter.js +3 -1
- package/build/client/fetch-adapter.js.map +1 -1
- package/build/client/fetch-adapter.test.js +11 -1
- package/build/client/fetch-adapter.test.js.map +1 -1
- package/build/client/index.test.js +7 -7
- package/build/client/index.test.js.map +1 -1
- package/build/client/request-builder.d.ts +1 -1
- package/build/client/request-builder.js +2 -2
- package/build/client/request-builder.js.map +1 -1
- package/build/client/stream.js +13 -2
- package/build/client/stream.js.map +1 -1
- package/build/client/stream.test.js +32 -7
- package/build/client/stream.test.js.map +1 -1
- package/build/client/typed-error-dispatch.test.js +8 -92
- package/build/client/typed-error-dispatch.test.js.map +1 -1
- package/build/client/types.d.ts +21 -3
- package/build/codegen/bin/cli.js +0 -0
- package/build/codegen/e2e.test.js +87 -23
- package/build/codegen/e2e.test.js.map +1 -1
- package/build/codegen/emit-errors.integration.test.js +1 -1
- package/build/codegen/emit-errors.integration.test.js.map +1 -1
- package/build/codegen/emit-scope.js +308 -47
- package/build/codegen/emit-scope.js.map +1 -1
- package/build/codegen/emit-scope.test.js +363 -110
- package/build/codegen/emit-scope.test.js.map +1 -1
- package/build/codegen/pipeline.test.js +7 -7
- package/build/codegen/pipeline.test.js.map +1 -1
- package/build/codegen/resolve-envelope.js +1 -1
- package/build/codegen/resolve-envelope.js.map +1 -1
- package/build/codegen/resolve-envelope.test.js +5 -5
- package/build/codegen/resolve-envelope.test.js.map +1 -1
- package/build/codegen/targets/_shared/route-slots.d.ts +8 -3
- package/build/codegen/targets/_shared/route-slots.js +49 -8
- package/build/codegen/targets/_shared/route-slots.js.map +1 -1
- package/build/codegen/targets/_shared/route-slots.test.js +99 -26
- package/build/codegen/targets/_shared/route-slots.test.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-route-kotlin.test.js +88 -17
- package/build/codegen/targets/kotlin/emit-route-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js +9 -6
- package/build/codegen/targets/kotlin/emit-scope-kotlin.test.js.map +1 -1
- package/build/codegen/targets/kotlin/integration.test.js +6 -0
- package/build/codegen/targets/kotlin/integration.test.js.map +1 -1
- package/build/codegen/targets/swift/access-level.test.js +8 -11
- package/build/codegen/targets/swift/access-level.test.js.map +1 -1
- package/build/codegen/targets/swift/emit-route-swift.test.js +91 -20
- package/build/codegen/targets/swift/emit-route-swift.test.js.map +1 -1
- package/build/codegen/targets/swift/emit-scope-swift.test.js +12 -9
- package/build/codegen/targets/swift/emit-scope-swift.test.js.map +1 -1
- package/build/codegen/targets/swift/integration.test.js +6 -0
- package/build/codegen/targets/swift/integration.test.js.map +1 -1
- package/build/create-http-stream.d.ts +58 -0
- package/build/create-http-stream.js +122 -0
- package/build/create-http-stream.js.map +1 -0
- package/build/create-http-stream.test.js +88 -0
- package/build/create-http-stream.test.js.map +1 -0
- package/build/create-http.d.ts +49 -0
- package/build/create-http.js +108 -0
- package/build/create-http.js.map +1 -0
- package/build/create-http.test.js +137 -0
- package/build/create-http.test.js.map +1 -0
- package/build/create-stream.d.ts +35 -0
- package/build/create-stream.js +123 -0
- package/build/create-stream.js.map +1 -0
- package/build/create-stream.test.js +428 -0
- package/build/create-stream.test.js.map +1 -0
- package/build/create.d.ts +28 -0
- package/build/create.js +82 -0
- package/build/create.js.map +1 -0
- package/build/create.test.js +483 -0
- package/build/create.test.js.map +1 -0
- package/build/exports.d.ts +2 -0
- package/build/implementations/http/astro/index.test.js +20 -12
- package/build/implementations/http/astro/index.test.js.map +1 -1
- package/build/implementations/http/doc-registry.js +1 -1
- package/build/implementations/http/doc-registry.js.map +1 -1
- package/build/implementations/http/doc-registry.test.js +36 -5
- package/build/implementations/http/doc-registry.test.js.map +1 -1
- package/build/implementations/http/error-dispatch.d.ts +76 -0
- package/build/implementations/http/error-dispatch.js +77 -0
- package/build/implementations/http/error-dispatch.js.map +1 -0
- package/build/implementations/http/error-dispatch.test.js +254 -0
- package/build/implementations/http/error-dispatch.test.js.map +1 -0
- package/build/implementations/http/error-taxonomy.d.ts +5 -5
- package/build/implementations/http/hono/docs/http-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/http-doc.js +42 -0
- package/build/implementations/http/hono/docs/http-doc.js.map +1 -0
- package/build/implementations/http/hono/docs/http-stream-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/http-stream-doc.js +40 -0
- package/build/implementations/http/hono/docs/http-stream-doc.js.map +1 -0
- package/build/implementations/http/hono/docs/rpc-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/rpc-doc.js +24 -0
- package/build/implementations/http/hono/docs/rpc-doc.js.map +1 -0
- package/build/implementations/http/hono/docs/stream-doc.d.ts +6 -0
- package/build/implementations/http/hono/docs/stream-doc.js +42 -0
- package/build/implementations/http/hono/docs/stream-doc.js.map +1 -0
- package/build/implementations/http/hono/handlers/http-stream.d.ts +10 -0
- package/build/implementations/http/hono/handlers/http-stream.js +123 -0
- package/build/implementations/http/hono/handlers/http-stream.js.map +1 -0
- package/build/implementations/http/hono/handlers/http-stream.test.js +128 -0
- package/build/implementations/http/hono/handlers/http-stream.test.js.map +1 -0
- package/build/implementations/http/hono/handlers/http.d.ts +10 -0
- package/build/implementations/http/hono/handlers/http.js +115 -0
- package/build/implementations/http/hono/handlers/http.js.map +1 -0
- package/build/implementations/http/hono/handlers/http.test.js +118 -0
- package/build/implementations/http/hono/handlers/http.test.js.map +1 -0
- package/build/implementations/http/hono/handlers/rpc.d.ts +11 -0
- package/build/implementations/http/hono/handlers/rpc.js +32 -0
- package/build/implementations/http/hono/handlers/rpc.js.map +1 -0
- package/build/implementations/http/hono/handlers/rpc.test.js +73 -0
- package/build/implementations/http/hono/handlers/rpc.test.js.map +1 -0
- package/build/implementations/http/hono/handlers/stream.d.ts +23 -0
- package/build/implementations/http/hono/handlers/stream.js +147 -0
- package/build/implementations/http/hono/handlers/stream.js.map +1 -0
- package/build/implementations/http/hono/handlers/stream.test.d.ts +1 -0
- package/build/implementations/http/hono/handlers/stream.test.js +177 -0
- package/build/implementations/http/hono/handlers/stream.test.js.map +1 -0
- package/build/implementations/http/hono/index.d.ts +57 -0
- package/build/implementations/http/hono/index.js +149 -0
- package/build/implementations/http/hono/index.js.map +1 -0
- package/build/implementations/http/hono/index.test.d.ts +1 -0
- package/build/implementations/http/hono/index.test.js +274 -0
- package/build/implementations/http/hono/index.test.js.map +1 -0
- package/build/implementations/http/hono/path.d.ts +17 -0
- package/build/implementations/http/hono/path.js +39 -0
- package/build/implementations/http/hono/path.js.map +1 -0
- package/build/implementations/http/hono/path.test.d.ts +1 -0
- package/build/implementations/http/hono/path.test.js +83 -0
- package/build/implementations/http/hono/path.test.js.map +1 -0
- package/build/implementations/http/hono/types.d.ts +51 -0
- package/build/implementations/http/hono/types.js.map +1 -0
- package/build/implementations/http/on-request-error.test.js +6 -96
- package/build/implementations/http/on-request-error.test.js.map +1 -1
- package/build/implementations/http/route-errors.test.js +11 -59
- package/build/implementations/http/route-errors.test.js.map +1 -1
- package/build/implementations/types.d.ts +43 -9
- package/build/index.d.ts +124 -124
- package/build/index.js +10 -221
- package/build/index.js.map +1 -1
- package/build/index.test.js +20 -919
- package/build/index.test.js.map +1 -1
- package/build/migration.test.d.ts +1 -0
- package/build/migration.test.js +34 -0
- package/build/migration.test.js.map +1 -0
- package/build/schema/compute-schema.d.ts +11 -3
- package/build/schema/compute-schema.js +13 -7
- package/build/schema/compute-schema.js.map +1 -1
- package/build/schema/parser.d.ts +11 -3
- package/build/schema/parser.js +49 -9
- package/build/schema/parser.js.map +1 -1
- package/build/stack-utils.js +8 -0
- package/build/stack-utils.js.map +1 -1
- package/build/types.d.ts +142 -0
- package/build/types.js.map +1 -0
- package/docs/astro-adapter.md +5 -5
- package/docs/core.md +15 -17
- package/docs/http-integrations.md +83 -170
- package/docs/streaming.md +3 -60
- package/docs/superpowers/plans/2026-05-07-astro-adapter.md +2 -7
- package/docs/superpowers/plans/2026-05-08-create-http.md +3355 -0
- package/docs/superpowers/plans/2026-05-08-hono-app-builder-convergence.md +3365 -0
- package/docs/superpowers/specs/2026-05-07-astro-adapter-design.md +1 -3
- package/docs/superpowers/specs/2026-05-08-create-http-design.md +409 -0
- package/docs/superpowers/specs/2026-05-08-hono-app-builder-convergence-design.md +411 -0
- package/package.json +4 -22
- package/src/client/call.test.ts +26 -0
- package/src/client/call.ts +4 -1
- package/src/client/fetch-adapter.test.ts +14 -1
- package/src/client/fetch-adapter.ts +3 -1
- package/src/client/index.test.ts +7 -7
- package/src/client/request-builder.ts +2 -2
- package/src/client/stream.test.ts +39 -7
- package/src/client/stream.ts +16 -2
- package/src/client/typed-error-dispatch.test.ts +7 -97
- package/src/client/types.ts +21 -3
- package/src/codegen/__fixtures__/users-envelope.json +119 -38
- package/src/codegen/e2e.test.ts +98 -24
- package/src/codegen/emit-errors.integration.test.ts +1 -1
- package/src/codegen/emit-scope.test.ts +395 -110
- package/src/codegen/emit-scope.ts +350 -55
- package/src/codegen/pipeline.test.ts +7 -7
- package/src/codegen/resolve-envelope.test.ts +5 -5
- package/src/codegen/resolve-envelope.ts +1 -1
- package/src/codegen/targets/_shared/route-slots.test.ts +109 -26
- package/src/codegen/targets/_shared/route-slots.ts +48 -11
- package/src/codegen/targets/kotlin/__fixtures__/users-golden.kt +73 -0
- package/src/codegen/targets/kotlin/emit-route-kotlin.test.ts +100 -17
- package/src/codegen/targets/kotlin/emit-scope-kotlin.test.ts +9 -6
- package/src/codegen/targets/kotlin/integration.test.ts +19 -0
- package/src/codegen/targets/swift/__fixtures__/users-golden.swift +79 -0
- package/src/codegen/targets/swift/access-level.test.ts +8 -11
- package/src/codegen/targets/swift/emit-route-swift.test.ts +103 -20
- package/src/codegen/targets/swift/emit-scope-swift.test.ts +12 -9
- package/src/codegen/targets/swift/integration.test.ts +17 -0
- package/src/create-http-stream.test.ts +97 -0
- package/src/create-http-stream.ts +191 -0
- package/src/create-http.test.ts +163 -0
- package/src/create-http.ts +211 -0
- package/src/create-stream.test.ts +565 -0
- package/src/create-stream.ts +228 -0
- package/src/create.test.ts +658 -0
- package/src/create.ts +172 -0
- package/src/exports.ts +2 -0
- package/src/implementations/http/README.md +135 -95
- package/src/implementations/http/astro/README.md +4 -5
- package/src/implementations/http/astro/index.test.ts +25 -18
- package/src/implementations/http/doc-registry.test.ts +42 -5
- package/src/implementations/http/doc-registry.ts +1 -1
- package/src/implementations/http/error-dispatch.test.ts +283 -0
- package/src/implementations/http/error-dispatch.ts +176 -0
- package/src/implementations/http/error-taxonomy.ts +5 -5
- package/src/implementations/http/hono/docs/http-doc.ts +43 -0
- package/src/implementations/http/hono/docs/http-stream-doc.ts +44 -0
- package/src/implementations/http/hono/docs/rpc-doc.ts +34 -0
- package/src/implementations/http/hono/docs/stream-doc.ts +53 -0
- package/src/implementations/http/hono/handlers/http-stream.test.ts +150 -0
- package/src/implementations/http/hono/handlers/http-stream.ts +152 -0
- package/src/implementations/http/hono/handlers/http.test.ts +130 -0
- package/src/implementations/http/hono/handlers/http.ts +147 -0
- package/src/implementations/http/hono/handlers/rpc.test.ts +81 -0
- package/src/implementations/http/hono/handlers/rpc.ts +54 -0
- package/src/implementations/http/hono/handlers/stream.test.ts +198 -0
- package/src/implementations/http/hono/handlers/stream.ts +208 -0
- package/src/implementations/http/hono/index.test.ts +329 -0
- package/src/implementations/http/hono/index.ts +204 -0
- package/src/implementations/http/hono/path.test.ts +96 -0
- package/src/implementations/http/hono/path.ts +59 -0
- package/src/implementations/http/hono/types.ts +93 -0
- package/src/implementations/http/on-request-error.test.ts +10 -116
- package/src/implementations/http/route-errors.test.ts +11 -77
- package/src/implementations/types.ts +44 -9
- package/src/index.test.ts +22 -1249
- package/src/index.ts +49 -485
- package/src/migration.test.ts +48 -0
- package/src/schema/compute-schema.ts +26 -12
- package/src/schema/parser.ts +62 -12
- package/src/stack-utils.ts +8 -0
- package/src/types.ts +133 -0
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/express-rpc.md +0 -137
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-api.md +0 -173
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-rpc.md +0 -142
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-stream.md +0 -147
- package/build/implementations/http/express-rpc/error-taxonomy.test.js +0 -83
- package/build/implementations/http/express-rpc/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/express-rpc/index.d.ts +0 -125
- package/build/implementations/http/express-rpc/index.js +0 -216
- package/build/implementations/http/express-rpc/index.js.map +0 -1
- package/build/implementations/http/express-rpc/index.test.js +0 -684
- package/build/implementations/http/express-rpc/index.test.js.map +0 -1
- package/build/implementations/http/express-rpc/types.d.ts +0 -11
- package/build/implementations/http/express-rpc/types.js.map +0 -1
- package/build/implementations/http/hono-api/error-taxonomy.test.js +0 -137
- package/build/implementations/http/hono-api/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono-api/index.d.ts +0 -151
- package/build/implementations/http/hono-api/index.js +0 -344
- package/build/implementations/http/hono-api/index.js.map +0 -1
- package/build/implementations/http/hono-api/index.test.js +0 -992
- package/build/implementations/http/hono-api/index.test.js.map +0 -1
- package/build/implementations/http/hono-api/types.d.ts +0 -13
- package/build/implementations/http/hono-api/types.js.map +0 -1
- package/build/implementations/http/hono-rpc/error-taxonomy.test.js +0 -64
- package/build/implementations/http/hono-rpc/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono-rpc/index.d.ts +0 -130
- package/build/implementations/http/hono-rpc/index.js +0 -209
- package/build/implementations/http/hono-rpc/index.js.map +0 -1
- package/build/implementations/http/hono-rpc/index.test.js +0 -828
- package/build/implementations/http/hono-rpc/index.test.js.map +0 -1
- package/build/implementations/http/hono-rpc/types.d.ts +0 -11
- package/build/implementations/http/hono-rpc/types.js +0 -2
- package/build/implementations/http/hono-rpc/types.js.map +0 -1
- package/build/implementations/http/hono-stream/error-taxonomy.test.js +0 -159
- package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +0 -1
- package/build/implementations/http/hono-stream/index.d.ts +0 -171
- package/build/implementations/http/hono-stream/index.js +0 -415
- package/build/implementations/http/hono-stream/index.js.map +0 -1
- package/build/implementations/http/hono-stream/index.test.js +0 -1383
- package/build/implementations/http/hono-stream/index.test.js.map +0 -1
- package/build/implementations/http/hono-stream/types.d.ts +0 -15
- package/build/implementations/http/hono-stream/types.js +0 -2
- package/build/implementations/http/hono-stream/types.js.map +0 -1
- package/src/implementations/http/express-rpc/README.md +0 -280
- package/src/implementations/http/express-rpc/error-taxonomy.test.ts +0 -103
- package/src/implementations/http/express-rpc/index.test.ts +0 -957
- package/src/implementations/http/express-rpc/index.ts +0 -327
- package/src/implementations/http/express-rpc/types.ts +0 -16
- package/src/implementations/http/hono-api/README.md +0 -284
- package/src/implementations/http/hono-api/error-taxonomy.test.ts +0 -179
- package/src/implementations/http/hono-api/index.test.ts +0 -1341
- package/src/implementations/http/hono-api/index.ts +0 -519
- package/src/implementations/http/hono-api/types.ts +0 -16
- package/src/implementations/http/hono-rpc/README.md +0 -357
- package/src/implementations/http/hono-rpc/error-taxonomy.test.ts +0 -82
- package/src/implementations/http/hono-rpc/index.test.ts +0 -1107
- package/src/implementations/http/hono-rpc/index.ts +0 -320
- package/src/implementations/http/hono-rpc/types.ts +0 -16
- package/src/implementations/http/hono-stream/README.md +0 -559
- package/src/implementations/http/hono-stream/error-taxonomy.test.ts +0 -178
- package/src/implementations/http/hono-stream/index.test.ts +0 -1804
- package/src/implementations/http/hono-stream/index.ts +0 -622
- package/src/implementations/http/hono-stream/types.ts +0 -20
- /package/build/{implementations/http/express-rpc/error-taxonomy.test.d.ts → create-http-stream.test.d.ts} +0 -0
- /package/build/{implementations/http/express-rpc/index.test.d.ts → create-http.test.d.ts} +0 -0
- /package/build/{implementations/http/hono-api/error-taxonomy.test.d.ts → create-stream.test.d.ts} +0 -0
- /package/build/{implementations/http/hono-api/index.test.d.ts → create.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-rpc/error-taxonomy.test.d.ts → error-dispatch.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-rpc/index.test.d.ts → hono/handlers/http-stream.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-stream/error-taxonomy.test.d.ts → hono/handlers/http.test.d.ts} +0 -0
- /package/build/implementations/http/{hono-stream/index.test.d.ts → hono/handlers/rpc.test.d.ts} +0 -0
- /package/build/implementations/http/{express-rpc → hono}/types.js +0 -0
- /package/build/{implementations/http/hono-api/types.js → types.js} +0 -0
|
@@ -41,20 +41,24 @@ const apiGroup = {
|
|
|
41
41
|
fullPath: '/api/posts/:id',
|
|
42
42
|
scope: 'posts',
|
|
43
43
|
jsonSchema: {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
req: {
|
|
45
|
+
pathParams: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: { id: { type: 'string' } },
|
|
48
|
+
required: ['id'],
|
|
49
|
+
},
|
|
50
|
+
body: {
|
|
51
|
+
type: 'object',
|
|
52
|
+
properties: { title: { type: 'string' } },
|
|
53
|
+
required: ['title'],
|
|
54
|
+
},
|
|
53
55
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
res: {
|
|
57
|
+
body: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: { id: { type: 'string' }, title: { type: 'string' } },
|
|
60
|
+
required: ['id', 'title'],
|
|
61
|
+
},
|
|
58
62
|
},
|
|
59
63
|
},
|
|
60
64
|
},
|
|
@@ -286,20 +290,20 @@ describe('emitScopeFile', () => {
|
|
|
286
290
|
});
|
|
287
291
|
});
|
|
288
292
|
describe('API scope', () => {
|
|
289
|
-
it('generates
|
|
293
|
+
it('generates Req-prefixed channel types in flat mode', async () => {
|
|
290
294
|
const output = await emitScopeFile(apiGroup);
|
|
291
|
-
expect(output).toContain('export type
|
|
292
|
-
expect(output).toContain('export type
|
|
295
|
+
expect(output).toContain('export type UpdatePostReqPathParams');
|
|
296
|
+
expect(output).toContain('export type UpdatePostReqBody');
|
|
293
297
|
});
|
|
294
|
-
it('composes structured
|
|
298
|
+
it('composes structured Req type in flat mode', async () => {
|
|
295
299
|
const output = await emitScopeFile(apiGroup);
|
|
296
|
-
expect(output).toContain('export type
|
|
297
|
-
expect(output).toContain('pathParams:
|
|
298
|
-
expect(output).toContain('body:
|
|
300
|
+
expect(output).toContain('export type UpdatePostReq =');
|
|
301
|
+
expect(output).toContain('pathParams: UpdatePostReqPathParams');
|
|
302
|
+
expect(output).toContain('body: UpdatePostReqBody');
|
|
299
303
|
});
|
|
300
|
-
it('exports response type', async () => {
|
|
304
|
+
it('exports response body type with Response prefix in flat mode', async () => {
|
|
301
305
|
const output = await emitScopeFile(apiGroup);
|
|
302
|
-
expect(output).toContain('export type
|
|
306
|
+
expect(output).toContain('export type UpdatePostResponseBody');
|
|
303
307
|
});
|
|
304
308
|
it('callable uses client.bindCallable with kind: api', async () => {
|
|
305
309
|
const output = await emitScopeFile(apiGroup);
|
|
@@ -403,22 +407,25 @@ describe('emitScopeFile', () => {
|
|
|
403
407
|
});
|
|
404
408
|
});
|
|
405
409
|
describe('API scope', () => {
|
|
406
|
-
it('wraps channel types
|
|
410
|
+
it('wraps channel types in nested Req/Response sub-namespaces inside route namespace', async () => {
|
|
407
411
|
const output = await emitScopeFile(apiGroup, { namespaceTypes: true });
|
|
408
412
|
expect(output).toContain('export namespace Posts {');
|
|
409
|
-
expect(output).toContain('
|
|
413
|
+
expect(output).toContain('export namespace UpdatePost {');
|
|
414
|
+
expect(output).toContain('export namespace Req {');
|
|
415
|
+
expect(output).toContain('export namespace Response {');
|
|
410
416
|
expect(output).toContain('export type PathParams =');
|
|
411
417
|
expect(output).toContain('export type Body =');
|
|
412
|
-
|
|
418
|
+
// Response body is emitted inside Response sub-namespace
|
|
419
|
+
expect(output).toContain('export type Body =');
|
|
413
420
|
});
|
|
414
|
-
it('
|
|
421
|
+
it('callable uses Req sub-namespace as params type', async () => {
|
|
415
422
|
const output = await emitScopeFile(apiGroup, { namespaceTypes: true });
|
|
416
|
-
expect(output).toContain('
|
|
423
|
+
expect(output).toContain('Posts.UpdatePost.Req');
|
|
417
424
|
});
|
|
418
425
|
it('callable references fully qualified namespace types', async () => {
|
|
419
426
|
const output = await emitScopeFile(apiGroup, { namespaceTypes: true });
|
|
420
|
-
//
|
|
421
|
-
expect(output).toContain('client.bindCallable<Posts.UpdatePost.
|
|
427
|
+
// Params type is Posts.UpdatePost.Req; return is Posts.UpdatePost.Response.Body (body only)
|
|
428
|
+
expect(output).toContain('client.bindCallable<Posts.UpdatePost.Req, Posts.UpdatePost.Response.Body>');
|
|
422
429
|
});
|
|
423
430
|
});
|
|
424
431
|
describe('Stream scope', () => {
|
|
@@ -700,20 +707,24 @@ const apiGroupWithErrors = {
|
|
|
700
707
|
scope: 'posts',
|
|
701
708
|
errors: ['NotFound'],
|
|
702
709
|
jsonSchema: {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
710
|
+
req: {
|
|
711
|
+
pathParams: {
|
|
712
|
+
type: 'object',
|
|
713
|
+
properties: { id: { type: 'string' } },
|
|
714
|
+
required: ['id'],
|
|
715
|
+
},
|
|
716
|
+
body: {
|
|
717
|
+
type: 'object',
|
|
718
|
+
properties: { title: { type: 'string' } },
|
|
719
|
+
required: ['title'],
|
|
720
|
+
},
|
|
712
721
|
},
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
722
|
+
res: {
|
|
723
|
+
body: {
|
|
724
|
+
type: 'object',
|
|
725
|
+
properties: { id: { type: 'string' }, title: { type: 'string' } },
|
|
726
|
+
required: ['id', 'title'],
|
|
727
|
+
},
|
|
717
728
|
},
|
|
718
729
|
},
|
|
719
730
|
},
|
|
@@ -731,20 +742,24 @@ const apiGroupNoErrors = {
|
|
|
731
742
|
fullPath: '/api/posts/:id',
|
|
732
743
|
scope: 'posts',
|
|
733
744
|
jsonSchema: {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
745
|
+
req: {
|
|
746
|
+
pathParams: {
|
|
747
|
+
type: 'object',
|
|
748
|
+
properties: { id: { type: 'string' } },
|
|
749
|
+
required: ['id'],
|
|
750
|
+
},
|
|
751
|
+
body: {
|
|
752
|
+
type: 'object',
|
|
753
|
+
properties: { title: { type: 'string' } },
|
|
754
|
+
required: ['title'],
|
|
755
|
+
},
|
|
743
756
|
},
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
757
|
+
res: {
|
|
758
|
+
body: {
|
|
759
|
+
type: 'object',
|
|
760
|
+
properties: { id: { type: 'string' }, title: { type: 'string' } },
|
|
761
|
+
required: ['id', 'title'],
|
|
762
|
+
},
|
|
748
763
|
},
|
|
749
764
|
},
|
|
750
765
|
},
|
|
@@ -757,7 +772,7 @@ describe('emitScopeFile .safe sibling on API', () => {
|
|
|
757
772
|
errorKeys: new Set(['NotFound']),
|
|
758
773
|
serviceName: 'Api',
|
|
759
774
|
});
|
|
760
|
-
// With errors: uses bindCallableTyped<
|
|
775
|
+
// With errors: uses bindCallableTyped<Req, ReturnType, Errors>
|
|
761
776
|
expect(out).toContain('client.bindCallableTyped<');
|
|
762
777
|
// No Object.assign in generated output
|
|
763
778
|
expect(out).not.toContain('Object.assign');
|
|
@@ -767,7 +782,7 @@ describe('emitScopeFile .safe sibling on API', () => {
|
|
|
767
782
|
namespaceTypes: true,
|
|
768
783
|
serviceName: 'Api',
|
|
769
784
|
});
|
|
770
|
-
// Without errors: uses bindCallable<
|
|
785
|
+
// Without errors: uses bindCallable<Req, ReturnType>
|
|
771
786
|
expect(out).toContain('client.bindCallable<');
|
|
772
787
|
// No Object.assign in generated output
|
|
773
788
|
expect(out).not.toContain('Object.assign');
|
|
@@ -779,7 +794,8 @@ describe('emitScopeFile .safe sibling on API', () => {
|
|
|
779
794
|
serviceName: 'Api',
|
|
780
795
|
});
|
|
781
796
|
// errorsRef in namespace mode is the route's Errors type alias: Scope.Route.Errors
|
|
782
|
-
|
|
797
|
+
// Params is Req sub-namespace; return is Response.Body (body-only)
|
|
798
|
+
expect(out).toContain('client.bindCallableTyped<Posts.UpdatePost.Req, Posts.UpdatePost.Response.Body, Posts.UpdatePost.Errors>');
|
|
783
799
|
});
|
|
784
800
|
it('flat mode: uses route Errors type alias as third type arg', async () => {
|
|
785
801
|
const out = await emitScopeFile(apiGroupWithErrors, {
|
|
@@ -788,7 +804,8 @@ describe('emitScopeFile .safe sibling on API', () => {
|
|
|
788
804
|
serviceName: 'Api',
|
|
789
805
|
});
|
|
790
806
|
// errorsRef in flat mode is the injected UpdatePostErrors type alias
|
|
791
|
-
|
|
807
|
+
// Params is UpdatePostReq; return is UpdatePostResponseBody (body-only)
|
|
808
|
+
expect(out).toContain('client.bindCallableTyped<UpdatePostReq, UpdatePostResponseBody, UpdatePostErrors>');
|
|
792
809
|
});
|
|
793
810
|
it('route with errors uses bindCallableTyped', async () => {
|
|
794
811
|
const out = await emitScopeFile(apiGroupWithErrors, {
|
|
@@ -875,39 +892,43 @@ const apiGroupScopeCollision = {
|
|
|
875
892
|
fullPath: '/api/keys',
|
|
876
893
|
scope: 'keys',
|
|
877
894
|
jsonSchema: {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
895
|
+
req: {
|
|
896
|
+
// Body has a property literally named `scope` whose value is an object —
|
|
897
|
+
// ajsc with inlineTypes:false extracts `export type Scope = {...}`.
|
|
898
|
+
body: {
|
|
899
|
+
type: 'object',
|
|
900
|
+
properties: {
|
|
901
|
+
scope: {
|
|
902
|
+
type: 'object',
|
|
903
|
+
properties: { resource: { type: 'string' }, action: { type: 'string' } },
|
|
904
|
+
required: ['resource', 'action'],
|
|
905
|
+
},
|
|
887
906
|
},
|
|
907
|
+
required: ['scope'],
|
|
888
908
|
},
|
|
889
|
-
required: ['scope'],
|
|
890
909
|
},
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
910
|
+
res: {
|
|
911
|
+
// Response also contains a property named `scope`, but with a DIFFERENT
|
|
912
|
+
// shape (additional `grantedAt` field). ajsc extracts a second
|
|
913
|
+
// `export type Scope = {...}` whose body string differs from the body's
|
|
914
|
+
// `Scope`, so the dedup-by-string-equality in formatTypes does not
|
|
915
|
+
// collapse them — both end up in the namespace.
|
|
916
|
+
body: {
|
|
917
|
+
type: 'object',
|
|
918
|
+
properties: {
|
|
919
|
+
id: { type: 'string' },
|
|
920
|
+
scope: {
|
|
921
|
+
type: 'object',
|
|
922
|
+
properties: {
|
|
923
|
+
resource: { type: 'string' },
|
|
924
|
+
action: { type: 'string' },
|
|
925
|
+
grantedAt: { type: 'string' },
|
|
926
|
+
},
|
|
927
|
+
required: ['resource', 'action', 'grantedAt'],
|
|
906
928
|
},
|
|
907
|
-
required: ['resource', 'action', 'grantedAt'],
|
|
908
929
|
},
|
|
930
|
+
required: ['id', 'scope'],
|
|
909
931
|
},
|
|
910
|
-
required: ['id', 'scope'],
|
|
911
932
|
},
|
|
912
933
|
},
|
|
913
934
|
},
|
|
@@ -925,26 +946,30 @@ const apiGroupParamsCollision = {
|
|
|
925
946
|
fullPath: '/api/schemas',
|
|
926
947
|
scope: 'schemas',
|
|
927
948
|
jsonSchema: {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
949
|
+
req: {
|
|
950
|
+
// Body has a property literally named `params` — ajsc extracts
|
|
951
|
+
// `export type Params = {...}`. With the new nested Req namespace,
|
|
952
|
+
// the `Params` sub-type lives inside `Req {}` and does not collide
|
|
953
|
+
// with the route-level structured type (which no longer exists as `Params`).
|
|
954
|
+
body: {
|
|
955
|
+
type: 'object',
|
|
956
|
+
properties: {
|
|
957
|
+
name: { type: 'string' },
|
|
958
|
+
params: {
|
|
959
|
+
type: 'object',
|
|
960
|
+
properties: { kind: { type: 'string' } },
|
|
961
|
+
required: ['kind'],
|
|
962
|
+
},
|
|
940
963
|
},
|
|
964
|
+
required: ['name', 'params'],
|
|
941
965
|
},
|
|
942
|
-
required: ['name', 'params'],
|
|
943
966
|
},
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
967
|
+
res: {
|
|
968
|
+
body: {
|
|
969
|
+
type: 'object',
|
|
970
|
+
properties: { id: { type: 'string' } },
|
|
971
|
+
required: ['id'],
|
|
972
|
+
},
|
|
948
973
|
},
|
|
949
974
|
},
|
|
950
975
|
},
|
|
@@ -962,16 +987,22 @@ describe('emitScopeFile (bug repro: duplicate identifiers in namespace)', () =>
|
|
|
962
987
|
// one `export type Params` inside the CreateSchema namespace.
|
|
963
988
|
expect(countTypeDeclarations(out, 'Params')).toBe(1);
|
|
964
989
|
});
|
|
965
|
-
it('does not emit two `export type Scope`
|
|
990
|
+
it('does not emit two `export type Scope` for API routes with `scope` properties in both req and res (now in separate sub-namespaces)', async () => {
|
|
966
991
|
const out = await emitScopeFile(apiGroupScopeCollision, { namespaceTypes: true });
|
|
967
|
-
//
|
|
968
|
-
//
|
|
969
|
-
|
|
992
|
+
// With the new Req/Response sub-namespace structure, the body's `scope`
|
|
993
|
+
// sub-type lives in `Req {}` and the response's `scope` sub-type lives in
|
|
994
|
+
// `Response {}` — they're in separate namespaces and do not collide. Each
|
|
995
|
+
// sub-namespace can have at most one `Scope` (the rename guard still applies
|
|
996
|
+
// within each sub-namespace). Total count across the file can be 2 (one in
|
|
997
|
+
// each sub-namespace).
|
|
998
|
+
expect(countTypeDeclarations(out, 'Scope')).toBeGreaterThanOrEqual(1);
|
|
999
|
+
expect(countTypeDeclarations(out, 'Scope')).toBeLessThanOrEqual(2);
|
|
970
1000
|
});
|
|
971
|
-
it('does not emit two `export type Params` inside
|
|
1001
|
+
it('does not emit two `export type Params` inside the Req sub-namespace when the body has a `params` property (API)', async () => {
|
|
972
1002
|
const out = await emitScopeFile(apiGroupParamsCollision, { namespaceTypes: true });
|
|
973
|
-
// One extracted `Params` (from body.params property)
|
|
974
|
-
//
|
|
1003
|
+
// One extracted `Params` (from body.params property) — lives inside `Req {}`.
|
|
1004
|
+
// No separate structured Params injection at the route level any more.
|
|
1005
|
+
// The rename guard inside formatSubNamespace ensures at most 1 `Params` in Req.
|
|
975
1006
|
expect(countTypeDeclarations(out, 'Params')).toBe(1);
|
|
976
1007
|
});
|
|
977
1008
|
});
|
|
@@ -1014,4 +1045,226 @@ describe('emitScopeFile streams omit .safe sibling', () => {
|
|
|
1014
1045
|
expect(out).not.toMatch(/WatchEvents\s*:\s*client\.bindCallable/);
|
|
1015
1046
|
});
|
|
1016
1047
|
});
|
|
1048
|
+
const apiGroupBodyOnly = {
|
|
1049
|
+
scopeKey: 'reports',
|
|
1050
|
+
camelCase: 'reports',
|
|
1051
|
+
routes: [
|
|
1052
|
+
{
|
|
1053
|
+
kind: 'api',
|
|
1054
|
+
name: 'GetReport',
|
|
1055
|
+
path: '/reports/:id',
|
|
1056
|
+
method: 'get',
|
|
1057
|
+
fullPath: '/api/reports/:id',
|
|
1058
|
+
scope: 'reports',
|
|
1059
|
+
jsonSchema: {
|
|
1060
|
+
req: { pathParams: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] } },
|
|
1061
|
+
res: { body: { type: 'object', properties: { data: { type: 'string' } }, required: ['data'] } },
|
|
1062
|
+
},
|
|
1063
|
+
},
|
|
1064
|
+
],
|
|
1065
|
+
};
|
|
1066
|
+
const apiGroupBothBodyAndHeaders = {
|
|
1067
|
+
scopeKey: 'downloads',
|
|
1068
|
+
camelCase: 'downloads',
|
|
1069
|
+
routes: [
|
|
1070
|
+
{
|
|
1071
|
+
kind: 'api',
|
|
1072
|
+
name: 'GetDownload',
|
|
1073
|
+
path: '/downloads/:id',
|
|
1074
|
+
method: 'get',
|
|
1075
|
+
fullPath: '/api/downloads/:id',
|
|
1076
|
+
scope: 'downloads',
|
|
1077
|
+
jsonSchema: {
|
|
1078
|
+
req: { pathParams: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] } },
|
|
1079
|
+
res: {
|
|
1080
|
+
body: { type: 'object', properties: { url: { type: 'string' } }, required: ['url'] },
|
|
1081
|
+
headers: { type: 'object', properties: { 'x-token': { type: 'string' } }, required: ['x-token'] },
|
|
1082
|
+
},
|
|
1083
|
+
},
|
|
1084
|
+
},
|
|
1085
|
+
],
|
|
1086
|
+
};
|
|
1087
|
+
const apiGroupHeadersOnly = {
|
|
1088
|
+
scopeKey: 'preflight',
|
|
1089
|
+
camelCase: 'preflight',
|
|
1090
|
+
routes: [
|
|
1091
|
+
{
|
|
1092
|
+
kind: 'api',
|
|
1093
|
+
name: 'GetPreflight',
|
|
1094
|
+
path: '/preflight',
|
|
1095
|
+
method: 'get',
|
|
1096
|
+
fullPath: '/api/preflight',
|
|
1097
|
+
scope: 'preflight',
|
|
1098
|
+
jsonSchema: {
|
|
1099
|
+
req: {},
|
|
1100
|
+
res: { headers: { type: 'object', properties: { 'x-allowed': { type: 'string' } }, required: ['x-allowed'] } },
|
|
1101
|
+
},
|
|
1102
|
+
},
|
|
1103
|
+
],
|
|
1104
|
+
};
|
|
1105
|
+
const apiGroupNoBody = {
|
|
1106
|
+
scopeKey: 'pings',
|
|
1107
|
+
camelCase: 'pings',
|
|
1108
|
+
routes: [
|
|
1109
|
+
{
|
|
1110
|
+
kind: 'api',
|
|
1111
|
+
name: 'Ping',
|
|
1112
|
+
path: '/ping',
|
|
1113
|
+
method: 'get',
|
|
1114
|
+
fullPath: '/api/ping',
|
|
1115
|
+
scope: 'pings',
|
|
1116
|
+
jsonSchema: { req: {}, res: {} },
|
|
1117
|
+
},
|
|
1118
|
+
],
|
|
1119
|
+
};
|
|
1120
|
+
describe('emitScopeFile API conditional return type', () => {
|
|
1121
|
+
describe('flat mode', () => {
|
|
1122
|
+
it('body-only: return type is the body type', async () => {
|
|
1123
|
+
const out = await emitScopeFile(apiGroupBodyOnly);
|
|
1124
|
+
expect(out).toContain('export type GetReportResponseBody =');
|
|
1125
|
+
expect(out).toContain('client.bindCallable<GetReportReq, GetReportResponseBody>');
|
|
1126
|
+
});
|
|
1127
|
+
it('body + headers: return type is { body; headers }', async () => {
|
|
1128
|
+
const out = await emitScopeFile(apiGroupBothBodyAndHeaders);
|
|
1129
|
+
expect(out).toContain('export type GetDownloadResponseBody =');
|
|
1130
|
+
expect(out).toContain('export type GetDownloadResponseHeaders =');
|
|
1131
|
+
expect(out).toContain('{ body: GetDownloadResponseBody; headers: GetDownloadResponseHeaders }');
|
|
1132
|
+
});
|
|
1133
|
+
it('headers-only: return type is { headers }', async () => {
|
|
1134
|
+
const out = await emitScopeFile(apiGroupHeadersOnly);
|
|
1135
|
+
expect(out).toContain('export type GetPreflightResponseHeaders =');
|
|
1136
|
+
expect(out).toContain('{ headers: GetPreflightResponseHeaders }');
|
|
1137
|
+
});
|
|
1138
|
+
it('neither body nor headers: return type is void', async () => {
|
|
1139
|
+
const out = await emitScopeFile(apiGroupNoBody);
|
|
1140
|
+
expect(out).toContain('client.bindCallable<unknown, void>');
|
|
1141
|
+
});
|
|
1142
|
+
});
|
|
1143
|
+
describe('namespace mode', () => {
|
|
1144
|
+
it('body-only: return type references Response.Body', async () => {
|
|
1145
|
+
const out = await emitScopeFile(apiGroupBodyOnly, { namespaceTypes: true });
|
|
1146
|
+
expect(out).toContain('export namespace Response {');
|
|
1147
|
+
expect(out).toContain('client.bindCallable<Reports.GetReport.Req, Reports.GetReport.Response.Body>');
|
|
1148
|
+
});
|
|
1149
|
+
it('body + headers: return type is { body: Response.Body; headers: Response.Headers }', async () => {
|
|
1150
|
+
const out = await emitScopeFile(apiGroupBothBodyAndHeaders, { namespaceTypes: true });
|
|
1151
|
+
expect(out).toContain('export namespace Response {');
|
|
1152
|
+
expect(out).toContain('export type Body =');
|
|
1153
|
+
expect(out).toContain('export type Headers =');
|
|
1154
|
+
expect(out).toContain('{ body: Downloads.GetDownload.Response.Body; headers: Downloads.GetDownload.Response.Headers }');
|
|
1155
|
+
});
|
|
1156
|
+
it('headers-only: return type is { headers: Response.Headers }', async () => {
|
|
1157
|
+
const out = await emitScopeFile(apiGroupHeadersOnly, { namespaceTypes: true });
|
|
1158
|
+
expect(out).toContain('{ headers: Preflight.GetPreflight.Response.Headers }');
|
|
1159
|
+
});
|
|
1160
|
+
it('neither body nor headers: return type is void', async () => {
|
|
1161
|
+
const out = await emitScopeFile(apiGroupNoBody, { namespaceTypes: true });
|
|
1162
|
+
expect(out).toContain('client.bindCallable<unknown, void>');
|
|
1163
|
+
});
|
|
1164
|
+
});
|
|
1165
|
+
});
|
|
1166
|
+
describe('emitScopeFile API responseHeadersDeclared descriptor field', () => {
|
|
1167
|
+
it('emits responseHeadersDeclared: true when res.headers is present', async () => {
|
|
1168
|
+
const out = await emitScopeFile(apiGroupBothBodyAndHeaders);
|
|
1169
|
+
expect(out).toContain('responseHeadersDeclared: true');
|
|
1170
|
+
});
|
|
1171
|
+
it('does NOT emit responseHeadersDeclared when res.headers is absent', async () => {
|
|
1172
|
+
const out = await emitScopeFile(apiGroupBodyOnly);
|
|
1173
|
+
expect(out).not.toContain('responseHeadersDeclared');
|
|
1174
|
+
});
|
|
1175
|
+
});
|
|
1176
|
+
// ---------------------------------------------------------------------------
|
|
1177
|
+
// http-stream kind emission
|
|
1178
|
+
// ---------------------------------------------------------------------------
|
|
1179
|
+
const httpStreamGroup = {
|
|
1180
|
+
scopeKey: 'feed',
|
|
1181
|
+
camelCase: 'feed',
|
|
1182
|
+
routes: [
|
|
1183
|
+
{
|
|
1184
|
+
kind: 'http-stream',
|
|
1185
|
+
name: 'StreamFeed',
|
|
1186
|
+
path: '/feed/stream',
|
|
1187
|
+
method: 'get',
|
|
1188
|
+
fullPath: '/api/feed/stream',
|
|
1189
|
+
scope: 'feed',
|
|
1190
|
+
streamMode: 'sse',
|
|
1191
|
+
jsonSchema: {
|
|
1192
|
+
req: {
|
|
1193
|
+
query: {
|
|
1194
|
+
type: 'object',
|
|
1195
|
+
properties: { cursor: { type: 'string' } },
|
|
1196
|
+
},
|
|
1197
|
+
},
|
|
1198
|
+
res: {
|
|
1199
|
+
headers: {
|
|
1200
|
+
type: 'object',
|
|
1201
|
+
properties: { 'x-session': { type: 'string' } },
|
|
1202
|
+
required: ['x-session'],
|
|
1203
|
+
},
|
|
1204
|
+
},
|
|
1205
|
+
yield: {
|
|
1206
|
+
type: 'object',
|
|
1207
|
+
properties: { message: { type: 'string' } },
|
|
1208
|
+
required: ['message'],
|
|
1209
|
+
},
|
|
1210
|
+
returnType: {
|
|
1211
|
+
type: 'object',
|
|
1212
|
+
properties: { total: { type: 'number' } },
|
|
1213
|
+
required: ['total'],
|
|
1214
|
+
},
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
],
|
|
1218
|
+
};
|
|
1219
|
+
describe('emitScopeFile http-stream kind', () => {
|
|
1220
|
+
describe('flat mode', () => {
|
|
1221
|
+
it('emits Req-prefixed query type', async () => {
|
|
1222
|
+
const out = await emitScopeFile(httpStreamGroup);
|
|
1223
|
+
expect(out).toContain('export type StreamFeedReqQuery =');
|
|
1224
|
+
});
|
|
1225
|
+
it('emits ResponseHeaders type', async () => {
|
|
1226
|
+
const out = await emitScopeFile(httpStreamGroup);
|
|
1227
|
+
expect(out).toContain('export type StreamFeedResponseHeaders =');
|
|
1228
|
+
});
|
|
1229
|
+
it('emits Yield and ReturnType types', async () => {
|
|
1230
|
+
const out = await emitScopeFile(httpStreamGroup);
|
|
1231
|
+
expect(out).toContain('export type StreamFeedYield =');
|
|
1232
|
+
expect(out).toContain('export type StreamFeedReturnType =');
|
|
1233
|
+
});
|
|
1234
|
+
it('callable returns TypedStream<Yield, ReturnType>', async () => {
|
|
1235
|
+
const out = await emitScopeFile(httpStreamGroup);
|
|
1236
|
+
expect(out).toContain('TypedStream<StreamFeedYield, StreamFeedReturnType>');
|
|
1237
|
+
});
|
|
1238
|
+
it('callable uses kind: http-stream in descriptor', async () => {
|
|
1239
|
+
const out = await emitScopeFile(httpStreamGroup);
|
|
1240
|
+
expect(out).toContain("kind: 'http-stream'");
|
|
1241
|
+
});
|
|
1242
|
+
it('imports TypedStream', async () => {
|
|
1243
|
+
const out = await emitScopeFile(httpStreamGroup);
|
|
1244
|
+
expect(out).toContain('TypedStream');
|
|
1245
|
+
});
|
|
1246
|
+
});
|
|
1247
|
+
describe('namespace mode', () => {
|
|
1248
|
+
it('emits Req sub-namespace with query type', async () => {
|
|
1249
|
+
const out = await emitScopeFile(httpStreamGroup, { namespaceTypes: true });
|
|
1250
|
+
expect(out).toContain('export namespace Req {');
|
|
1251
|
+
expect(out).toContain('export type Query =');
|
|
1252
|
+
});
|
|
1253
|
+
it('emits Response sub-namespace with Headers type', async () => {
|
|
1254
|
+
const out = await emitScopeFile(httpStreamGroup, { namespaceTypes: true });
|
|
1255
|
+
expect(out).toContain('export namespace Response {');
|
|
1256
|
+
expect(out).toContain('export type Headers =');
|
|
1257
|
+
});
|
|
1258
|
+
it('emits Yield and ReturnType in route namespace', async () => {
|
|
1259
|
+
const out = await emitScopeFile(httpStreamGroup, { namespaceTypes: true });
|
|
1260
|
+
expect(out).toContain('export type Yield =');
|
|
1261
|
+
expect(out).toContain('export type ReturnType =');
|
|
1262
|
+
});
|
|
1263
|
+
it('callable uses qualified Req and TypedStream types', async () => {
|
|
1264
|
+
const out = await emitScopeFile(httpStreamGroup, { namespaceTypes: true });
|
|
1265
|
+
expect(out).toContain('Feed.StreamFeed.Req');
|
|
1266
|
+
expect(out).toContain('TypedStream<Feed.StreamFeed.Yield, Feed.StreamFeed.ReturnType>');
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
});
|
|
1017
1270
|
//# sourceMappingURL=emit-scope.test.js.map
|