@constructive-io/graphql-codegen 4.9.0 → 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 (59) hide show
  1. package/core/codegen/cli/arg-mapper.d.ts +1 -1
  2. package/core/codegen/cli/arg-mapper.js +15 -11
  3. package/core/codegen/cli/command-map-generator.d.ts +1 -0
  4. package/core/codegen/cli/command-map-generator.js +4 -0
  5. package/core/codegen/cli/config-command-generator.d.ts +11 -0
  6. package/core/codegen/cli/config-command-generator.js +458 -0
  7. package/core/codegen/cli/custom-command-generator.js +4 -3
  8. package/core/codegen/cli/docs-generator.d.ts +6 -5
  9. package/core/codegen/cli/docs-generator.js +167 -64
  10. package/core/codegen/cli/helpers-generator.d.ts +15 -0
  11. package/core/codegen/cli/helpers-generator.js +119 -0
  12. package/core/codegen/cli/index.d.ts +4 -0
  13. package/core/codegen/cli/index.js +21 -3
  14. package/core/codegen/cli/table-command-generator.d.ts +15 -0
  15. package/core/codegen/cli/table-command-generator.js +20 -1
  16. package/core/codegen/docs-utils.d.ts +26 -1
  17. package/core/codegen/docs-utils.js +105 -0
  18. package/core/codegen/orm/index.js +3 -2
  19. package/core/codegen/orm/input-types-generator.d.ts +3 -1
  20. package/core/codegen/orm/input-types-generator.js +123 -17
  21. package/core/codegen/orm/model-generator.d.ts +6 -2
  22. package/core/codegen/orm/model-generator.js +59 -29
  23. package/core/codegen/orm/select-types.d.ts +4 -2
  24. package/core/codegen/scalars.js +8 -0
  25. package/core/codegen/templates/cli-entry.ts +2 -2
  26. package/core/codegen/templates/cli-utils.ts +28 -0
  27. package/core/codegen/templates/query-builder.ts +28 -5
  28. package/core/codegen/templates/select-types.ts +4 -2
  29. package/core/generate.js +14 -4
  30. package/esm/core/codegen/cli/arg-mapper.d.ts +1 -1
  31. package/esm/core/codegen/cli/arg-mapper.js +15 -11
  32. package/esm/core/codegen/cli/command-map-generator.d.ts +1 -0
  33. package/esm/core/codegen/cli/command-map-generator.js +4 -0
  34. package/esm/core/codegen/cli/config-command-generator.d.ts +11 -0
  35. package/esm/core/codegen/cli/config-command-generator.js +422 -0
  36. package/esm/core/codegen/cli/custom-command-generator.js +4 -3
  37. package/esm/core/codegen/cli/docs-generator.d.ts +6 -5
  38. package/esm/core/codegen/cli/docs-generator.js +168 -65
  39. package/esm/core/codegen/cli/helpers-generator.d.ts +15 -0
  40. package/esm/core/codegen/cli/helpers-generator.js +83 -0
  41. package/esm/core/codegen/cli/index.d.ts +4 -0
  42. package/esm/core/codegen/cli/index.js +18 -2
  43. package/esm/core/codegen/cli/table-command-generator.d.ts +15 -0
  44. package/esm/core/codegen/cli/table-command-generator.js +20 -3
  45. package/esm/core/codegen/docs-utils.d.ts +26 -1
  46. package/esm/core/codegen/docs-utils.js +102 -0
  47. package/esm/core/codegen/orm/index.js +3 -2
  48. package/esm/core/codegen/orm/input-types-generator.d.ts +3 -1
  49. package/esm/core/codegen/orm/input-types-generator.js +123 -17
  50. package/esm/core/codegen/orm/model-generator.d.ts +6 -2
  51. package/esm/core/codegen/orm/model-generator.js +59 -29
  52. package/esm/core/codegen/orm/select-types.d.ts +4 -2
  53. package/esm/core/codegen/scalars.js +8 -0
  54. package/esm/core/generate.js +14 -4
  55. package/esm/types/config.d.ts +9 -0
  56. package/esm/types/config.js +1 -0
  57. package/package.json +11 -11
  58. package/types/config.d.ts +9 -0
  59. package/types/config.js +1 -0
