@constructive-io/graphql-codegen 4.12.2 → 4.13.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.
Files changed (33) hide show
  1. package/core/codegen/cli/command-map-generator.d.ts +1 -0
  2. package/core/codegen/cli/command-map-generator.js +4 -0
  3. package/core/codegen/cli/config-command-generator.d.ts +11 -0
  4. package/core/codegen/cli/config-command-generator.js +458 -0
  5. package/core/codegen/cli/helpers-generator.d.ts +15 -0
  6. package/core/codegen/cli/helpers-generator.js +119 -0
  7. package/core/codegen/cli/index.d.ts +4 -0
  8. package/core/codegen/cli/index.js +21 -3
  9. package/core/codegen/orm/index.js +3 -2
  10. package/core/codegen/orm/input-types-generator.d.ts +3 -1
  11. package/core/codegen/orm/input-types-generator.js +14 -6
  12. package/core/codegen/orm/model-generator.d.ts +6 -2
  13. package/core/codegen/orm/model-generator.js +59 -37
  14. package/core/codegen/templates/query-builder.ts +2 -2
  15. package/core/codegen/templates/select-types.ts +2 -2
  16. package/esm/core/codegen/cli/command-map-generator.d.ts +1 -0
  17. package/esm/core/codegen/cli/command-map-generator.js +4 -0
  18. package/esm/core/codegen/cli/config-command-generator.d.ts +11 -0
  19. package/esm/core/codegen/cli/config-command-generator.js +422 -0
  20. package/esm/core/codegen/cli/helpers-generator.d.ts +15 -0
  21. package/esm/core/codegen/cli/helpers-generator.js +83 -0
  22. package/esm/core/codegen/cli/index.d.ts +4 -0
  23. package/esm/core/codegen/cli/index.js +18 -2
  24. package/esm/core/codegen/orm/index.js +3 -2
  25. package/esm/core/codegen/orm/input-types-generator.d.ts +3 -1
  26. package/esm/core/codegen/orm/input-types-generator.js +14 -6
  27. package/esm/core/codegen/orm/model-generator.d.ts +6 -2
  28. package/esm/core/codegen/orm/model-generator.js +59 -37
  29. package/esm/types/config.d.ts +9 -0
  30. package/esm/types/config.js +1 -0
  31. package/package.json +4 -4
  32. package/types/config.d.ts +9 -0
  33. package/types/config.js +1 -0
