ts-procedures 8.3.0 → 8.5.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/claude-code/skills/ts-procedures/SKILL.md +26 -8
- package/agent_config/claude-code/skills/ts-procedures/templates/client.md +3 -3
- package/agent_config/claude-code/skills/ts-procedures/templates/hono.md +3 -3
- package/agent_config/claude-code/skills/ts-procedures/templates/procedure.md +3 -3
- package/agent_config/claude-code/skills/ts-procedures/templates/stream-procedure.md +3 -3
- package/build/client/call.js +1 -1
- package/build/client/call.js.map +1 -1
- package/build/client/index.d.ts +1 -1
- package/build/client/index.js +23 -1
- package/build/client/index.js.map +1 -1
- package/build/client/index.test.js +87 -0
- package/build/client/index.test.js.map +1 -1
- package/build/client/resolve-options.d.ts +5 -4
- package/build/client/resolve-options.js +18 -7
- package/build/client/resolve-options.js.map +1 -1
- package/build/client/resolve-options.test.js +53 -24
- package/build/client/resolve-options.test.js.map +1 -1
- package/build/client/stream.js +1 -1
- package/build/client/stream.js.map +1 -1
- package/build/client/types.d.ts +31 -3
- package/build/codegen/__fixtures__/make-envelope.d.ts +41 -0
- package/build/codegen/__fixtures__/make-envelope.js +38 -0
- package/build/codegen/__fixtures__/make-envelope.js.map +1 -0
- package/build/codegen/bin/cli.d.ts +15 -0
- package/build/codegen/bin/cli.js +46 -21
- package/build/codegen/bin/cli.js.map +1 -1
- package/build/codegen/bin/cli.test.js +54 -1
- package/build/codegen/bin/cli.test.js.map +1 -1
- package/build/codegen/bin/flag-specs.d.ts +10 -0
- package/build/codegen/bin/flag-specs.js +62 -0
- package/build/codegen/bin/flag-specs.js.map +1 -0
- package/build/codegen/bin/flag-specs.test.d.ts +1 -0
- package/build/codegen/bin/flag-specs.test.js +35 -0
- package/build/codegen/bin/flag-specs.test.js.map +1 -0
- package/build/codegen/collect-models.d.ts +48 -0
- package/build/codegen/collect-models.js +84 -0
- package/build/codegen/collect-models.js.map +1 -0
- package/build/codegen/collect-models.test.d.ts +1 -0
- package/build/codegen/collect-models.test.js +59 -0
- package/build/codegen/collect-models.test.js.map +1 -0
- package/build/codegen/emit-client-runtime.js +1 -0
- package/build/codegen/emit-client-runtime.js.map +1 -1
- package/build/codegen/emit-models.d.ts +26 -0
- package/build/codegen/emit-models.js +53 -0
- package/build/codegen/emit-models.js.map +1 -0
- package/build/codegen/emit-models.test.d.ts +1 -0
- package/build/codegen/emit-models.test.js +42 -0
- package/build/codegen/emit-models.test.js.map +1 -0
- package/build/codegen/emit-scope.d.ts +10 -0
- package/build/codegen/emit-scope.js +119 -34
- package/build/codegen/emit-scope.js.map +1 -1
- package/build/codegen/emit-types.d.ts +26 -1
- package/build/codegen/emit-types.js +27 -5
- package/build/codegen/emit-types.js.map +1 -1
- package/build/codegen/index.d.ts +15 -0
- package/build/codegen/index.js +5 -0
- package/build/codegen/index.js.map +1 -1
- package/build/codegen/model-refs.d.ts +27 -0
- package/build/codegen/model-refs.js +49 -0
- package/build/codegen/model-refs.js.map +1 -0
- package/build/codegen/model-refs.test.d.ts +1 -0
- package/build/codegen/model-refs.test.js +33 -0
- package/build/codegen/model-refs.test.js.map +1 -0
- package/build/codegen/pipeline.d.ts +7 -0
- package/build/codegen/pipeline.js +6 -1
- package/build/codegen/pipeline.js.map +1 -1
- package/build/codegen/schema-walk.d.ts +13 -0
- package/build/codegen/schema-walk.js +26 -0
- package/build/codegen/schema-walk.js.map +1 -0
- package/build/codegen/schema-walk.test.d.ts +1 -0
- package/build/codegen/schema-walk.test.js +35 -0
- package/build/codegen/schema-walk.test.js.map +1 -0
- package/build/codegen/targets/_shared/target-run.d.ts +15 -0
- package/build/codegen/targets/ts/run.js +37 -1
- package/build/codegen/targets/ts/run.js.map +1 -1
- package/build/codegen/targets/ts/shared-models.test.d.ts +1 -0
- package/build/codegen/targets/ts/shared-models.test.js +354 -0
- package/build/codegen/targets/ts/shared-models.test.js.map +1 -0
- package/build/doc-envelope.d.ts +13 -0
- package/build/doc-envelope.js +23 -0
- package/build/doc-envelope.js.map +1 -0
- package/build/doc-envelope.test.d.ts +1 -0
- package/build/doc-envelope.test.js +31 -0
- package/build/doc-envelope.test.js.map +1 -0
- package/build/exports.d.ts +2 -0
- package/build/exports.js +1 -0
- package/build/exports.js.map +1 -1
- package/docs/client-and-codegen.md +163 -0
- package/docs/handoffs/ajsc-named-type-collision.md +134 -0
- package/docs/handoffs/ajsc-named-type-support.md +181 -0
- package/docs/handoffs/shared-models-auto-resolve-response.md +181 -0
- package/docs/superpowers/plans/2026-06-05-dx-feedback-round.md +1292 -0
- package/docs/superpowers/plans/2026-06-06-shared-models-convention-and-diagnostics.md +659 -0
- package/docs/superpowers/specs/2026-06-05-dx-feedback-round-design.md +285 -0
- package/package.json +2 -2
- package/src/client/call.ts +1 -1
- package/src/client/index.test.ts +98 -0
- package/src/client/index.ts +32 -1
- package/src/client/resolve-options.test.ts +73 -26
- package/src/client/resolve-options.ts +23 -9
- package/src/client/stream.ts +1 -1
- package/src/client/types.ts +34 -3
- package/src/codegen/__fixtures__/make-envelope.ts +89 -0
- package/src/codegen/bin/cli.test.ts +65 -1
- package/src/codegen/bin/cli.ts +51 -22
- package/src/codegen/bin/flag-specs.test.ts +38 -0
- package/src/codegen/bin/flag-specs.ts +71 -0
- package/src/codegen/collect-models.test.ts +68 -0
- package/src/codegen/collect-models.ts +125 -0
- package/src/codegen/emit-client-runtime.ts +1 -0
- package/src/codegen/emit-models.test.ts +48 -0
- package/src/codegen/emit-models.ts +63 -0
- package/src/codegen/emit-scope.ts +145 -33
- package/src/codegen/emit-types.ts +48 -7
- package/src/codegen/index.ts +20 -0
- package/src/codegen/model-refs.test.ts +37 -0
- package/src/codegen/model-refs.ts +57 -0
- package/src/codegen/pipeline.ts +13 -1
- package/src/codegen/schema-walk.test.ts +37 -0
- package/src/codegen/schema-walk.ts +23 -0
- package/src/codegen/targets/_shared/target-run.ts +15 -0
- package/src/codegen/targets/ts/run.ts +50 -0
- package/src/codegen/targets/ts/shared-models.test.ts +391 -0
- package/src/doc-envelope.test.ts +35 -0
- package/src/doc-envelope.ts +30 -0
- package/src/exports.ts +2 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { runPipeline } from '../../pipeline.js';
|
|
3
|
+
import { makeApiRoute, makeEnvelope } from '../../__fixtures__/make-envelope.js';
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Fixtures
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/** A reusable `$id`-bearing schema — appears verbatim in multiple routes/scopes. */
|
|
8
|
+
const messageModel = {
|
|
9
|
+
$id: 'urn:msg',
|
|
10
|
+
title: 'Message',
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
id: { type: 'string' },
|
|
14
|
+
body: { type: 'string' },
|
|
15
|
+
},
|
|
16
|
+
required: ['id', 'body'],
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The same `urn:msg` model appears as a nested property in two scopes
|
|
20
|
+
* (`messages`, `threads`), and once as the WHOLE response body of a route
|
|
21
|
+
* (top-level `$id`).
|
|
22
|
+
*/
|
|
23
|
+
function modelEnvelope() {
|
|
24
|
+
return makeEnvelope([
|
|
25
|
+
makeApiRoute({
|
|
26
|
+
name: 'GetMessage',
|
|
27
|
+
scope: 'messages',
|
|
28
|
+
fullPath: '/messages/:id',
|
|
29
|
+
jsonSchema: {
|
|
30
|
+
req: {
|
|
31
|
+
pathParams: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: { id: { type: 'string' } },
|
|
34
|
+
required: ['id'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
// Whole response body IS the model (top-level $id) → `Response = Message`.
|
|
38
|
+
res: { body: { ...messageModel } },
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
makeApiRoute({
|
|
42
|
+
name: 'ListMessages',
|
|
43
|
+
scope: 'messages',
|
|
44
|
+
fullPath: '/messages',
|
|
45
|
+
jsonSchema: {
|
|
46
|
+
res: {
|
|
47
|
+
body: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
// Model nested inside an array → referenced, not inlined.
|
|
51
|
+
items: { type: 'array', items: { ...messageModel } },
|
|
52
|
+
},
|
|
53
|
+
required: ['items'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
makeApiRoute({
|
|
59
|
+
name: 'GetThread',
|
|
60
|
+
scope: 'threads',
|
|
61
|
+
fullPath: '/threads/:id',
|
|
62
|
+
jsonSchema: {
|
|
63
|
+
res: {
|
|
64
|
+
body: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
// Same model in a SECOND scope.
|
|
68
|
+
latest: { ...messageModel },
|
|
69
|
+
},
|
|
70
|
+
required: ['latest'],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
/** Identical to {@link modelEnvelope} but with every `$id`/`title` stripped. */
|
|
78
|
+
function noModelEnvelope() {
|
|
79
|
+
return makeEnvelope([
|
|
80
|
+
makeApiRoute({
|
|
81
|
+
name: 'GetMessage',
|
|
82
|
+
scope: 'messages',
|
|
83
|
+
fullPath: '/messages/:id',
|
|
84
|
+
jsonSchema: {
|
|
85
|
+
req: {
|
|
86
|
+
pathParams: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
properties: { id: { type: 'string' } },
|
|
89
|
+
required: ['id'],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
res: {
|
|
93
|
+
body: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: { id: { type: 'string' }, body: { type: 'string' } },
|
|
96
|
+
required: ['id', 'body'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
}),
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
function findFile(files, suffix) {
|
|
104
|
+
return files.find((f) => f.path.endsWith(suffix));
|
|
105
|
+
}
|
|
106
|
+
const countMatches = (haystack, re) => (haystack.match(re) ?? []).length;
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Tests
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
describe('shared models (TS target, ajsc x-named-type)', () => {
|
|
111
|
+
it('shareModels:true emits _models.ts with exactly one Message type; scopes reference it', async () => {
|
|
112
|
+
const files = await runPipeline({
|
|
113
|
+
envelope: modelEnvelope(),
|
|
114
|
+
outDir: 'out',
|
|
115
|
+
dryRun: true,
|
|
116
|
+
shareModels: true,
|
|
117
|
+
namespaceTypes: true,
|
|
118
|
+
selfContained: false,
|
|
119
|
+
});
|
|
120
|
+
const modelsFile = findFile(files, '_models.ts');
|
|
121
|
+
expect(modelsFile).toBeDefined();
|
|
122
|
+
expect(countMatches(modelsFile.code, /export type Message =/g)).toBe(1);
|
|
123
|
+
// Both scopes that use the model import it and reference Message by name.
|
|
124
|
+
const messages = findFile(files, 'messages.ts');
|
|
125
|
+
const threads = findFile(files, 'threads.ts');
|
|
126
|
+
for (const scope of [messages, threads]) {
|
|
127
|
+
expect(scope.code).toContain("from './_models'");
|
|
128
|
+
expect(scope.code).toContain('Message');
|
|
129
|
+
// No inlined model object literal — the body shape lives only in _models.ts.
|
|
130
|
+
expect(scope.code).not.toMatch(/body:\s*string;[^}]*}\s*\)/);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
it('a route whose entire response IS the model emits `Response = Message`', async () => {
|
|
134
|
+
const files = await runPipeline({
|
|
135
|
+
envelope: modelEnvelope(),
|
|
136
|
+
outDir: 'out',
|
|
137
|
+
dryRun: true,
|
|
138
|
+
shareModels: true,
|
|
139
|
+
namespaceTypes: true,
|
|
140
|
+
});
|
|
141
|
+
const messages = findFile(files, 'messages.ts');
|
|
142
|
+
// GetMessage's response body IS the whole model (top-level $id) → the Body
|
|
143
|
+
// alias is exactly `Message`, the single token replacing the whole schema.
|
|
144
|
+
expect(messages.code).toMatch(/export type Body = Message\b/);
|
|
145
|
+
// And the nested-array case references the same model inside Array<…>.
|
|
146
|
+
expect(messages.code).toMatch(/Array<Message>/);
|
|
147
|
+
});
|
|
148
|
+
it('shareModels:false emits NO _models.ts and inlines as before', async () => {
|
|
149
|
+
const files = await runPipeline({
|
|
150
|
+
envelope: modelEnvelope(),
|
|
151
|
+
outDir: 'out',
|
|
152
|
+
dryRun: true,
|
|
153
|
+
shareModels: false,
|
|
154
|
+
namespaceTypes: true,
|
|
155
|
+
});
|
|
156
|
+
expect(findFile(files, '_models.ts')).toBeUndefined();
|
|
157
|
+
const messages = findFile(files, 'messages.ts');
|
|
158
|
+
// The model is inlined: its properties appear in the scope, no _models import.
|
|
159
|
+
expect(messages.code).not.toContain("from './_models'");
|
|
160
|
+
expect(messages.code).toContain('body');
|
|
161
|
+
});
|
|
162
|
+
it('regression: a no-$id envelope produces byte-identical scope output for true vs false', async () => {
|
|
163
|
+
const on = await runPipeline({
|
|
164
|
+
envelope: noModelEnvelope(),
|
|
165
|
+
outDir: 'out',
|
|
166
|
+
dryRun: true,
|
|
167
|
+
shareModels: true,
|
|
168
|
+
namespaceTypes: true,
|
|
169
|
+
});
|
|
170
|
+
const off = await runPipeline({
|
|
171
|
+
envelope: noModelEnvelope(),
|
|
172
|
+
outDir: 'out',
|
|
173
|
+
dryRun: true,
|
|
174
|
+
shareModels: false,
|
|
175
|
+
namespaceTypes: true,
|
|
176
|
+
});
|
|
177
|
+
// No models exist, so neither run emits _models.ts.
|
|
178
|
+
expect(findFile(on, '_models.ts')).toBeUndefined();
|
|
179
|
+
expect(findFile(off, '_models.ts')).toBeUndefined();
|
|
180
|
+
const onScope = findFile(on, 'messages.ts');
|
|
181
|
+
const offScope = findFile(off, 'messages.ts');
|
|
182
|
+
expect(onScope.code).toBe(offScope.code);
|
|
183
|
+
});
|
|
184
|
+
it('sharedTypesImport re-exports the model and skips generating its body', async () => {
|
|
185
|
+
const files = await runPipeline({
|
|
186
|
+
envelope: modelEnvelope(),
|
|
187
|
+
outDir: 'out',
|
|
188
|
+
dryRun: true,
|
|
189
|
+
shareModels: true,
|
|
190
|
+
namespaceTypes: true,
|
|
191
|
+
sharedTypesImport: { 'urn:msg': { module: '@shared/schemas', name: 'Message' } },
|
|
192
|
+
});
|
|
193
|
+
const modelsFile = findFile(files, '_models.ts');
|
|
194
|
+
expect(modelsFile.code).toContain("export { Message } from '@shared/schemas'");
|
|
195
|
+
// No generated body when the model is externally imported.
|
|
196
|
+
expect(modelsFile.code).not.toMatch(/export type Message =/);
|
|
197
|
+
// Scopes still import Message from ./_models (the single hub).
|
|
198
|
+
const messages = findFile(files, 'messages.ts');
|
|
199
|
+
expect(messages.code).toContain("from './_models'");
|
|
200
|
+
expect(messages.code).toContain('Message');
|
|
201
|
+
});
|
|
202
|
+
it('flat mode (namespaceTypes:false) imports Message from ./_models', async () => {
|
|
203
|
+
const files = await runPipeline({
|
|
204
|
+
envelope: modelEnvelope(),
|
|
205
|
+
outDir: 'out',
|
|
206
|
+
dryRun: true,
|
|
207
|
+
shareModels: true,
|
|
208
|
+
namespaceTypes: false,
|
|
209
|
+
});
|
|
210
|
+
const messages = findFile(files, 'messages.ts');
|
|
211
|
+
expect(messages.code).toContain("import type { Message } from './_models'");
|
|
212
|
+
});
|
|
213
|
+
it('sharedModelsModule re-exports every $id model from the convention module', async () => {
|
|
214
|
+
const files = await runPipeline({
|
|
215
|
+
envelope: modelEnvelope(),
|
|
216
|
+
outDir: 'out',
|
|
217
|
+
dryRun: true,
|
|
218
|
+
shareModels: true,
|
|
219
|
+
namespaceTypes: true,
|
|
220
|
+
selfContained: false,
|
|
221
|
+
sharedModelsModule: '@app/schemas',
|
|
222
|
+
});
|
|
223
|
+
const modelsFile = findFile(files, '_models.ts');
|
|
224
|
+
// Re-exported, not generated.
|
|
225
|
+
expect(modelsFile.code).toContain("export { Message } from '@app/schemas'");
|
|
226
|
+
expect(countMatches(modelsFile.code, /export type Message =/g)).toBe(0);
|
|
227
|
+
// Scopes still import the shared name from ./_models.
|
|
228
|
+
expect(findFile(files, 'messages.ts').code).toContain("from './_models'");
|
|
229
|
+
});
|
|
230
|
+
it('explicit sharedTypesImport overrides the sharedModelsModule convention per $id', async () => {
|
|
231
|
+
const files = await runPipeline({
|
|
232
|
+
envelope: modelEnvelope(),
|
|
233
|
+
outDir: 'out',
|
|
234
|
+
dryRun: true,
|
|
235
|
+
shareModels: true,
|
|
236
|
+
namespaceTypes: true,
|
|
237
|
+
selfContained: false,
|
|
238
|
+
sharedModelsModule: '@app/schemas',
|
|
239
|
+
sharedTypesImport: { 'urn:msg': { module: '@override/pkg', name: 'Message' } },
|
|
240
|
+
});
|
|
241
|
+
expect(findFile(files, '_models.ts').code).toContain("export { Message } from '@override/pkg'");
|
|
242
|
+
});
|
|
243
|
+
it('emits a neutral summary of the re-exported / generated split via the injected logger', async () => {
|
|
244
|
+
const lines = [];
|
|
245
|
+
await runPipeline({
|
|
246
|
+
envelope: modelEnvelope(),
|
|
247
|
+
outDir: 'out',
|
|
248
|
+
dryRun: true,
|
|
249
|
+
shareModels: true,
|
|
250
|
+
namespaceTypes: true,
|
|
251
|
+
selfContained: false,
|
|
252
|
+
logger: (m) => lines.push(m),
|
|
253
|
+
});
|
|
254
|
+
expect(lines.join('\n')).toContain('Shared models: 1 total — 0 re-exported, 1 generated locally.');
|
|
255
|
+
});
|
|
256
|
+
it('does not emit a summary when there are no $id-bearing models', async () => {
|
|
257
|
+
const lines = [];
|
|
258
|
+
await runPipeline({
|
|
259
|
+
envelope: noModelEnvelope(),
|
|
260
|
+
outDir: 'out',
|
|
261
|
+
dryRun: true,
|
|
262
|
+
shareModels: true,
|
|
263
|
+
namespaceTypes: true,
|
|
264
|
+
selfContained: false,
|
|
265
|
+
logger: (m) => lines.push(m),
|
|
266
|
+
});
|
|
267
|
+
expect(lines.join('\n')).not.toContain('Shared models:');
|
|
268
|
+
});
|
|
269
|
+
it('stays silent (no console output) when no logger is injected', async () => {
|
|
270
|
+
const log = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
271
|
+
try {
|
|
272
|
+
await runPipeline({
|
|
273
|
+
envelope: modelEnvelope(),
|
|
274
|
+
outDir: 'out',
|
|
275
|
+
dryRun: true,
|
|
276
|
+
shareModels: true,
|
|
277
|
+
namespaceTypes: true,
|
|
278
|
+
selfContained: false,
|
|
279
|
+
});
|
|
280
|
+
expect(log.mock.calls.flat().join('\n')).not.toContain('Shared models:');
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
log.mockRestore();
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
it('strictSharedModels throws listing the offending $id and derived name', async () => {
|
|
287
|
+
await expect(runPipeline({
|
|
288
|
+
envelope: modelEnvelope(),
|
|
289
|
+
outDir: 'out',
|
|
290
|
+
dryRun: true,
|
|
291
|
+
shareModels: true,
|
|
292
|
+
namespaceTypes: true,
|
|
293
|
+
selfContained: false,
|
|
294
|
+
strictSharedModels: true,
|
|
295
|
+
})).rejects.toThrow(/--strict-shared-models[\s\S]*urn:msg[\s\S]*Message/);
|
|
296
|
+
});
|
|
297
|
+
it('strictSharedModels passes once every model is covered by the convention', async () => {
|
|
298
|
+
await expect(runPipeline({
|
|
299
|
+
envelope: modelEnvelope(),
|
|
300
|
+
outDir: 'out',
|
|
301
|
+
dryRun: true,
|
|
302
|
+
shareModels: true,
|
|
303
|
+
namespaceTypes: true,
|
|
304
|
+
selfContained: false,
|
|
305
|
+
strictSharedModels: true,
|
|
306
|
+
sharedModelsModule: '@app/schemas',
|
|
307
|
+
})).resolves.toBeDefined();
|
|
308
|
+
});
|
|
309
|
+
it('fails loudly when a shared model name collides with a property-derived sub-type', async () => {
|
|
310
|
+
// `latest` references the Message model; a sibling property literally named
|
|
311
|
+
// `message` would make ajsc extract a structural sub-type ALSO named
|
|
312
|
+
// `Message`. ajsc silently merges the two (the model reference resolves to
|
|
313
|
+
// the unrelated structural type), so codegen must reject this rather than
|
|
314
|
+
// emit a silently-wrong type. See assertNoModelNameCollision in emit-scope.
|
|
315
|
+
const collision = makeEnvelope([
|
|
316
|
+
makeApiRoute({
|
|
317
|
+
name: 'GetThread',
|
|
318
|
+
scope: 'chat',
|
|
319
|
+
fullPath: '/thread',
|
|
320
|
+
jsonSchema: {
|
|
321
|
+
res: {
|
|
322
|
+
body: {
|
|
323
|
+
type: 'object',
|
|
324
|
+
required: ['latest', 'message'],
|
|
325
|
+
properties: {
|
|
326
|
+
latest: {
|
|
327
|
+
type: 'object',
|
|
328
|
+
$id: 'urn:msg',
|
|
329
|
+
title: 'Message',
|
|
330
|
+
required: ['id'],
|
|
331
|
+
properties: { id: { type: 'string' } },
|
|
332
|
+
},
|
|
333
|
+
message: {
|
|
334
|
+
type: 'object',
|
|
335
|
+
required: ['unread'],
|
|
336
|
+
properties: { unread: { type: 'boolean' } },
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
}),
|
|
343
|
+
]);
|
|
344
|
+
await expect(runPipeline({
|
|
345
|
+
envelope: collision,
|
|
346
|
+
outDir: 'out',
|
|
347
|
+
dryRun: true,
|
|
348
|
+
shareModels: true,
|
|
349
|
+
namespaceTypes: true,
|
|
350
|
+
selfContained: false,
|
|
351
|
+
})).rejects.toThrow(/shared model 'Message' collides/);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
//# sourceMappingURL=shared-models.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-models.test.js","sourceRoot":"","sources":["../../../../src/codegen/targets/ts/shared-models.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocEnvelope } from './implementations/types.js';
|
|
2
|
+
export type DocEnvelopeSource = DocEnvelope | {
|
|
3
|
+
toDocEnvelope(): DocEnvelope;
|
|
4
|
+
} | {
|
|
5
|
+
toJSON(): DocEnvelope;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Serializes a doc envelope to disk as pretty JSON so codegen can run offline
|
|
9
|
+
* via `--file <path>` without a running server. Accepts a plain `DocEnvelope`,
|
|
10
|
+
* a builder exposing `toDocEnvelope()`, or a `DocRegistry` exposing `toJSON()`.
|
|
11
|
+
* Parent directories are created as needed.
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeDocEnvelope(source: DocEnvelopeSource, path: string): Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
function coerceToEnvelope(source) {
|
|
4
|
+
if (typeof source.toDocEnvelope === 'function') {
|
|
5
|
+
return source.toDocEnvelope();
|
|
6
|
+
}
|
|
7
|
+
if (typeof source.toJSON === 'function') {
|
|
8
|
+
return source.toJSON();
|
|
9
|
+
}
|
|
10
|
+
return source;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Serializes a doc envelope to disk as pretty JSON so codegen can run offline
|
|
14
|
+
* via `--file <path>` without a running server. Accepts a plain `DocEnvelope`,
|
|
15
|
+
* a builder exposing `toDocEnvelope()`, or a `DocRegistry` exposing `toJSON()`.
|
|
16
|
+
* Parent directories are created as needed.
|
|
17
|
+
*/
|
|
18
|
+
export async function writeDocEnvelope(source, path) {
|
|
19
|
+
const envelope = coerceToEnvelope(source);
|
|
20
|
+
await mkdir(dirname(path), { recursive: true });
|
|
21
|
+
await writeFile(path, JSON.stringify(envelope, null, 2), 'utf8');
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=doc-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-envelope.js","sourceRoot":"","sources":["../src/doc-envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAQnC,SAAS,gBAAgB,CAAC,MAAyB;IACjD,IAAI,OAAQ,MAAsC,CAAC,aAAa,KAAK,UAAU,EAAE,CAAC;QAChF,OAAQ,MAA2C,CAAC,aAAa,EAAE,CAAA;IACrE,CAAC;IACD,IAAI,OAAQ,MAA+B,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAClE,OAAQ,MAAoC,CAAC,MAAM,EAAE,CAAA;IACvD,CAAC;IACD,OAAO,MAAqB,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAyB,EAAE,IAAY;IAC5E,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACzC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/C,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AAClE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
+
import { readFile, rm, mkdtemp } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { writeDocEnvelope } from './doc-envelope.js';
|
|
6
|
+
const envelope = { basePath: '', headers: [], errors: [], routes: [] };
|
|
7
|
+
describe('writeDocEnvelope', () => {
|
|
8
|
+
let dir;
|
|
9
|
+
afterEach(async () => { if (dir)
|
|
10
|
+
await rm(dir, { recursive: true, force: true }); });
|
|
11
|
+
it('writes a plain DocEnvelope as pretty JSON', async () => {
|
|
12
|
+
dir = await mkdtemp(join(tmpdir(), 'tsp-'));
|
|
13
|
+
const out = join(dir, 'nested', 'docs.json');
|
|
14
|
+
await writeDocEnvelope(envelope, out);
|
|
15
|
+
const parsed = JSON.parse(await readFile(out, 'utf8'));
|
|
16
|
+
expect(parsed).toEqual(envelope);
|
|
17
|
+
});
|
|
18
|
+
it('accepts a builder-like object with toDocEnvelope()', async () => {
|
|
19
|
+
dir = await mkdtemp(join(tmpdir(), 'tsp-'));
|
|
20
|
+
const out = join(dir, 'docs.json');
|
|
21
|
+
await writeDocEnvelope({ toDocEnvelope: () => envelope }, out);
|
|
22
|
+
expect(JSON.parse(await readFile(out, 'utf8'))).toEqual(envelope);
|
|
23
|
+
});
|
|
24
|
+
it('accepts a DocRegistry-like object (toJSON)', async () => {
|
|
25
|
+
dir = await mkdtemp(join(tmpdir(), 'tsp-'));
|
|
26
|
+
const out = join(dir, 'docs.json');
|
|
27
|
+
await writeDocEnvelope({ toJSON: () => envelope }, out);
|
|
28
|
+
expect(JSON.parse(await readFile(out, 'utf8'))).toEqual(envelope);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=doc-envelope.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-envelope.test.js","sourceRoot":"","sources":["../src/doc-envelope.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGpD,MAAM,QAAQ,GAAgB,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;AAEnF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,GAAW,CAAA;IACf,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,IAAI,GAAG;QAAE,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IAEnF,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;QAC5C,MAAM,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;QACtD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;QAClC,MAAM,gBAAgB,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;QAClC,MAAM,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAA;QACvD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/build/exports.d.ts
CHANGED
|
@@ -7,3 +7,5 @@ export * from './schema/resolve-schema-lib.js';
|
|
|
7
7
|
export * from './schema/types.js';
|
|
8
8
|
export type { HttpReturn } from './create-http.js';
|
|
9
9
|
export type { TCreateHttpConfig } from './types.js';
|
|
10
|
+
export { writeDocEnvelope, type DocEnvelopeSource } from './doc-envelope.js';
|
|
11
|
+
export type { DocEnvelope } from './implementations/types.js';
|
package/build/exports.js
CHANGED
package/build/exports.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,oBAAoB,CAAA;AAClC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,oBAAoB,CAAA;AAClC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mBAAmB,CAAA;AAGjC,OAAO,EAAE,gBAAgB,EAA0B,MAAM,mBAAmB,CAAA"}
|