@constructive-io/graphql-codegen 4.0.2 → 4.1.1
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/cli/handler.d.ts +13 -0
- package/cli/handler.js +74 -0
- package/cli/index.js +11 -57
- package/core/codegen/barrel.d.ts +1 -0
- package/core/codegen/barrel.js +5 -2
- package/core/codegen/cli/arg-mapper.d.ts +4 -0
- package/core/codegen/cli/arg-mapper.js +117 -0
- package/core/codegen/cli/command-map-generator.d.ts +16 -0
- package/core/codegen/cli/command-map-generator.js +338 -0
- package/core/codegen/cli/custom-command-generator.d.ts +8 -0
- package/core/codegen/cli/custom-command-generator.js +155 -0
- package/core/codegen/cli/docs-generator.d.ts +26 -0
- package/core/codegen/cli/docs-generator.js +1399 -0
- package/core/codegen/cli/executor-generator.d.ts +11 -0
- package/core/codegen/cli/executor-generator.js +217 -0
- package/core/codegen/cli/index.d.ts +53 -0
- package/core/codegen/cli/index.js +153 -0
- package/core/codegen/cli/infra-generator.d.ts +9 -0
- package/core/codegen/cli/infra-generator.js +1195 -0
- package/core/codegen/cli/table-command-generator.d.ts +7 -0
- package/core/codegen/cli/table-command-generator.js +323 -0
- package/core/codegen/docs-utils.d.ts +30 -0
- package/core/codegen/docs-utils.js +122 -0
- package/core/codegen/hooks-docs-generator.d.ts +6 -0
- package/core/codegen/hooks-docs-generator.js +468 -0
- package/core/codegen/orm/docs-generator.d.ts +6 -0
- package/core/codegen/orm/docs-generator.js +416 -0
- package/core/codegen/target-docs-generator.d.ts +20 -0
- package/core/codegen/target-docs-generator.js +110 -0
- package/core/database/index.d.ts +0 -12
- package/core/database/index.js +2 -19
- package/core/generate.d.ts +34 -2
- package/core/generate.js +453 -12
- package/core/index.d.ts +0 -2
- package/core/index.js +0 -2
- package/core/introspect/source/database.js +2 -2
- package/core/introspect/source/pgpm-module.js +2 -2
- package/core/output/index.d.ts +1 -1
- package/core/output/index.js +1 -2
- package/core/output/writer.d.ts +0 -10
- package/core/output/writer.js +0 -31
- package/esm/cli/handler.d.ts +13 -0
- package/esm/cli/handler.js +71 -0
- package/esm/cli/index.js +11 -57
- package/esm/core/codegen/barrel.d.ts +1 -0
- package/esm/core/codegen/barrel.js +5 -2
- package/esm/core/codegen/cli/arg-mapper.d.ts +4 -0
- package/esm/core/codegen/cli/arg-mapper.js +80 -0
- package/esm/core/codegen/cli/command-map-generator.d.ts +16 -0
- package/esm/core/codegen/cli/command-map-generator.js +301 -0
- package/esm/core/codegen/cli/custom-command-generator.d.ts +8 -0
- package/esm/core/codegen/cli/custom-command-generator.js +119 -0
- package/esm/core/codegen/cli/docs-generator.d.ts +26 -0
- package/esm/core/codegen/cli/docs-generator.js +1387 -0
- package/esm/core/codegen/cli/executor-generator.d.ts +11 -0
- package/esm/core/codegen/cli/executor-generator.js +180 -0
- package/esm/core/codegen/cli/index.d.ts +53 -0
- package/esm/core/codegen/cli/index.js +128 -0
- package/esm/core/codegen/cli/infra-generator.d.ts +9 -0
- package/esm/core/codegen/cli/infra-generator.js +1156 -0
- package/esm/core/codegen/cli/table-command-generator.d.ts +7 -0
- package/esm/core/codegen/cli/table-command-generator.js +287 -0
- package/esm/core/codegen/docs-utils.d.ts +30 -0
- package/esm/core/codegen/docs-utils.js +112 -0
- package/esm/core/codegen/hooks-docs-generator.d.ts +6 -0
- package/esm/core/codegen/hooks-docs-generator.js +462 -0
- package/esm/core/codegen/orm/docs-generator.d.ts +6 -0
- package/esm/core/codegen/orm/docs-generator.js +410 -0
- package/esm/core/codegen/target-docs-generator.d.ts +20 -0
- package/esm/core/codegen/target-docs-generator.js +105 -0
- package/esm/core/database/index.d.ts +0 -12
- package/esm/core/database/index.js +1 -17
- package/esm/core/generate.d.ts +34 -2
- package/esm/core/generate.js +417 -12
- package/esm/core/index.d.ts +0 -2
- package/esm/core/index.js +0 -2
- package/esm/core/introspect/source/database.js +2 -2
- package/esm/core/introspect/source/pgpm-module.js +2 -2
- package/esm/core/output/index.d.ts +1 -1
- package/esm/core/output/index.js +1 -1
- package/esm/core/output/writer.d.ts +0 -10
- package/esm/core/output/writer.js +0 -30
- package/esm/generators/index.d.ts +0 -3
- package/esm/generators/index.js +0 -3
- package/esm/index.d.ts +4 -3
- package/esm/index.js +4 -2
- package/esm/types/config.d.ts +78 -0
- package/generators/index.d.ts +0 -3
- package/generators/index.js +0 -3
- package/index.d.ts +4 -3
- package/index.js +7 -2
- package/package.json +8 -7
- package/types/config.d.ts +78 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CleanTable } from '../../../types/schema';
|
|
2
|
+
import type { GeneratedFile } from './executor-generator';
|
|
3
|
+
export interface TableCommandOptions {
|
|
4
|
+
targetName?: string;
|
|
5
|
+
executorImportPath?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function generateTableCommand(table: CleanTable, options?: TableCommandOptions): GeneratedFile;
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import { toKebabCase } from 'komoji';
|
|
3
|
+
import { generateCode } from '../babel-ast';
|
|
4
|
+
import { getGeneratedFileHeader, getPrimaryKeyInfo, getScalarFields, getTableNames, ucFirst, } from '../utils';
|
|
5
|
+
function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
|
|
6
|
+
const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
|
|
7
|
+
const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
|
|
8
|
+
decl.importKind = typeOnly ? 'type' : 'value';
|
|
9
|
+
return decl;
|
|
10
|
+
}
|
|
11
|
+
function buildSelectObject(table) {
|
|
12
|
+
const fields = getScalarFields(table);
|
|
13
|
+
return t.objectExpression(fields.map((f) => t.objectProperty(t.identifier(f.name), t.booleanLiteral(true))));
|
|
14
|
+
}
|
|
15
|
+
function buildJsonLog(expr) {
|
|
16
|
+
return t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [
|
|
17
|
+
t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('stringify')), [expr, t.nullLiteral(), t.numericLiteral(2)]),
|
|
18
|
+
]));
|
|
19
|
+
}
|
|
20
|
+
function buildOrmCall(singularName, methodName, args) {
|
|
21
|
+
return t.callExpression(t.memberExpression(t.callExpression(t.memberExpression(t.memberExpression(t.identifier('client'), t.identifier(singularName)), t.identifier(methodName)), [args]), t.identifier('execute')), []);
|
|
22
|
+
}
|
|
23
|
+
function buildErrorCatch(errorMessage) {
|
|
24
|
+
return t.catchClause(t.identifier('error'), t.blockStatement([
|
|
25
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [t.stringLiteral(errorMessage)])),
|
|
26
|
+
t.ifStatement(t.binaryExpression('instanceof', t.identifier('error'), t.identifier('Error')), t.blockStatement([
|
|
27
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [
|
|
28
|
+
t.memberExpression(t.identifier('error'), t.identifier('message')),
|
|
29
|
+
])),
|
|
30
|
+
])),
|
|
31
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
|
|
32
|
+
]));
|
|
33
|
+
}
|
|
34
|
+
function buildGetClientStatement(targetName) {
|
|
35
|
+
const args = targetName
|
|
36
|
+
? [t.stringLiteral(targetName)]
|
|
37
|
+
: [];
|
|
38
|
+
return t.variableDeclaration('const', [
|
|
39
|
+
t.variableDeclarator(t.identifier('client'), t.callExpression(t.identifier('getClient'), args)),
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
function buildArgvType() {
|
|
43
|
+
return t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([
|
|
44
|
+
t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
|
|
45
|
+
t.tsStringKeyword(),
|
|
46
|
+
t.tsUnknownKeyword(),
|
|
47
|
+
])),
|
|
48
|
+
])));
|
|
49
|
+
}
|
|
50
|
+
function buildSubcommandSwitch(subcommands, handlerPrefix, usageVarName) {
|
|
51
|
+
const cases = subcommands.map((sub) => t.switchCase(t.stringLiteral(sub), [
|
|
52
|
+
t.returnStatement(t.callExpression(t.identifier(`${handlerPrefix}${ucFirst(sub)}`), [
|
|
53
|
+
t.identifier('argv'),
|
|
54
|
+
t.identifier('prompter'),
|
|
55
|
+
])),
|
|
56
|
+
]));
|
|
57
|
+
cases.push(t.switchCase(null, [
|
|
58
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier(usageVarName)])),
|
|
59
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
|
|
60
|
+
]));
|
|
61
|
+
return t.switchStatement(t.identifier('subcommand'), cases);
|
|
62
|
+
}
|
|
63
|
+
function buildListHandler(table, targetName) {
|
|
64
|
+
const { singularName } = getTableNames(table);
|
|
65
|
+
const selectObj = buildSelectObject(table);
|
|
66
|
+
const tryBody = [
|
|
67
|
+
buildGetClientStatement(targetName),
|
|
68
|
+
t.variableDeclaration('const', [
|
|
69
|
+
t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCall(singularName, 'findMany', t.objectExpression([
|
|
70
|
+
t.objectProperty(t.identifier('select'), selectObj),
|
|
71
|
+
])))),
|
|
72
|
+
]),
|
|
73
|
+
buildJsonLog(t.identifier('result')),
|
|
74
|
+
];
|
|
75
|
+
const argvParam = t.identifier('_argv');
|
|
76
|
+
argvParam.typeAnnotation = buildArgvType();
|
|
77
|
+
const prompterParam = t.identifier('_prompter');
|
|
78
|
+
prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
|
|
79
|
+
return t.functionDeclaration(t.identifier('handleList'), [argvParam, prompterParam], t.blockStatement([
|
|
80
|
+
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Failed to list records.')),
|
|
81
|
+
]), false, true);
|
|
82
|
+
}
|
|
83
|
+
function buildGetHandler(table, targetName) {
|
|
84
|
+
const { singularName } = getTableNames(table);
|
|
85
|
+
const pkFields = getPrimaryKeyInfo(table);
|
|
86
|
+
const pk = pkFields[0];
|
|
87
|
+
const selectObj = buildSelectObject(table);
|
|
88
|
+
const promptQuestion = t.objectExpression([
|
|
89
|
+
t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
|
|
90
|
+
t.objectProperty(t.identifier('name'), t.stringLiteral(pk.name)),
|
|
91
|
+
t.objectProperty(t.identifier('message'), t.stringLiteral(pk.name)),
|
|
92
|
+
t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
|
|
93
|
+
]);
|
|
94
|
+
const ormArgs = t.objectExpression([
|
|
95
|
+
t.objectProperty(t.identifier(pk.name), t.memberExpression(t.identifier('answers'), t.identifier(pk.name))),
|
|
96
|
+
t.objectProperty(t.identifier('select'), selectObj),
|
|
97
|
+
]);
|
|
98
|
+
const tryBody = [
|
|
99
|
+
t.variableDeclaration('const', [
|
|
100
|
+
t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [t.identifier('argv'), t.arrayExpression([promptQuestion])]))),
|
|
101
|
+
]),
|
|
102
|
+
buildGetClientStatement(targetName),
|
|
103
|
+
t.variableDeclaration('const', [
|
|
104
|
+
t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCall(singularName, 'findOne', ormArgs))),
|
|
105
|
+
]),
|
|
106
|
+
buildJsonLog(t.identifier('result')),
|
|
107
|
+
];
|
|
108
|
+
const argvParam = t.identifier('argv');
|
|
109
|
+
argvParam.typeAnnotation = buildArgvType();
|
|
110
|
+
const prompterParam = t.identifier('prompter');
|
|
111
|
+
prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
|
|
112
|
+
return t.functionDeclaration(t.identifier('handleGet'), [argvParam, prompterParam], t.blockStatement([
|
|
113
|
+
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Record not found.')),
|
|
114
|
+
]), false, true);
|
|
115
|
+
}
|
|
116
|
+
function buildMutationHandler(table, operation, targetName) {
|
|
117
|
+
const { singularName } = getTableNames(table);
|
|
118
|
+
const pkFields = getPrimaryKeyInfo(table);
|
|
119
|
+
const pk = pkFields[0];
|
|
120
|
+
const editableFields = getScalarFields(table).filter((f) => f.name !== pk.name &&
|
|
121
|
+
f.name !== 'nodeId' &&
|
|
122
|
+
f.name !== 'createdAt' &&
|
|
123
|
+
f.name !== 'updatedAt');
|
|
124
|
+
const questions = [];
|
|
125
|
+
if (operation === 'update' || operation === 'delete') {
|
|
126
|
+
questions.push(t.objectExpression([
|
|
127
|
+
t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
|
|
128
|
+
t.objectProperty(t.identifier('name'), t.stringLiteral(pk.name)),
|
|
129
|
+
t.objectProperty(t.identifier('message'), t.stringLiteral(pk.name)),
|
|
130
|
+
t.objectProperty(t.identifier('required'), t.booleanLiteral(true)),
|
|
131
|
+
]));
|
|
132
|
+
}
|
|
133
|
+
if (operation !== 'delete') {
|
|
134
|
+
for (const field of editableFields) {
|
|
135
|
+
questions.push(t.objectExpression([
|
|
136
|
+
t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
|
|
137
|
+
t.objectProperty(t.identifier('name'), t.stringLiteral(field.name)),
|
|
138
|
+
t.objectProperty(t.identifier('message'), t.stringLiteral(field.name)),
|
|
139
|
+
t.objectProperty(t.identifier('required'), t.booleanLiteral(operation === 'create')),
|
|
140
|
+
]));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const selectObj = operation === 'delete'
|
|
144
|
+
? t.objectExpression([
|
|
145
|
+
t.objectProperty(t.identifier(pk.name), t.booleanLiteral(true)),
|
|
146
|
+
])
|
|
147
|
+
: buildSelectObject(table);
|
|
148
|
+
let ormArgs;
|
|
149
|
+
if (operation === 'create') {
|
|
150
|
+
const dataProps = editableFields.map((f) => t.objectProperty(t.identifier(f.name), t.memberExpression(t.identifier('answers'), t.identifier(f.name)), false, true));
|
|
151
|
+
ormArgs = t.objectExpression([
|
|
152
|
+
t.objectProperty(t.identifier('data'), t.objectExpression(dataProps)),
|
|
153
|
+
t.objectProperty(t.identifier('select'), selectObj),
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
else if (operation === 'update') {
|
|
157
|
+
const dataProps = editableFields.map((f) => t.objectProperty(t.identifier(f.name), t.memberExpression(t.identifier('answers'), t.identifier(f.name)), false, true));
|
|
158
|
+
ormArgs = t.objectExpression([
|
|
159
|
+
t.objectProperty(t.identifier(pk.name), t.memberExpression(t.identifier('answers'), t.identifier(pk.name))),
|
|
160
|
+
t.objectProperty(t.identifier('data'), t.objectExpression(dataProps)),
|
|
161
|
+
t.objectProperty(t.identifier('select'), selectObj),
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
ormArgs = t.objectExpression([
|
|
166
|
+
t.objectProperty(t.identifier(pk.name), t.memberExpression(t.identifier('answers'), t.identifier(pk.name))),
|
|
167
|
+
t.objectProperty(t.identifier('select'), selectObj),
|
|
168
|
+
]);
|
|
169
|
+
}
|
|
170
|
+
const tryBody = [
|
|
171
|
+
t.variableDeclaration('const', [
|
|
172
|
+
t.variableDeclarator(t.identifier('answers'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [t.identifier('argv'), t.arrayExpression(questions)]))),
|
|
173
|
+
]),
|
|
174
|
+
buildGetClientStatement(targetName),
|
|
175
|
+
t.variableDeclaration('const', [
|
|
176
|
+
t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCall(singularName, operation, ormArgs))),
|
|
177
|
+
]),
|
|
178
|
+
buildJsonLog(t.identifier('result')),
|
|
179
|
+
];
|
|
180
|
+
const argvParam = t.identifier('argv');
|
|
181
|
+
argvParam.typeAnnotation = buildArgvType();
|
|
182
|
+
const prompterParam = t.identifier('prompter');
|
|
183
|
+
prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
|
|
184
|
+
const handlerName = `handle${ucFirst(operation)}`;
|
|
185
|
+
return t.functionDeclaration(t.identifier(handlerName), [argvParam, prompterParam], t.blockStatement([
|
|
186
|
+
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch(`Failed to ${operation} record.`)),
|
|
187
|
+
]), false, true);
|
|
188
|
+
}
|
|
189
|
+
export function generateTableCommand(table, options) {
|
|
190
|
+
const { singularName } = getTableNames(table);
|
|
191
|
+
const commandName = toKebabCase(singularName);
|
|
192
|
+
const statements = [];
|
|
193
|
+
const executorPath = options?.executorImportPath ?? '../executor';
|
|
194
|
+
statements.push(createImportDeclaration('inquirerer', [
|
|
195
|
+
'CLIOptions',
|
|
196
|
+
'Inquirerer',
|
|
197
|
+
'extractFirst',
|
|
198
|
+
]));
|
|
199
|
+
statements.push(createImportDeclaration(executorPath, ['getClient']));
|
|
200
|
+
const subcommands = ['list', 'get', 'create', 'update', 'delete'];
|
|
201
|
+
const usageLines = [
|
|
202
|
+
'',
|
|
203
|
+
`${commandName} <command>`,
|
|
204
|
+
'',
|
|
205
|
+
'Commands:',
|
|
206
|
+
` list List all ${singularName} records`,
|
|
207
|
+
` get Get a ${singularName} by ID`,
|
|
208
|
+
` create Create a new ${singularName}`,
|
|
209
|
+
` update Update an existing ${singularName}`,
|
|
210
|
+
` delete Delete a ${singularName}`,
|
|
211
|
+
'',
|
|
212
|
+
' --help, -h Show this help message',
|
|
213
|
+
'',
|
|
214
|
+
];
|
|
215
|
+
statements.push(t.variableDeclaration('const', [
|
|
216
|
+
t.variableDeclarator(t.identifier('usage'), t.stringLiteral(usageLines.join('\n'))),
|
|
217
|
+
]));
|
|
218
|
+
const argvParam = t.identifier('argv');
|
|
219
|
+
argvParam.typeAnnotation = buildArgvType();
|
|
220
|
+
const prompterParam = t.identifier('prompter');
|
|
221
|
+
prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
|
|
222
|
+
const optionsParam = t.identifier('_options');
|
|
223
|
+
optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CLIOptions')));
|
|
224
|
+
const mainBody = [
|
|
225
|
+
t.ifStatement(t.logicalExpression('||', t.memberExpression(t.identifier('argv'), t.identifier('help')), t.memberExpression(t.identifier('argv'), t.identifier('h'))), t.blockStatement([
|
|
226
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), [t.identifier('usage')])),
|
|
227
|
+
t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(0)])),
|
|
228
|
+
])),
|
|
229
|
+
t.variableDeclaration('const', [
|
|
230
|
+
t.variableDeclarator(t.objectPattern([
|
|
231
|
+
t.objectProperty(t.identifier('first'), t.identifier('subcommand')),
|
|
232
|
+
t.objectProperty(t.identifier('newArgv'), t.identifier('newArgv'), false, true),
|
|
233
|
+
]), t.callExpression(t.identifier('extractFirst'), [
|
|
234
|
+
t.identifier('argv'),
|
|
235
|
+
])),
|
|
236
|
+
]),
|
|
237
|
+
t.ifStatement(t.unaryExpression('!', t.identifier('subcommand')), t.blockStatement([
|
|
238
|
+
t.variableDeclaration('const', [
|
|
239
|
+
t.variableDeclarator(t.identifier('answer'), t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('prompter'), t.identifier('prompt')), [
|
|
240
|
+
t.identifier('argv'),
|
|
241
|
+
t.arrayExpression([
|
|
242
|
+
t.objectExpression([
|
|
243
|
+
t.objectProperty(t.identifier('type'), t.stringLiteral('autocomplete')),
|
|
244
|
+
t.objectProperty(t.identifier('name'), t.stringLiteral('subcommand')),
|
|
245
|
+
t.objectProperty(t.identifier('message'), t.stringLiteral('What do you want to do?')),
|
|
246
|
+
t.objectProperty(t.identifier('options'), t.arrayExpression(subcommands.map((s) => t.stringLiteral(s)))),
|
|
247
|
+
]),
|
|
248
|
+
]),
|
|
249
|
+
]))),
|
|
250
|
+
]),
|
|
251
|
+
t.returnStatement(t.callExpression(t.identifier('handleTableSubcommand'), [
|
|
252
|
+
t.memberExpression(t.identifier('answer'), t.identifier('subcommand')),
|
|
253
|
+
t.identifier('newArgv'),
|
|
254
|
+
t.identifier('prompter'),
|
|
255
|
+
])),
|
|
256
|
+
])),
|
|
257
|
+
t.returnStatement(t.callExpression(t.identifier('handleTableSubcommand'), [
|
|
258
|
+
t.identifier('subcommand'),
|
|
259
|
+
t.identifier('newArgv'),
|
|
260
|
+
t.identifier('prompter'),
|
|
261
|
+
])),
|
|
262
|
+
];
|
|
263
|
+
statements.push(t.exportDefaultDeclaration(t.arrowFunctionExpression([argvParam, prompterParam, optionsParam], t.blockStatement(mainBody), true)));
|
|
264
|
+
const subcmdParam = t.identifier('subcommand');
|
|
265
|
+
subcmdParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
|
|
266
|
+
const argvParam2 = t.identifier('argv');
|
|
267
|
+
argvParam2.typeAnnotation = buildArgvType();
|
|
268
|
+
const prompterParam2 = t.identifier('prompter');
|
|
269
|
+
prompterParam2.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
|
|
270
|
+
statements.push(t.functionDeclaration(t.identifier('handleTableSubcommand'), [subcmdParam, argvParam2, prompterParam2], t.blockStatement([
|
|
271
|
+
buildSubcommandSwitch(subcommands, 'handle', 'usage'),
|
|
272
|
+
]), false, true));
|
|
273
|
+
const tn = options?.targetName;
|
|
274
|
+
statements.push(buildListHandler(table, tn));
|
|
275
|
+
statements.push(buildGetHandler(table, tn));
|
|
276
|
+
statements.push(buildMutationHandler(table, 'create', tn));
|
|
277
|
+
statements.push(buildMutationHandler(table, 'update', tn));
|
|
278
|
+
statements.push(buildMutationHandler(table, 'delete', tn));
|
|
279
|
+
const header = getGeneratedFileHeader(`CLI commands for ${table.name}`);
|
|
280
|
+
const code = generateCode(statements);
|
|
281
|
+
return {
|
|
282
|
+
fileName: options?.targetName
|
|
283
|
+
? `commands/${options.targetName}/${commandName}.ts`
|
|
284
|
+
: `commands/${commandName}.ts`,
|
|
285
|
+
content: header + '\n' + code,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DocsConfig } from '../../types/config';
|
|
2
|
+
import type { CleanField, CleanOperation, CleanTable } from '../../types/schema';
|
|
3
|
+
export interface GeneratedDocFile {
|
|
4
|
+
fileName: string;
|
|
5
|
+
content: string;
|
|
6
|
+
}
|
|
7
|
+
export interface McpTool {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
inputSchema: Record<string, unknown>;
|
|
11
|
+
_meta?: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
export interface SkillDefinition {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
usage: string[];
|
|
17
|
+
examples: {
|
|
18
|
+
description: string;
|
|
19
|
+
code: string[];
|
|
20
|
+
}[];
|
|
21
|
+
language?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function getReadmeHeader(title: string): string[];
|
|
24
|
+
export declare function getReadmeFooter(): string[];
|
|
25
|
+
export declare function resolveDocsConfig(docs: DocsConfig | boolean | undefined): DocsConfig;
|
|
26
|
+
export declare function formatArgType(arg: CleanOperation['args'][number]): string;
|
|
27
|
+
export declare function formatTypeRef(t: CleanOperation['args'][number]['type']): string;
|
|
28
|
+
export declare function getEditableFields(table: CleanTable): CleanField[];
|
|
29
|
+
export declare function gqlTypeToJsonSchemaType(gqlType: string): string;
|
|
30
|
+
export declare function buildSkillFile(skill: SkillDefinition): string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { getScalarFields, getPrimaryKeyInfo } from './utils';
|
|
2
|
+
const CONSTRUCTIVE_LOGO_URL = 'https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg';
|
|
3
|
+
const CONSTRUCTIVE_REPO = 'https://github.com/constructive-io/constructive';
|
|
4
|
+
export function getReadmeHeader(title) {
|
|
5
|
+
return [
|
|
6
|
+
`# ${title}`,
|
|
7
|
+
'',
|
|
8
|
+
'<p align="center" width="100%">',
|
|
9
|
+
` <img height="120" src="${CONSTRUCTIVE_LOGO_URL}" />`,
|
|
10
|
+
'</p>',
|
|
11
|
+
'',
|
|
12
|
+
`> @generated by @constructive-io/graphql-codegen - DO NOT EDIT`,
|
|
13
|
+
'',
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
export function getReadmeFooter() {
|
|
17
|
+
return [
|
|
18
|
+
'---',
|
|
19
|
+
'',
|
|
20
|
+
'Built by the [Constructive](https://constructive.io) team.',
|
|
21
|
+
'',
|
|
22
|
+
'## Disclaimer',
|
|
23
|
+
'',
|
|
24
|
+
'AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.',
|
|
25
|
+
'',
|
|
26
|
+
'No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.',
|
|
27
|
+
'',
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
export function resolveDocsConfig(docs) {
|
|
31
|
+
if (docs === true) {
|
|
32
|
+
return { readme: true, agents: true, mcp: true, skills: true };
|
|
33
|
+
}
|
|
34
|
+
if (docs === false) {
|
|
35
|
+
return { readme: false, agents: false, mcp: false, skills: false };
|
|
36
|
+
}
|
|
37
|
+
if (!docs) {
|
|
38
|
+
return { readme: true, agents: true, mcp: false, skills: false };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
readme: docs.readme ?? true,
|
|
42
|
+
agents: docs.agents ?? true,
|
|
43
|
+
mcp: docs.mcp ?? false,
|
|
44
|
+
skills: docs.skills ?? false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function formatArgType(arg) {
|
|
48
|
+
const t = arg.type;
|
|
49
|
+
if (t.kind === 'NON_NULL' && t.ofType) {
|
|
50
|
+
return `${formatTypeRef(t.ofType)} (required)`;
|
|
51
|
+
}
|
|
52
|
+
return formatTypeRef(t);
|
|
53
|
+
}
|
|
54
|
+
export function formatTypeRef(t) {
|
|
55
|
+
if (t.kind === 'LIST' && t.ofType) {
|
|
56
|
+
return `[${formatTypeRef(t.ofType)}]`;
|
|
57
|
+
}
|
|
58
|
+
if (t.kind === 'NON_NULL' && t.ofType) {
|
|
59
|
+
return `${formatTypeRef(t.ofType)}!`;
|
|
60
|
+
}
|
|
61
|
+
return t.name ?? 'unknown';
|
|
62
|
+
}
|
|
63
|
+
export function getEditableFields(table) {
|
|
64
|
+
const pk = getPrimaryKeyInfo(table)[0];
|
|
65
|
+
return getScalarFields(table).filter((f) => f.name !== pk.name &&
|
|
66
|
+
f.name !== 'nodeId' &&
|
|
67
|
+
f.name !== 'createdAt' &&
|
|
68
|
+
f.name !== 'updatedAt');
|
|
69
|
+
}
|
|
70
|
+
export function gqlTypeToJsonSchemaType(gqlType) {
|
|
71
|
+
switch (gqlType) {
|
|
72
|
+
case 'Int':
|
|
73
|
+
return 'integer';
|
|
74
|
+
case 'Float':
|
|
75
|
+
return 'number';
|
|
76
|
+
case 'Boolean':
|
|
77
|
+
return 'boolean';
|
|
78
|
+
default:
|
|
79
|
+
return 'string';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function buildSkillFile(skill) {
|
|
83
|
+
const lang = skill.language ?? 'bash';
|
|
84
|
+
const lines = [];
|
|
85
|
+
lines.push(`# ${skill.name}`);
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push('> @generated by @constructive-io/graphql-codegen - DO NOT EDIT');
|
|
88
|
+
lines.push('');
|
|
89
|
+
lines.push(skill.description);
|
|
90
|
+
lines.push('');
|
|
91
|
+
lines.push('## Usage');
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push(`\`\`\`${lang}`);
|
|
94
|
+
for (const u of skill.usage) {
|
|
95
|
+
lines.push(u);
|
|
96
|
+
}
|
|
97
|
+
lines.push('```');
|
|
98
|
+
lines.push('');
|
|
99
|
+
lines.push('## Examples');
|
|
100
|
+
lines.push('');
|
|
101
|
+
for (const ex of skill.examples) {
|
|
102
|
+
lines.push(`### ${ex.description}`);
|
|
103
|
+
lines.push('');
|
|
104
|
+
lines.push(`\`\`\`${lang}`);
|
|
105
|
+
for (const cmd of ex.code) {
|
|
106
|
+
lines.push(cmd);
|
|
107
|
+
}
|
|
108
|
+
lines.push('```');
|
|
109
|
+
lines.push('');
|
|
110
|
+
}
|
|
111
|
+
return lines.join('\n');
|
|
112
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CleanOperation, CleanTable } from '../../types/schema';
|
|
2
|
+
import type { GeneratedDocFile, McpTool } from './docs-utils';
|
|
3
|
+
export declare function generateHooksReadme(tables: CleanTable[], customOperations: CleanOperation[]): GeneratedDocFile;
|
|
4
|
+
export declare function generateHooksAgentsDocs(tables: CleanTable[], customOperations: CleanOperation[]): GeneratedDocFile;
|
|
5
|
+
export declare function getHooksMcpTools(tables: CleanTable[], customOperations: CleanOperation[]): McpTool[];
|
|
6
|
+
export declare function generateHooksSkills(tables: CleanTable[], customOperations: CleanOperation[]): GeneratedDocFile[];
|