@@ -0,0 +1,422 @@
1
+ import * as t from '@babel/types';
2
+ import { generateCode } from '../babel-ast';
3
+ import { getGeneratedFileHeader } from '../utils';
4
+ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
5
+ const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
6
+ const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
7
+ decl.importKind = typeOnly ? 'type' : 'value';
8
+ return decl;
9
+ }
10
+ function buildSwitchCase(testValue, handlerName, args) {
11
+ return t.switchCase(t.stringLiteral(testValue), [
12
+ t.returnStatement(t.callExpression(t.identifier(handlerName), args)),
13
+ ]);
14
+ }
15
+ function buildDefaultSwitchCase(usageVarName) {
16
+ return t.switchCase(null, [
17
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier(usageVarName)])),
18
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
19
+ ]);
20
+ }
21
+ /**
22
+ * Generate the config command file (get/set/list/delete for per-context vars).
23
+ *
24
+ * Usage:
25
+ * <tool> config get <key>
26
+ * <tool> config set <key> <value>
27
+ * <tool> config list
28
+ * <tool> config delete <key>
29
+ */
30
+ export function generateConfigCommand(toolName, commandName) {
31
+ const statements = [];
32
+ statements.push(createImportDeclaration('inquirerer', [
33
+ 'CLIOptions',
34
+ 'Inquirerer',
35
+ 'extractFirst',
36
+ ]));
37
+ statements.push(createImportDeclaration('../executor', ['getStore']));
38
+ const usageStr = `
39
+ ${toolName} ${commandName} <command>
40
+
41
+ Commands:
42
+ get <key> Get a config value
43
+ set <key> <value> Set a config value
44
+ list List all config values
45
+ delete <key> Delete a config value
46
+
47
+ --help, -h Show this help message
48
+ `;
49
+ statements.push(t.variableDeclaration('const', [
50
+ t.variableDeclarator(t.identifier('usage'), t.stringLiteral(usageStr)),
51
+ ]));
52
+ // Main export: default async (argv, prompter, _options) => { ... }
53
+ const argvParam = t.identifier('argv');
54
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
55
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
56
+ t.tsStringKeyword(),
57
+ t.tsUnknownKeyword(),
58
+ ])),
59
+ ])));
60
+ const prompterParam = t.identifier('prompter');
61
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
62
+ const optionsParam = t.identifier('_options');
63
+ optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CLIOptions')));
64
+ const mainBody = [
65
+ // Help check
66
+ t.ifStatement(t.logicalExpression('||', t.memberExpression(t.identifier('argv'), t.identifier('help')), t.memberExpression(t.identifier('argv'), t.identifier('h'))), t.blockStatement([
67
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('usage')])),
68
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(0)])),
69
+ ])),
70
+ // const store = getStore();
71
+ t.variableDeclaration('const', [
72
+ t.variableDeclarator(t.identifier('store'), t.callExpression(t.identifier('getStore'), [])),
73
+ ]),
74
+ // const { first: subcommand, newArgv } = extractFirst(argv);
75
+ t.variableDeclaration('const', [
76
+ t.variableDeclarator(t.objectPattern([
77
+ t.objectProperty(t.identifier('first'), t.identifier('subcommand')),
78
+ t.objectProperty(t.identifier('newArgv'), t.identifier('newArgv'), false, true),
79
+ ]), t.callExpression(t.identifier('extractFirst'), [
80
+ t.identifier('argv'),
81
+ ])),
82
+ ]),
83
+ // If no subcommand, prompt
84
+ t.ifStatement(t.unaryExpression('!', t.identifier('subcommand')), t.blockStatement([
85
+ t.variableDeclaration('const', [
86
+ t.variableDeclarator(t.identifier('answer'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
87
+ t.identifier('argv'),
88
+ t.arrayExpression([
89
+ t.objectExpression([
90
+ t.objectProperty(t.identifier('type'), t.stringLiteral('autocomplete')),
91
+ t.objectProperty(t.identifier('name'), t.stringLiteral('subcommand')),
92
+ t.objectProperty(t.identifier('message'), t.stringLiteral('What do you want to do?')),
93
+ t.objectProperty(t.identifier('options'), t.arrayExpression([
94
+ t.stringLiteral('get'),
95
+ t.stringLiteral('set'),
96
+ t.stringLiteral('list'),
97
+ t.stringLiteral('delete'),
98
+ ])),
99
+ ]),
100
+ ]),
101
+ ]))),
102
+ ]),
103
+ t.returnStatement(t.callExpression(t.identifier('handleSubcommand'), [
104
+ t.memberExpression(t.identifier('answer'), t.identifier('subcommand')),
105
+ t.identifier('newArgv'),
106
+ t.identifier('prompter'),
107
+ t.identifier('store'),
108
+ ])),
109
+ ])),
110
+ t.returnStatement(t.callExpression(t.identifier('handleSubcommand'), [
111
+ t.identifier('subcommand'),
112
+ t.identifier('newArgv'),
113
+ t.identifier('prompter'),
114
+ t.identifier('store'),
115
+ ])),
116
+ ];
117
+ const mainExport = t.exportDefaultDeclaration(t.arrowFunctionExpression([argvParam, prompterParam, optionsParam], t.blockStatement(mainBody), true));
118
+ statements.push(mainExport);
119
+ // handleSubcommand function
120
+ const subcmdParam = t.identifier('subcommand');
121
+ subcmdParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
122
+ const argvParam2 = t.identifier('argv');
123
+ argvParam2.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
124
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
125
+ t.tsStringKeyword(),
126
+ t.tsUnknownKeyword(),
127
+ ])),
128
+ ])));
129
+ const prompterParam2 = t.identifier('prompter');
130
+ prompterParam2.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
131
+ const storeParam = t.identifier('store');
132
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
133
+ t.tsTypeQuery(t.identifier('getStore')),
134
+ ])));
135
+ const handleSubcommandFunc = t.functionDeclaration(t.identifier('handleSubcommand'), [subcmdParam, argvParam2, prompterParam2, storeParam], t.blockStatement([
136
+ t.switchStatement(t.identifier('subcommand'), [
137
+ buildSwitchCase('get', 'handleGet', [
138
+ t.identifier('argv'),
139
+ t.identifier('prompter'),
140
+ t.identifier('store'),
141
+ ]),
142
+ buildSwitchCase('set', 'handleSet', [
143
+ t.identifier('argv'),
144
+ t.identifier('prompter'),
145
+ t.identifier('store'),
146
+ ]),
147
+ buildSwitchCase('list', 'handleList', [t.identifier('store')]),
148
+ buildSwitchCase('delete', 'handleDelete', [
149
+ t.identifier('argv'),
150
+ t.identifier('prompter'),
151
+ t.identifier('store'),
152
+ ]),
153
+ buildDefaultSwitchCase('usage'),
154
+ ]),
155
+ ]), false, true);
156
+ statements.push(handleSubcommandFunc);
157
+ // handleGet
158
+ statements.push(buildGetHandler());
159
+ // handleSet
160
+ statements.push(buildSetHandler());
161
+ // handleList
162
+ statements.push(buildListHandler());
163
+ // handleDelete
164
+ statements.push(buildDeleteHandler());
165
+ const header = getGeneratedFileHeader('Config key-value store commands');
166
+ const code = generateCode(statements);
167
+ return {
168
+ fileName: `commands/${commandName}.ts`,
169
+ content: header + '\n' + code,
170
+ };
171
+ }
172
+ function buildGetHandler() {
173
+ const argvParam = t.identifier('argv');
174
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
175
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
176
+ t.tsStringKeyword(),
177
+ t.tsUnknownKeyword(),
178
+ ])),
179
+ ])));
180
+ const prompterParam = t.identifier('prompter');
181
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
182
+ const storeParam = t.identifier('store');
183
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
184
+ t.tsTypeQuery(t.identifier('getStore')),
185
+ ])));
186
+ const body = [
187
+ // const { first: key } = extractFirst(argv);
188
+ t.variableDeclaration('const', [
189
+ t.variableDeclarator(t.objectPattern([
190
+ t.objectProperty(t.identifier('first'), t.identifier('key')),
191
+ ]), t.callExpression(t.identifier('extractFirst'), [
192
+ t.identifier('argv'),
193
+ ])),
194
+ ]),
195
+ // Prompt if no key
196
+ t.ifStatement(t.unaryExpression('!', t.identifier('key')), t.blockStatement([
197
+ t.variableDeclaration('const', [
198
+ t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
199
+ t.identifier('argv'),
200
+ t.arrayExpression([
201
+ t.objectExpression([
202
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
203
+ t.objectProperty(t.identifier('name'), t.stringLiteral('key')),
204
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config key')),
205
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
206
+ ]),
207
+ ]),
208
+ ]))),
209
+ ]),
210
+ t.variableDeclaration('const', [
211
+ t.variableDeclarator(t.identifier('value'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('getVar')), [t.memberExpression(t.identifier('answers'), t.identifier('key'))])),
212
+ ]),
213
+ t.ifStatement(t.binaryExpression('===', t.identifier('value'), t.identifier('undefined')), t.blockStatement([
214
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [
215
+ t.templateLiteral([
216
+ t.templateElement({ raw: 'Key "', cooked: 'Key "' }),
217
+ t.templateElement({ raw: '" not found.', cooked: '" not found.' }, true),
218
+ ], [t.memberExpression(t.identifier('answers'), t.identifier('key'))]),
219
+ ])),
220
+ ]), t.blockStatement([
221
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('value')])),
222
+ ])),
223
+ t.returnStatement(),
224
+ ])),
225
+ // const value = store.getVar(key);
226
+ t.variableDeclaration('const', [
227
+ t.variableDeclarator(t.identifier('value'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('getVar')), [t.identifier('key')])),
228
+ ]),
229
+ t.ifStatement(t.binaryExpression('===', t.identifier('value'), t.identifier('undefined')), t.blockStatement([
230
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [
231
+ t.templateLiteral([
232
+ t.templateElement({ raw: 'Key "', cooked: 'Key "' }),
233
+ t.templateElement({ raw: '" not found.', cooked: '" not found.' }, true),
234
+ ], [t.identifier('key')]),
235
+ ])),
236
+ ]), t.blockStatement([
237
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('value')])),
238
+ ])),
239
+ ];
240
+ return t.functionDeclaration(t.identifier('handleGet'), [argvParam, prompterParam, storeParam], t.blockStatement(body), false, true);
241
+ }
242
+ function buildSetHandler() {
243
+ const argvParam = t.identifier('argv');
244
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
245
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
246
+ t.tsStringKeyword(),
247
+ t.tsUnknownKeyword(),
248
+ ])),
249
+ ])));
250
+ const prompterParam = t.identifier('prompter');
251
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
252
+ const storeParam = t.identifier('store');
253
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
254
+ t.tsTypeQuery(t.identifier('getStore')),
255
+ ])));
256
+ const body = [
257
+ // const { first: key, newArgv: restArgv } = extractFirst(argv);
258
+ t.variableDeclaration('const', [
259
+ t.variableDeclarator(t.objectPattern([
260
+ t.objectProperty(t.identifier('first'), t.identifier('key')),
261
+ t.objectProperty(t.identifier('newArgv'), t.identifier('restArgv')),
262
+ ]), t.callExpression(t.identifier('extractFirst'), [
263
+ t.identifier('argv'),
264
+ ])),
265
+ ]),
266
+ // const { first: value } = extractFirst(restArgv);
267
+ t.variableDeclaration('const', [
268
+ t.variableDeclarator(t.objectPattern([
269
+ t.objectProperty(t.identifier('first'), t.identifier('value')),
270
+ ]), t.callExpression(t.identifier('extractFirst'), [
271
+ t.identifier('restArgv'),
272
+ ])),
273
+ ]),
274
+ // Prompt if missing key or value
275
+ t.ifStatement(t.logicalExpression('||', t.unaryExpression('!', t.identifier('key')), t.unaryExpression('!', t.identifier('value'))), t.blockStatement([
276
+ t.variableDeclaration('const', [
277
+ t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
278
+ t.objectExpression([
279
+ t.objectProperty(t.identifier('key'), t.identifier('key'), false, true),
280
+ t.objectProperty(t.identifier('value'), t.identifier('value'), false, true),
281
+ ]),
282
+ t.arrayExpression([
283
+ t.objectExpression([
284
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
285
+ t.objectProperty(t.identifier('name'), t.stringLiteral('key')),
286
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config key')),
287
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
288
+ ]),
289
+ t.objectExpression([
290
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
291
+ t.objectProperty(t.identifier('name'), t.stringLiteral('value')),
292
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config value')),
293
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
294
+ ]),
295
+ ]),
296
+ ]))),
297
+ ]),
298
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('setVar')), [
299
+ t.memberExpression(t.identifier('answers'), t.identifier('key')),
300
+ t.callExpression(t.memberExpression(t.identifier('String'), t.identifier('call')), [
301
+ t.identifier('undefined'),
302
+ t.memberExpression(t.identifier('answers'), t.identifier('value')),
303
+ ]),
304
+ ])),
305
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
306
+ t.templateLiteral([
307
+ t.templateElement({ raw: 'Set ', cooked: 'Set ' }),
308
+ t.templateElement({ raw: ' = ', cooked: ' = ' }),
309
+ t.templateElement({ raw: '', cooked: '' }, true),
310
+ ], [
311
+ t.memberExpression(t.identifier('answers'), t.identifier('key')),
312
+ t.memberExpression(t.identifier('answers'), t.identifier('value')),
313
+ ]),
314
+ ])),
315
+ t.returnStatement(),
316
+ ])),
317
+ // store.setVar(key, String(value));
318
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('setVar')), [
319
+ t.identifier('key'),
320
+ t.callExpression(t.identifier('String'), [t.identifier('value')]),
321
+ ])),
322
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
323
+ t.templateLiteral([
324
+ t.templateElement({ raw: 'Set ', cooked: 'Set ' }),
325
+ t.templateElement({ raw: ' = ', cooked: ' = ' }),
326
+ t.templateElement({ raw: '', cooked: '' }, true),
327
+ ], [t.identifier('key'), t.identifier('value')]),
328
+ ])),
329
+ ];
330
+ return t.functionDeclaration(t.identifier('handleSet'), [argvParam, prompterParam, storeParam], t.blockStatement(body), false, true);
331
+ }
332
+ function buildListHandler() {
333
+ const storeParam = t.identifier('store');
334
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
335
+ t.tsTypeQuery(t.identifier('getStore')),
336
+ ])));
337
+ const body = [
338
+ // const vars = store.listVars();
339
+ t.variableDeclaration('const', [
340
+ t.variableDeclarator(t.identifier('vars'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('listVars')), [])),
341
+ ]),
342
+ // const entries = Object.entries(vars);
343
+ t.variableDeclaration('const', [
344
+ t.variableDeclarator(t.identifier('entries'), t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('entries')), [t.identifier('vars')])),
345
+ ]),
346
+ t.ifStatement(t.binaryExpression('===', t.memberExpression(t.identifier('entries'), t.identifier('length')), t.numericLiteral(0)), t.blockStatement([
347
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.stringLiteral('No config values set.')])),
348
+ t.returnStatement(),
349
+ ])),
350
+ // for (const [key, value] of entries) { console.log(`${key} = ${value}`); }
351
+ t.forOfStatement(t.variableDeclaration('const', [
352
+ t.variableDeclarator(t.arrayPattern([t.identifier('key'), t.identifier('value')])),
353
+ ]), t.identifier('entries'), t.blockStatement([
354
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
355
+ t.templateLiteral([
356
+ t.templateElement({ raw: '', cooked: '' }),
357
+ t.templateElement({ raw: ' = ', cooked: ' = ' }),
358
+ t.templateElement({ raw: '', cooked: '' }, true),
359
+ ], [t.identifier('key'), t.identifier('value')]),
360
+ ])),
361
+ ])),
362
+ ];
363
+ return t.functionDeclaration(t.identifier('handleList'), [storeParam], t.blockStatement(body));
364
+ }
365
+ function buildDeleteHandler() {
366
+ const argvParam = t.identifier('argv');
367
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
368
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
369
+ t.tsStringKeyword(),
370
+ t.tsUnknownKeyword(),
371
+ ])),
372
+ ])));
373
+ const prompterParam = t.identifier('prompter');
374
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
375
+ const storeParam = t.identifier('store');
376
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
377
+ t.tsTypeQuery(t.identifier('getStore')),
378
+ ])));
379
+ const body = [
380
+ // const { first: key } = extractFirst(argv);
381
+ t.variableDeclaration('const', [
382
+ t.variableDeclarator(t.objectPattern([
383
+ t.objectProperty(t.identifier('first'), t.identifier('key')),
384
+ ]), t.callExpression(t.identifier('extractFirst'), [
385
+ t.identifier('argv'),
386
+ ])),
387
+ ]),
388
+ // Prompt if no key
389
+ t.ifStatement(t.unaryExpression('!', t.identifier('key')), t.blockStatement([
390
+ t.variableDeclaration('const', [
391
+ t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
392
+ t.identifier('argv'),
393
+ t.arrayExpression([
394
+ t.objectExpression([
395
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
396
+ t.objectProperty(t.identifier('name'), t.stringLiteral('key')),
397
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config key to delete')),
398
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
399
+ ]),
400
+ ]),
401
+ ]))),
402
+ ]),
403
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('deleteVar')), [t.memberExpression(t.identifier('answers'), t.identifier('key'))])),
404
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
405
+ t.templateLiteral([
406
+ t.templateElement({ raw: 'Deleted key: ', cooked: 'Deleted key: ' }),
407
+ t.templateElement({ raw: '', cooked: '' }, true),
408
+ ], [t.memberExpression(t.identifier('answers'), t.identifier('key'))]),
409
+ ])),
410
+ t.returnStatement(),
411
+ ])),
412
+ // store.deleteVar(key);
413
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('deleteVar')), [t.identifier('key')])),
414
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
415
+ t.templateLiteral([
416
+ t.templateElement({ raw: 'Deleted key: ', cooked: 'Deleted key: ' }),
417
+ t.templateElement({ raw: '', cooked: '' }, true),
418
+ ], [t.identifier('key')]),
419
+ ])),
420
+ ];
421
+ return t.functionDeclaration(t.identifier('handleDelete'), [argvParam, prompterParam, storeParam], t.blockStatement(body), false, true);
422
+ }
@@ -0,0 +1,15 @@
1
+ import type { GeneratedFile } from './executor-generator';
2
+ export interface HelpersGeneratorInput {
3
+ name: string;
4
+ ormImportPath: string;
5
+ }
6
+ /**
7
+ * Generate helpers.ts with typed per-target client factories.
8
+ *
9
+ * Each target gets a `createXxxClient(contextName?)` function that uses
10
+ * `store.getClientConfig(targetName, contextName)` under the hood with
11
+ * 3-tier resolution: appstash store -> env vars -> throw.
12
+ *
13
+ * Also re-exports the store for direct config/var access.
14
+ */
15
+ export declare function generateHelpersFile(toolName: string, targets: HelpersGeneratorInput[]): GeneratedFile;
@@ -0,0 +1,83 @@
1
+ import * as t from '@babel/types';
2
+ import { generateCode } from '../babel-ast';
3
+ import { getGeneratedFileHeader } from '../utils';
4
+ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
5
+ const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
6
+ const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
7
+ decl.importKind = typeOnly ? 'type' : 'value';
8
+ return decl;
9
+ }
10
+ /**
11
+ * Generate helpers.ts with typed per-target client factories.
12
+ *
13
+ * Each target gets a `createXxxClient(contextName?)` function that uses
14
+ * `store.getClientConfig(targetName, contextName)` under the hood with
15
+ * 3-tier resolution: appstash store -> env vars -> throw.
16
+ *
17
+ * Also re-exports the store for direct config/var access.
18
+ */
19
+ export function generateHelpersFile(toolName, targets) {
20
+ const statements = [];
21
+ // import { createConfigStore } from 'appstash';
22
+ statements.push(createImportDeclaration('appstash', ['createConfigStore']));
23
+ // import type { ClientConfig } from 'appstash';
24
+ statements.push(createImportDeclaration('appstash', ['ClientConfig'], true));
25
+ // Import createClient from each target's ORM
26
+ for (const target of targets) {
27
+ const aliasName = `create${target.name[0].toUpperCase()}${target.name.slice(1)}OrmClient`;
28
+ const specifier = t.importSpecifier(t.identifier(aliasName), t.identifier('createClient'));
29
+ statements.push(t.importDeclaration([specifier], t.stringLiteral(target.ormImportPath)));
30
+ }
31
+ // const store = createConfigStore('toolName');
32
+ statements.push(t.variableDeclaration('const', [
33
+ t.variableDeclarator(t.identifier('store'), t.callExpression(t.identifier('createConfigStore'), [
34
+ t.stringLiteral(toolName),
35
+ ])),
36
+ ]));
37
+ // export const getStore = () => store;
38
+ const getStoreExport = t.variableDeclaration('const', [
39
+ t.variableDeclarator(t.identifier('getStore'), t.arrowFunctionExpression([], t.identifier('store'))),
40
+ ]);
41
+ statements.push(t.exportNamedDeclaration(getStoreExport));
42
+ // export function getClientConfig(targetName: string, contextName?: string): ClientConfig
43
+ const targetNameParam = t.identifier('targetName');
44
+ targetNameParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
45
+ const contextNameParam = t.identifier('contextName');
46
+ contextNameParam.optional = true;
47
+ contextNameParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
48
+ const getClientConfigBody = t.blockStatement([
49
+ t.returnStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('getClientConfig')), [t.identifier('targetName'), t.identifier('contextName')])),
50
+ ]);
51
+ const getClientConfigFunc = t.functionDeclaration(t.identifier('getClientConfig'), [targetNameParam, contextNameParam], getClientConfigBody);
52
+ // Add return type annotation
53
+ const returnTypeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ClientConfig')));
54
+ getClientConfigFunc.returnType = returnTypeAnnotation;
55
+ statements.push(t.exportNamedDeclaration(getClientConfigFunc));
56
+ // Generate typed factory for each target
57
+ for (const target of targets) {
58
+ const factoryName = `create${target.name[0].toUpperCase()}${target.name.slice(1)}Client`;
59
+ const ormAliasName = `create${target.name[0].toUpperCase()}${target.name.slice(1)}OrmClient`;
60
+ const ctxParam = t.identifier('contextName');
61
+ ctxParam.optional = true;
62
+ ctxParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
63
+ const factoryBody = t.blockStatement([
64
+ t.variableDeclaration('const', [
65
+ t.variableDeclarator(t.identifier('config'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('getClientConfig')), [t.stringLiteral(target.name), t.identifier('contextName')])),
66
+ ]),
67
+ t.returnStatement(t.callExpression(t.identifier(ormAliasName), [
68
+ t.objectExpression([
69
+ t.objectProperty(t.identifier('endpoint'), t.memberExpression(t.identifier('config'), t.identifier('endpoint'))),
70
+ t.objectProperty(t.identifier('headers'), t.memberExpression(t.identifier('config'), t.identifier('headers'))),
71
+ ]),
72
+ ])),
73
+ ]);
74
+ const factoryFunc = t.functionDeclaration(t.identifier(factoryName), [ctxParam], factoryBody);
75
+ statements.push(t.exportNamedDeclaration(factoryFunc));
76
+ }
77
+ const header = getGeneratedFileHeader('SDK helpers — typed per-target client factories with 3-tier credential resolution');
78
+ const code = generateCode(statements);
79
+ return {
80
+ fileName: 'helpers.ts',
81
+ content: header + '\n' + code,
82
+ };
83
+ }
@@ -47,12 +47,16 @@ export interface GenerateMultiTargetCliOptions {
47
47
  export declare function resolveBuiltinNames(targetNames: string[], userOverrides?: BuiltinNames): {
48
48
  auth: string;
49
49
  context: string;
50
+ config: string;
50
51
  };
51
52
  export declare function generateMultiTargetCli(options: GenerateMultiTargetCliOptions): GenerateCliResult;
52
53
  export { generateExecutorFile, generateMultiTargetExecutorFile } from './executor-generator';
53
54
  export { generateTableCommand } from './table-command-generator';
54
55
  export { generateCustomCommand } from './custom-command-generator';
55
56
  export { generateCommandMap, generateMultiTargetCommandMap } from './command-map-generator';
57
+ export { generateConfigCommand } from './config-command-generator';
58
+ export { generateHelpersFile } from './helpers-generator';
59
+ export type { HelpersGeneratorInput } from './helpers-generator';
56
60
  export { generateContextCommand, generateAuthCommand, generateMultiTargetContextCommand, generateAuthCommandWithName, } from './infra-generator';
57
61
  export { generateReadme, generateAgentsDocs, getCliMcpTools, generateSkills, generateMultiTargetReadme, generateMultiTargetAgentsDocs, getMultiTargetCliMcpTools, generateMultiTargetSkills, } from './docs-generator';
58
62
  export type { MultiTargetDocsInput } from './docs-generator';
@@ -1,6 +1,8 @@
1
1
  import { generateCommandMap, generateMultiTargetCommandMap } from './command-map-generator';
2
+ import { generateConfigCommand } from './config-command-generator';
2
3
  import { generateCustomCommand } from './custom-command-generator';
3
4
  import { generateExecutorFile, generateMultiTargetExecutorFile } from './executor-generator';
5
+ import { generateHelpersFile } from './helpers-generator';
4
6
  import { generateAuthCommand, generateAuthCommandWithName, generateContextCommand, generateMultiTargetContextCommand, } from './infra-generator';
5
7
  import { generateTableCommand } from './table-command-generator';
6
8
  import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile } from './utils-generator';