@@ -1,4 +1,4 @@
1
1
  import * as t from '@babel/types';
2
2
  import type { CleanArgument } from '../../../types/schema';
3
- export declare function buildQuestionObject(arg: CleanArgument): t.ObjectExpression;
3
+ export declare function buildQuestionObject(arg: CleanArgument, namePrefix?: string): t.ObjectExpression;
4
4
  export declare function buildQuestionsArray(args: CleanArgument[]): t.ArrayExpression;
@@ -48,35 +48,37 @@ function resolveBaseType(typeRef) {
48
48
  }
49
49
  return typeRef;
50
50
  }
51
- function buildQuestionObject(arg) {
51
+ function buildQuestionObject(arg, namePrefix) {
52
52
  const { inner, required } = unwrapNonNull(arg.type);
53
53
  const base = resolveBaseType(arg.type);
54
54
  const props = [];
55
+ const questionName = namePrefix ? `${namePrefix}.${arg.name}` : arg.name;
55
56
  if (base.kind === 'ENUM' && base.enumValues && base.enumValues.length > 0) {
56
57
  props.push(t.objectProperty(t.identifier('type'), t.stringLiteral('autocomplete')));
57
- props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(arg.name)));
58
- props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || arg.name)));
58
+ props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(questionName)));
59
+ props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || questionName)));
59
60
  props.push(t.objectProperty(t.identifier('options'), t.arrayExpression(base.enumValues.map((v) => t.stringLiteral(v)))));
60
61
  }
61
62
  else if (base.kind === 'SCALAR' && base.name === 'Boolean') {
62
63
  props.push(t.objectProperty(t.identifier('type'), t.stringLiteral('confirm')));
63
- props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(arg.name)));
64
- props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || arg.name)));
64
+ props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(questionName)));
65
+ props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || questionName)));
65
66
  props.push(t.objectProperty(t.identifier('default'), t.booleanLiteral(false)));
66
67
  }
67
68
  else if (base.kind === 'SCALAR' &&
68
69
  (base.name === 'Int' || base.name === 'Float')) {
69
70
  props.push(t.objectProperty(t.identifier('type'), t.stringLiteral('text')));
70
- props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(arg.name)));
71
- props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || `${arg.name} (number)`)));
71
+ props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(questionName)));
72
+ props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || `${questionName} (number)`)));
72
73
  }
73
74
  else if (inner.kind === 'INPUT_OBJECT' && inner.inputFields) {
75
+ // INPUT_OBJECT fields are flattened in buildQuestionsArray with dot-notation
74
76
  return buildInputObjectQuestion(arg.name, inner, required);
75
77
  }
76
78
  else {
77
79
  props.push(t.objectProperty(t.identifier('type'), t.stringLiteral('text')));
78
- props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(arg.name)));
79
- props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || arg.name)));
80
+ props.push(t.objectProperty(t.identifier('name'), t.stringLiteral(questionName)));
81
+ props.push(t.objectProperty(t.identifier('message'), t.stringLiteral(arg.description || questionName)));
80
82
  }