@@ -62,13 +64,17 @@ export function generateCli(options) {
62
64
  export function resolveBuiltinNames(targetNames, userOverrides) {
63
65
  let authName = userOverrides?.auth ?? 'auth';
64
66
  let contextName = userOverrides?.context ?? 'context';
67
+ let configName = userOverrides?.config ?? 'config';
65
68
  if (targetNames.includes(authName) && !userOverrides?.auth) {
66
69
  authName = 'credentials';
67
70
  }
68
71
  if (targetNames.includes(contextName) && !userOverrides?.context) {
69
72
  contextName = 'env';
70
73
  }
71
- return { auth: authName, context: contextName };
74
+ if (targetNames.includes(configName) && !userOverrides?.config) {
75
+ configName = 'vars';
76
+ }
77
+ return { auth: authName, context: contextName, config: configName };
72
78
  }
73
79
  export function generateMultiTargetCli(options) {
74
80
  const { toolName, targets } = options;
@@ -94,6 +100,14 @@ export function generateMultiTargetCli(options) {
94
100
  files.push(contextFile);
95
101
  const authFile = generateAuthCommandWithName(toolName, builtinNames.auth);
96
102
  files.push(authFile);
103
+ const configFile = generateConfigCommand(toolName, builtinNames.config);
104
+ files.push(configFile);
105
+ const helpersInputs = targets.map((t) => ({
106
+ name: t.name,
107
+ ormImportPath: t.ormImportPath,
108
+ }));
109
+ const helpersFile = generateHelpersFile(toolName, helpersInputs);
110
+ files.push(helpersFile);
97
111
  let totalTables = 0;
98
112
  let totalQueries = 0;
99
113
  let totalMutations = 0;
@@ -145,7 +159,7 @@ export function generateMultiTargetCli(options) {
145
159
  tables: totalTables,
146
160
  customQueries: totalQueries,
147
161
  customMutations: totalMutations,
148
- infraFiles: 4,
162
+ infraFiles: 6,
149
163
  totalFiles: files.length,
150
164
  },
151
165
  };
@@ -154,6 +168,8 @@ export { generateExecutorFile, generateMultiTargetExecutorFile } from './executo
154
168
  export { generateTableCommand } from './table-command-generator';
155
169
  export { generateCustomCommand } from './custom-command-generator';
156
170
  export { generateCommandMap, generateMultiTargetCommandMap } from './command-map-generator';
171
+ export { generateConfigCommand } from './config-command-generator';
172
+ export { generateHelpersFile } from './helpers-generator';
157
173
  export { generateContextCommand, generateAuthCommand, generateMultiTargetContextCommand, generateAuthCommandWithName, } from './infra-generator';
158
174
  export { generateReadme, generateAgentsDocs, getCliMcpTools, generateSkills, generateMultiTargetReadme, generateMultiTargetAgentsDocs, getMultiTargetCliMcpTools, generateMultiTargetSkills, } from './docs-generator';
159
175
  export { resolveDocsConfig } from '../docs-utils';
@@ -9,6 +9,7 @@ import { generateAllModelFiles } from './model-generator';
9
9
  export function generateOrm(options) {
10
10
  const { tables, customOperations, sharedTypesPath } = options;
11
11
  const commentsEnabled = options.config.codegen?.comments !== false;
12
+ const conditionEnabled = options.config.codegen?.condition !== false;
12
13
  const files = [];
13
14
  // Use shared types when a sharedTypesPath is provided (unified output mode)
14
15
  const useSharedTypes = !!sharedTypesPath;
@@ -29,7 +30,7 @@ export function generateOrm(options) {
29
30
  content: selectTypesFile.content,
30
31
  });
31
32
  // 2. Generate model files
32
- const modelFiles = generateAllModelFiles(tables, useSharedTypes);
33
+ const modelFiles = generateAllModelFiles(tables, useSharedTypes, { condition: conditionEnabled });
33
34
  for (const modelFile of modelFiles) {
34
35
  files.push({
35
36
  path: `models/${modelFile.fileName}`,
@@ -66,7 +67,7 @@ export function generateOrm(options) {
66
67
  }
67
68
  }
68
69
  }
69
- const inputTypesFile = generateInputTypesFile(typeRegistry ?? new Map(), usedInputTypes, tables, usedPayloadTypes, commentsEnabled);
70
+ const inputTypesFile = generateInputTypesFile(typeRegistry ?? new Map(), usedInputTypes, tables, usedPayloadTypes, commentsEnabled, { condition: conditionEnabled });
70
71
  files.push({
71
72
  path: inputTypesFile.fileName,
72
73
  content: inputTypesFile.content,
@@ -18,4 +18,6 @@ export declare function collectPayloadTypeNames(operations: Array<{
18
18
  /**
19
19
  * Generate comprehensive input-types.ts file using Babel AST
20
20
  */
21
- export declare function generateInputTypesFile(typeRegistry: TypeRegistry, usedInputTypes: Set<string>, tables?: CleanTable[], usedPayloadTypes?: Set<string>, comments?: boolean): GeneratedInputTypesFile;
21
+ export declare function generateInputTypesFile(typeRegistry: TypeRegistry, usedInputTypes: Set<string>, tables?: CleanTable[], usedPayloadTypes?: Set<string>, comments?: boolean, options?: {
22
+ condition?: boolean;
23
+ }): GeneratedInputTypesFile;