81
83
  if (required) {
82
84
  props.push(t.objectProperty(t.identifier('required'), t.booleanLiteral(true)));
@@ -100,13 +102,15 @@ function buildQuestionsArray(args) {
100
102
  const base = resolveBaseType(arg.type);
101
103
  const { inner } = unwrapNonNull(arg.type);
102
104
  if (inner.kind === 'INPUT_OBJECT' && inner.inputFields) {
105
+ // Flatten INPUT_OBJECT fields with dot-notation: e.g. input.email, input.password
103
106
  for (const field of inner.inputFields) {
104
- questions.push(buildQuestionObject(field));
107
+ questions.push(buildQuestionObject(field, arg.name));
105
108
  }
106
109
  }
107
110
  else if (base.kind === 'INPUT_OBJECT' && base.inputFields) {
111
+ // Same for NON_NULL-wrapped INPUT_OBJECT
108
112
  for (const field of base.inputFields) {
109
- questions.push(buildQuestionObject(field));
113
+ questions.push(buildQuestionObject(field, arg.name));
110
114
  }
111
115
  }
112
116
  else {
@@ -6,6 +6,7 @@ export interface MultiTargetCommandMapInput {
6
6
  builtinNames: {
7
7
  auth: string;
8
8
  context: string;
9
+ config: string;
9
10
  };
10
11
  targets: Array<{
11
12
  name: string;
@@ -223,6 +223,9 @@ function generateMultiTargetCommandMap(input) {
223
223
  const authImportName = `${builtinNames.auth}Cmd`;
224
224
  commandEntries.push({ kebab: builtinNames.auth, importName: authImportName });
225
225
  statements.push(createImportDeclaration(`./commands/${builtinNames.auth}`, authImportName));
226
+ const configImportName = `${builtinNames.config}Cmd`;
227
+ commandEntries.push({ kebab: builtinNames.config, importName: configImportName });
228
+ statements.push(createImportDeclaration(`./commands/${builtinNames.config}`, configImportName));
226
229
  for (const target of targets) {
227
230
  for (const table of target.tables) {
228
231
  const { singularName } = (0, utils_1.getTableNames)(table);
@@ -259,6 +262,7 @@ function generateMultiTargetCommandMap(input) {
259
262
  'Commands:',
260
263
  ` ${builtinNames.context.padEnd(20)} Manage API contexts`,
261
264
  ` ${builtinNames.auth.padEnd(20)} Manage authentication`,
265
+ ` ${builtinNames.config.padEnd(20)} Manage config key-value store`,
262
266
  ];
263
267
  for (const target of targets) {
264
268
  usageLines.push('');
@@ -0,0 +1,11 @@
1
+ import type { GeneratedFile } from './executor-generator';
2
+ /**
3
+ * Generate the config command file (get/set/list/delete for per-context vars).
4
+ *
5
+ * Usage:
6
+ * <tool> config get <key>
7
+ * <tool> config set <key> <value>
8
+ * <tool> config list
9
+ * <tool> config delete <key>
10
+ */
11
+ export declare function generateConfigCommand(toolName: string, commandName: string): GeneratedFile;
@@ -0,0 +1,458 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateConfigCommand = generateConfigCommand;
37
+ const t = __importStar(require("@babel/types"));
38
+ const babel_ast_1 = require("../babel-ast");
39
+ const utils_1 = require("../utils");
40
+ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
41
+ const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
42
+ const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
43
+ decl.importKind = typeOnly ? 'type' : 'value';
44
+ return decl;
45
+ }
46
+ function buildSwitchCase(testValue, handlerName, args) {
47
+ return t.switchCase(t.stringLiteral(testValue), [
48
+ t.returnStatement(t.callExpression(t.identifier(handlerName), args)),
49
+ ]);
50
+ }
51
+ function buildDefaultSwitchCase(usageVarName) {
52
+ return t.switchCase(null, [
53
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier(usageVarName)])),
54
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
55
+ ]);
56
+ }
57
+ /**
58
+ * Generate the config command file (get/set/list/delete for per-context vars).
59
+ *
60
+ * Usage:
61
+ * <tool> config get <key>
62
+ * <tool> config set <key> <value>
63
+ * <tool> config list
64
+ * <tool> config delete <key>
65
+ */
66
+ function generateConfigCommand(toolName, commandName) {
67
+ const statements = [];
68
+ statements.push(createImportDeclaration('inquirerer', [
69
+ 'CLIOptions',
70
+ 'Inquirerer',
71
+ 'extractFirst',
72
+ ]));
73
+ statements.push(createImportDeclaration('../executor', ['getStore']));
74
+ const usageStr = `
75
+ ${toolName} ${commandName} <command>
76
+
77
+ Commands:
78
+ get <key> Get a config value
79
+ set <key> <value> Set a config value
80
+ list List all config values
81
+ delete <key> Delete a config value
82
+
83
+ --help, -h Show this help message
84
+ `;
85
+ statements.push(t.variableDeclaration('const', [
86
+ t.variableDeclarator(t.identifier('usage'), t.stringLiteral(usageStr)),
87
+ ]));
88
+ // Main export: default async (argv, prompter, _options) => { ... }
89
+ const argvParam = t.identifier('argv');
90
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
91
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
92
+ t.tsStringKeyword(),
93
+ t.tsUnknownKeyword(),
94
+ ])),
95
+ ])));
96
+ const prompterParam = t.identifier('prompter');
97
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
98
+ const optionsParam = t.identifier('_options');
99
+ optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CLIOptions')));
100
+ const mainBody = [
101
+ // Help check
102
+ t.ifStatement(t.logicalExpression('||', t.memberExpression(t.identifier('argv'), t.identifier('help')), t.memberExpression(t.identifier('argv'), t.identifier('h'))), t.blockStatement([
103
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('usage')])),
104
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(0)])),
105
+ ])),
106
+ // const store = getStore();
107
+ t.variableDeclaration('const', [
108
+ t.variableDeclarator(t.identifier('store'), t.callExpression(t.identifier('getStore'), [])),
109
+ ]),
110
+ // const { first: subcommand, newArgv } = extractFirst(argv);
111
+ t.variableDeclaration('const', [
112
+ t.variableDeclarator(t.objectPattern([
113
+ t.objectProperty(t.identifier('first'), t.identifier('subcommand')),
114
+ t.objectProperty(t.identifier('newArgv'), t.identifier('newArgv'), false, true),
115
+ ]), t.callExpression(t.identifier('extractFirst'), [
116
+ t.identifier('argv'),
117
+ ])),
118
+ ]),
119
+ // If no subcommand, prompt
120
+ t.ifStatement(t.unaryExpression('!', t.identifier('subcommand')), t.blockStatement([
121
+ t.variableDeclaration('const', [
122
+ t.variableDeclarator(t.identifier('answer'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
123
+ t.identifier('argv'),
124
+ t.arrayExpression([
125
+ t.objectExpression([
126
+ t.objectProperty(t.identifier('type'), t.stringLiteral('autocomplete')),
127
+ t.objectProperty(t.identifier('name'), t.stringLiteral('subcommand')),
128
+ t.objectProperty(t.identifier('message'), t.stringLiteral('What do you want to do?')),
129
+ t.objectProperty(t.identifier('options'), t.arrayExpression([
130
+ t.stringLiteral('get'),
131
+ t.stringLiteral('set'),
132
+ t.stringLiteral('list'),
133
+ t.stringLiteral('delete'),
134
+ ])),
135
+ ]),
136
+ ]),
137
+ ]))),
138
+ ]),
139
+ t.returnStatement(t.callExpression(t.identifier('handleSubcommand'), [
140
+ t.memberExpression(t.identifier('answer'), t.identifier('subcommand')),
141
+ t.identifier('newArgv'),
142
+ t.identifier('prompter'),
143
+ t.identifier('store'),
144
+ ])),
145
+ ])),
146
+ t.returnStatement(t.callExpression(t.identifier('handleSubcommand'), [
147
+ t.identifier('subcommand'),
148
+ t.identifier('newArgv'),
149
+ t.identifier('prompter'),
150
+ t.identifier('store'),
151
+ ])),
152
+ ];
153
+ const mainExport = t.exportDefaultDeclaration(t.arrowFunctionExpression([argvParam, prompterParam, optionsParam], t.blockStatement(mainBody), true));
154
+ statements.push(mainExport);
155
+ // handleSubcommand function
156
+ const subcmdParam = t.identifier('subcommand');
157
+ subcmdParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
158
+ const argvParam2 = t.identifier('argv');
159
+ argvParam2.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
160
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
161
+ t.tsStringKeyword(),
162
+ t.tsUnknownKeyword(),
163
+ ])),
164
+ ])));
165
+ const prompterParam2 = t.identifier('prompter');
166
+ prompterParam2.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
167
+ const storeParam = t.identifier('store');
168
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
169
+ t.tsTypeQuery(t.identifier('getStore')),
170
+ ])));
171
+ const handleSubcommandFunc = t.functionDeclaration(t.identifier('handleSubcommand'), [subcmdParam, argvParam2, prompterParam2, storeParam], t.blockStatement([
172
+ t.switchStatement(t.identifier('subcommand'), [
173
+ buildSwitchCase('get', 'handleGet', [
174
+ t.identifier('argv'),
175
+ t.identifier('prompter'),
176
+ t.identifier('store'),
177
+ ]),
178
+ buildSwitchCase('set', 'handleSet', [
179
+ t.identifier('argv'),
180
+ t.identifier('prompter'),
181
+ t.identifier('store'),
182
+ ]),
183
+ buildSwitchCase('list', 'handleList', [t.identifier('store')]),
184
+ buildSwitchCase('delete', 'handleDelete', [
185
+ t.identifier('argv'),
186
+ t.identifier('prompter'),
187
+ t.identifier('store'),
188
+ ]),
189
+ buildDefaultSwitchCase('usage'),
190
+ ]),
191
+ ]), false, true);
192
+ statements.push(handleSubcommandFunc);
193
+ // handleGet
194
+ statements.push(buildGetHandler());
195
+ // handleSet
196
+ statements.push(buildSetHandler());
197
+ // handleList
198
+ statements.push(buildListHandler());
199
+ // handleDelete
200
+ statements.push(buildDeleteHandler());
201
+ const header = (0, utils_1.getGeneratedFileHeader)('Config key-value store commands');
202
+ const code = (0, babel_ast_1.generateCode)(statements);
203
+ return {
204
+ fileName: `commands/${commandName}.ts`,
205
+ content: header + '\n' + code,
206
+ };
207
+ }
208
+ function buildGetHandler() {
209
+ const argvParam = t.identifier('argv');
210
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
211
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
212
+ t.tsStringKeyword(),
213
+ t.tsUnknownKeyword(),
214
+ ])),
215
+ ])));
216
+ const prompterParam = t.identifier('prompter');
217
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
218
+ const storeParam = t.identifier('store');
219
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
220
+ t.tsTypeQuery(t.identifier('getStore')),
221
+ ])));
222
+ const body = [
223
+ // const { first: key } = extractFirst(argv);
224
+ t.variableDeclaration('const', [
225
+ t.variableDeclarator(t.objectPattern([
226
+ t.objectProperty(t.identifier('first'), t.identifier('key')),
227
+ ]), t.callExpression(t.identifier('extractFirst'), [
228
+ t.identifier('argv'),
229
+ ])),
230
+ ]),
231
+ // Prompt if no key
232
+ t.ifStatement(t.unaryExpression('!', t.identifier('key')), t.blockStatement([
233
+ t.variableDeclaration('const', [
234
+ t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
235
+ t.identifier('argv'),
236
+ t.arrayExpression([
237
+ t.objectExpression([
238
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
239
+ t.objectProperty(t.identifier('name'), t.stringLiteral('key')),
240
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config key')),
241
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
242
+ ]),
243
+ ]),
244
+ ]))),
245
+ ]),
246
+ t.variableDeclaration('const', [
247
+ t.variableDeclarator(t.identifier('value'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('getVar')), [t.memberExpression(t.identifier('answers'), t.identifier('key'))])),
248
+ ]),
249
+ t.ifStatement(t.binaryExpression('===', t.identifier('value'), t.identifier('undefined')), t.blockStatement([
250
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [
251
+ t.templateLiteral([
252
+ t.templateElement({ raw: 'Key "', cooked: 'Key "' }),
253
+ t.templateElement({ raw: '" not found.', cooked: '" not found.' }, true),
254
+ ], [t.memberExpression(t.identifier('answers'), t.identifier('key'))]),
255
+ ])),
256
+ ]), t.blockStatement([
257
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('value')])),
258
+ ])),
259
+ t.returnStatement(),
260
+ ])),
261
+ // const value = store.getVar(key);
262
+ t.variableDeclaration('const', [
263
+ t.variableDeclarator(t.identifier('value'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('getVar')), [t.identifier('key')])),
264
+ ]),
265
+ t.ifStatement(t.binaryExpression('===', t.identifier('value'), t.identifier('undefined')), t.blockStatement([
266
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [
267
+ t.templateLiteral([
268
+ t.templateElement({ raw: 'Key "', cooked: 'Key "' }),
269
+ t.templateElement({ raw: '" not found.', cooked: '" not found.' }, true),
270
+ ], [t.identifier('key')]),
271
+ ])),
272
+ ]), t.blockStatement([
273
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('value')])),
274
+ ])),
275
+ ];
276
+ return t.functionDeclaration(t.identifier('handleGet'), [argvParam, prompterParam, storeParam], t.blockStatement(body), false, true);
277
+ }
278
+ function buildSetHandler() {
279
+ const argvParam = t.identifier('argv');
280
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
281
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
282
+ t.tsStringKeyword(),
283
+ t.tsUnknownKeyword(),
284
+ ])),
285
+ ])));
286
+ const prompterParam = t.identifier('prompter');
287
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
288
+ const storeParam = t.identifier('store');
289
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
290
+ t.tsTypeQuery(t.identifier('getStore')),
291
+ ])));
292
+ const body = [
293
+ // const { first: key, newArgv: restArgv } = extractFirst(argv);
294
+ t.variableDeclaration('const', [
295
+ t.variableDeclarator(t.objectPattern([
296
+ t.objectProperty(t.identifier('first'), t.identifier('key')),
297
+ t.objectProperty(t.identifier('newArgv'), t.identifier('restArgv')),
298
+ ]), t.callExpression(t.identifier('extractFirst'), [
299
+ t.identifier('argv'),
300
+ ])),
301
+ ]),
302
+ // const { first: value } = extractFirst(restArgv);
303
+ t.variableDeclaration('const', [
304
+ t.variableDeclarator(t.objectPattern([
305
+ t.objectProperty(t.identifier('first'), t.identifier('value')),
306
+ ]), t.callExpression(t.identifier('extractFirst'), [
307
+ t.identifier('restArgv'),
308
+ ])),
309
+ ]),
310
+ // Prompt if missing key or value
311
+ t.ifStatement(t.logicalExpression('||', t.unaryExpression('!', t.identifier('key')), t.unaryExpression('!', t.identifier('value'))), t.blockStatement([
312
+ t.variableDeclaration('const', [
313
+ t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
314
+ t.objectExpression([
315
+ t.objectProperty(t.identifier('key'), t.identifier('key'), false, true),
316
+ t.objectProperty(t.identifier('value'), t.identifier('value'), false, true),
317
+ ]),
318
+ t.arrayExpression([
319
+ t.objectExpression([
320
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
321
+ t.objectProperty(t.identifier('name'), t.stringLiteral('key')),
322
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config key')),
323
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
324
+ ]),
325
+ t.objectExpression([
326
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
327
+ t.objectProperty(t.identifier('name'), t.stringLiteral('value')),
328
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config value')),
329
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
330
+ ]),
331
+ ]),
332
+ ]))),
333
+ ]),
334
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('setVar')), [
335
+ t.memberExpression(t.identifier('answers'), t.identifier('key')),
336
+ t.callExpression(t.memberExpression(t.identifier('String'), t.identifier('call')), [
337
+ t.identifier('undefined'),
338
+ t.memberExpression(t.identifier('answers'), t.identifier('value')),
339
+ ]),
340
+ ])),
341
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
342
+ t.templateLiteral([
343
+ t.templateElement({ raw: 'Set ', cooked: 'Set ' }),
344
+ t.templateElement({ raw: ' = ', cooked: ' = ' }),
345
+ t.templateElement({ raw: '', cooked: '' }, true),
346
+ ], [
347
+ t.memberExpression(t.identifier('answers'), t.identifier('key')),
348
+ t.memberExpression(t.identifier('answers'), t.identifier('value')),
349
+ ]),
350
+ ])),
351
+ t.returnStatement(),
352
+ ])),
353
+ // store.setVar(key, String(value));
354
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('setVar')), [
355
+ t.identifier('key'),
356
+ t.callExpression(t.identifier('String'), [t.identifier('value')]),
357
+ ])),
358
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
359
+ t.templateLiteral([
360
+ t.templateElement({ raw: 'Set ', cooked: 'Set ' }),
361
+ t.templateElement({ raw: ' = ', cooked: ' = ' }),
362
+ t.templateElement({ raw: '', cooked: '' }, true),
363
+ ], [t.identifier('key'), t.identifier('value')]),
364
+ ])),
365
+ ];
366
+ return t.functionDeclaration(t.identifier('handleSet'), [argvParam, prompterParam, storeParam], t.blockStatement(body), false, true);
367
+ }
368
+ function buildListHandler() {
369
+ const storeParam = t.identifier('store');
370
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
371
+ t.tsTypeQuery(t.identifier('getStore')),
372
+ ])));
373
+ const body = [
374
+ // const vars = store.listVars();
375
+ t.variableDeclaration('const', [
376
+ t.variableDeclarator(t.identifier('vars'), t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('listVars')), [])),
377
+ ]),
378
+ // const entries = Object.entries(vars);
379
+ t.variableDeclaration('const', [
380
+ t.variableDeclarator(t.identifier('entries'), t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('entries')), [t.identifier('vars')])),
381
+ ]),
382
+ t.ifStatement(t.binaryExpression('===', t.memberExpression(t.identifier('entries'), t.identifier('length')), t.numericLiteral(0)), t.blockStatement([
383
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.stringLiteral('No config values set.')])),
384
+ t.returnStatement(),
385
+ ])),
386
+ // for (const [key, value] of entries) { console.log(`${key} = ${value}`); }
387
+ t.forOfStatement(t.variableDeclaration('const', [
388
+ t.variableDeclarator(t.arrayPattern([t.identifier('key'), t.identifier('value')])),
389
+ ]), t.identifier('entries'), t.blockStatement([
390
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
391
+ t.templateLiteral([
392
+ t.templateElement({ raw: '', cooked: '' }),
393
+ t.templateElement({ raw: ' = ', cooked: ' = ' }),
394
+ t.templateElement({ raw: '', cooked: '' }, true),
395
+ ], [t.identifier('key'), t.identifier('value')]),
396
+ ])),
397
+ ])),
398
+ ];
399
+ return t.functionDeclaration(t.identifier('handleList'), [storeParam], t.blockStatement(body));
400
+ }
401
+ function buildDeleteHandler() {
402
+ const argvParam = t.identifier('argv');
403
+ argvParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
404
+ t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
405
+ t.tsStringKeyword(),
406
+ t.tsUnknownKeyword(),
407
+ ])),
408
+ ])));
409
+ const prompterParam = t.identifier('prompter');
410
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
411
+ const storeParam = t.identifier('store');
412
+ storeParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ReturnType'), t.tsTypeParameterInstantiation([
413
+ t.tsTypeQuery(t.identifier('getStore')),
414
+ ])));
415
+ const body = [
416
+ // const { first: key } = extractFirst(argv);
417
+ t.variableDeclaration('const', [
418
+ t.variableDeclarator(t.objectPattern([
419
+ t.objectProperty(t.identifier('first'), t.identifier('key')),
420
+ ]), t.callExpression(t.identifier('extractFirst'), [
421
+ t.identifier('argv'),
422
+ ])),
423
+ ]),
424
+ // Prompt if no key
425
+ t.ifStatement(t.unaryExpression('!', t.identifier('key')), t.blockStatement([
426
+ t.variableDeclaration('const', [
427
+ t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
428
+ t.identifier('argv'),
429
+ t.arrayExpression([
430
+ t.objectExpression([
431
+ t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
432
+ t.objectProperty(t.identifier('name'), t.stringLiteral('key')),
433
+ t.objectProperty(t.identifier('message'), t.stringLiteral('Config key to delete')),
434
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
435
+ ]),
436
+ ]),
437
+ ]))),
438
+ ]),
439
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('deleteVar')), [t.memberExpression(t.identifier('answers'), t.identifier('key'))])),
440
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
441
+ t.templateLiteral([
442
+ t.templateElement({ raw: 'Deleted key: ', cooked: 'Deleted key: ' }),
443
+ t.templateElement({ raw: '', cooked: '' }, true),
444
+ ], [t.memberExpression(t.identifier('answers'), t.identifier('key'))]),
445
+ ])),
446
+ t.returnStatement(),
447
+ ])),
448
+ // store.deleteVar(key);
449
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('store'), t.identifier('deleteVar')), [t.identifier('key')])),
450
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
451
+ t.templateLiteral([
452
+ t.templateElement({ raw: 'Deleted key: ', cooked: 'Deleted key: ' }),
453
+ t.templateElement({ raw: '', cooked: '' }, true),
454
+ ], [t.identifier('key')]),
455
+ ])),
456
+ ];
457
+ return t.functionDeclaration(t.identifier('handleDelete'), [argvParam, prompterParam, storeParam], t.blockStatement(body), false, true);
458
+ }
@@ -155,7 +155,7 @@ function generateCustomCommand(op, options) {
155
155
  // Build the list of utils imports needed
156
156
  const utilsImports = [];
157
157
  if (hasInputObjectArg) {
158
- utilsImports.push('parseMutationInput');
158
+ utilsImports.push('unflattenDotNotation');
159
159
  }
160
160
  if (isObjectReturn) {
161
161
  utilsImports.push('buildSelectFromPaths');
@@ -204,10 +204,11 @@ function generateCustomCommand(op, options) {
204
204
  t.variableDeclarator(t.identifier('client'), t.callExpression(t.identifier('getClient'), getClientArgs)),
205
205
  ]));
206
206
  // For mutations with INPUT_OBJECT args (like `input: SignUpInput`),
207
- // parse JSON strings from CLI into proper objects
207
+ // reconstruct nested objects from dot-notation CLI answers.
208
+ // e.g. { 'input.email': 'foo', 'input.password': 'bar' } → { input: { email: 'foo', password: 'bar' } }
208
209
  if (hasInputObjectArg && op.args.length > 0) {
209
210
  bodyStatements.push(t.variableDeclaration('const', [
210
- t.variableDeclarator(t.identifier('parsedAnswers'), t.callExpression(t.identifier('parseMutationInput'), [
211
+ t.variableDeclarator(t.identifier('parsedAnswers'), t.callExpression(t.identifier('unflattenDotNotation'), [
211
212
  t.identifier('answers'),
212
213
  ])),
213
214
  ]));
@@ -1,17 +1,18 @@
1
- import type { CleanTable, CleanOperation } from '../../../types/schema';
1
+ import type { CleanTable, CleanOperation, TypeRegistry } from '../../../types/schema';
2
2
  import type { GeneratedDocFile, McpTool } from '../docs-utils';
3
3
  export { resolveDocsConfig } from '../docs-utils';
4
4
  export type { GeneratedDocFile, McpTool } from '../docs-utils';
5
- export declare function generateReadme(tables: CleanTable[], customOperations: CleanOperation[], toolName: string): GeneratedDocFile;
6
- export declare function generateAgentsDocs(tables: CleanTable[], customOperations: CleanOperation[], toolName: string): GeneratedDocFile;
7
- export declare function getCliMcpTools(tables: CleanTable[], customOperations: CleanOperation[], toolName: string): McpTool[];
8
- export declare function generateSkills(tables: CleanTable[], customOperations: CleanOperation[], toolName: string, targetName: string): GeneratedDocFile[];
5
+ export declare function generateReadme(tables: CleanTable[], customOperations: CleanOperation[], toolName: string, registry?: TypeRegistry): GeneratedDocFile;
6
+ export declare function generateAgentsDocs(tables: CleanTable[], customOperations: CleanOperation[], toolName: string, registry?: TypeRegistry): GeneratedDocFile;
7
+ export declare function getCliMcpTools(tables: CleanTable[], customOperations: CleanOperation[], toolName: string, registry?: TypeRegistry): McpTool[];
8
+ export declare function generateSkills(tables: CleanTable[], customOperations: CleanOperation[], toolName: string, targetName: string, registry?: TypeRegistry): GeneratedDocFile[];
9
9
  export interface MultiTargetDocsInput {
10
10
  toolName: string;
11
11
  builtinNames: {
12
12
  auth: string;
13
13
  context: string;
14
14
  };
15
+ registry?: TypeRegistry;
15
16
  targets: Array<{
16
17
  name: string;
17
18
  endpoint: string;