@constructive-io/graphql-codegen 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/handler.d.ts +13 -0
- package/cli/handler.js +74 -0
- package/cli/index.js +11 -60
- package/cli/shared.d.ts +1 -1
- package/cli/shared.js +2 -5
- 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 -60
- package/esm/cli/shared.d.ts +1 -1
- package/esm/cli/shared.js +2 -5
- 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,416 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateOrmReadme = generateOrmReadme;
|
|
4
|
+
exports.generateOrmAgentsDocs = generateOrmAgentsDocs;
|
|
5
|
+
exports.getOrmMcpTools = getOrmMcpTools;
|
|
6
|
+
exports.generateOrmSkills = generateOrmSkills;
|
|
7
|
+
const docs_utils_1 = require("../docs-utils");
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
function generateOrmReadme(tables, customOperations) {
|
|
10
|
+
const lines = [];
|
|
11
|
+
lines.push(...(0, docs_utils_1.getReadmeHeader)('ORM Client'));
|
|
12
|
+
lines.push('## Setup');
|
|
13
|
+
lines.push('');
|
|
14
|
+
lines.push('```typescript');
|
|
15
|
+
lines.push("import { createClient } from './orm';");
|
|
16
|
+
lines.push('');
|
|
17
|
+
lines.push('const db = createClient({');
|
|
18
|
+
lines.push(" endpoint: 'https://api.example.com/graphql',");
|
|
19
|
+
lines.push(" headers: { Authorization: 'Bearer <token>' },");
|
|
20
|
+
lines.push('});');
|
|
21
|
+
lines.push('```');
|
|
22
|
+
lines.push('');
|
|
23
|
+
lines.push('## Models');
|
|
24
|
+
lines.push('');
|
|
25
|
+
lines.push('| Model | Operations |');
|
|
26
|
+
lines.push('|-------|------------|');
|
|
27
|
+
for (const table of tables) {
|
|
28
|
+
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
29
|
+
lines.push(`| \`${singularName}\` | findMany, findOne, create, update, delete |`);
|
|
30
|
+
}
|
|
31
|
+
lines.push('');
|
|
32
|
+
if (tables.length > 0) {
|
|
33
|
+
lines.push('## Table Operations');
|
|
34
|
+
lines.push('');
|
|
35
|
+
for (const table of tables) {
|
|
36
|
+
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
37
|
+
const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
|
|
38
|
+
const scalarFields = (0, utils_1.getScalarFields)(table);
|
|
39
|
+
const editableFields = (0, docs_utils_1.getEditableFields)(table);
|
|
40
|
+
lines.push(`### \`db.${singularName}\``);
|
|
41
|
+
lines.push('');
|
|
42
|
+
lines.push(`CRUD operations for ${table.name} records.`);
|
|
43
|
+
lines.push('');
|
|
44
|
+
lines.push('**Fields:**');
|
|
45
|
+
lines.push('');
|
|
46
|
+
lines.push('| Field | Type | Editable |');
|
|
47
|
+
lines.push('|-------|------|----------|');
|
|
48
|
+
for (const f of scalarFields) {
|
|
49
|
+
const editable = editableFields.some((ef) => ef.name === f.name);
|
|
50
|
+
lines.push(`| \`${f.name}\` | ${f.type.gqlType} | ${editable ? 'Yes' : 'No'} |`);
|
|
51
|
+
}
|
|
52
|
+
lines.push('');
|
|
53
|
+
lines.push('**Operations:**');
|
|
54
|
+
lines.push('');
|
|
55
|
+
lines.push('```typescript');
|
|
56
|
+
lines.push(`// List all ${singularName} records`);
|
|
57
|
+
lines.push(`const items = await db.${singularName}.findMany({ select: { ${scalarFields.map((f) => `${f.name}: true`).join(', ')} } }).execute();`);
|
|
58
|
+
lines.push('');
|
|
59
|
+
lines.push(`// Get one by ${pk.name}`);
|
|
60
|
+
lines.push(`const item = await db.${singularName}.findOne({ where: { ${pk.name}: '<value>' }, select: { ${scalarFields.map((f) => `${f.name}: true`).join(', ')} } }).execute();`);
|
|
61
|
+
lines.push('');
|
|
62
|
+
lines.push(`// Create`);
|
|
63
|
+
lines.push(`const created = await db.${singularName}.create({ data: { ${editableFields.map((f) => `${f.name}: '<value>'`).join(', ')} }, select: { ${pk.name}: true } }).execute();`);
|
|
64
|
+
lines.push('');
|
|
65
|
+
lines.push(`// Update`);
|
|
66
|
+
lines.push(`const updated = await db.${singularName}.update({ where: { ${pk.name}: '<value>' }, data: { ${editableFields[0]?.name || 'field'}: '<new-value>' }, select: { ${pk.name}: true } }).execute();`);
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push(`// Delete`);
|
|
69
|
+
lines.push(`const deleted = await db.${singularName}.delete({ where: { ${pk.name}: '<value>' } }).execute();`);
|
|
70
|
+
lines.push('```');
|
|
71
|
+
lines.push('');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (customOperations.length > 0) {
|
|
75
|
+
lines.push('## Custom Operations');
|
|
76
|
+
lines.push('');
|
|
77
|
+
for (const op of customOperations) {
|
|
78
|
+
const accessor = op.kind === 'query' ? 'query' : 'mutation';
|
|
79
|
+
lines.push(`### \`db.${accessor}.${op.name}\``);
|
|
80
|
+
lines.push('');
|
|
81
|
+
lines.push(op.description || op.name);
|
|
82
|
+
lines.push('');
|
|
83
|
+
lines.push(`- **Type:** ${op.kind}`);
|
|
84
|
+
if (op.args.length > 0) {
|
|
85
|
+
lines.push('- **Arguments:**');
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(' | Argument | Type |');
|
|
88
|
+
lines.push(' |----------|------|');
|
|
89
|
+
for (const arg of op.args) {
|
|
90
|
+
lines.push(` | \`${arg.name}\` | ${(0, docs_utils_1.formatArgType)(arg)} |`);
|
|
91
|
+
}
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push('```typescript');
|
|
94
|
+
lines.push(`const result = await db.${accessor}.${op.name}({ ${op.args.map((a) => `${a.name}: '<value>'`).join(', ')} }).execute();`);
|
|
95
|
+
lines.push('```');
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
lines.push('- **Arguments:** none');
|
|
99
|
+
lines.push('');
|
|
100
|
+
lines.push('```typescript');
|
|
101
|
+
lines.push(`const result = await db.${accessor}.${op.name}().execute();`);
|
|
102
|
+
lines.push('```');
|
|
103
|
+
}
|
|
104
|
+
lines.push('');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
lines.push(...(0, docs_utils_1.getReadmeFooter)());
|
|
108
|
+
return {
|
|
109
|
+
fileName: 'README.md',
|
|
110
|
+
content: lines.join('\n'),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function generateOrmAgentsDocs(tables, customOperations) {
|
|
114
|
+
const lines = [];
|
|
115
|
+
lines.push('# ORM Client - Agent Reference');
|
|
116
|
+
lines.push('');
|
|
117
|
+
lines.push('> @generated by @constructive-io/graphql-codegen - DO NOT EDIT');
|
|
118
|
+
lines.push('> This document is structured for LLM/agent consumption.');
|
|
119
|
+
lines.push('');
|
|
120
|
+
lines.push('## OVERVIEW');
|
|
121
|
+
lines.push('');
|
|
122
|
+
lines.push('Prisma-like ORM client for interacting with a GraphQL API.');
|
|
123
|
+
lines.push('All methods return a query builder. Call `.execute()` to run the query.');
|
|
124
|
+
lines.push('');
|
|
125
|
+
lines.push('## SETUP');
|
|
126
|
+
lines.push('');
|
|
127
|
+
lines.push('```typescript');
|
|
128
|
+
lines.push("import { createClient } from './orm';");
|
|
129
|
+
lines.push('');
|
|
130
|
+
lines.push('const db = createClient({');
|
|
131
|
+
lines.push(" endpoint: 'https://api.example.com/graphql',");
|
|
132
|
+
lines.push(" headers: { Authorization: 'Bearer <token>' },");
|
|
133
|
+
lines.push('});');
|
|
134
|
+
lines.push('```');
|
|
135
|
+
lines.push('');
|
|
136
|
+
lines.push('## MODELS');
|
|
137
|
+
lines.push('');
|
|
138
|
+
for (const table of tables) {
|
|
139
|
+
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
140
|
+
const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
|
|
141
|
+
const scalarFields = (0, utils_1.getScalarFields)(table);
|
|
142
|
+
const editableFields = (0, docs_utils_1.getEditableFields)(table);
|
|
143
|
+
lines.push(`### MODEL: ${singularName}`);
|
|
144
|
+
lines.push('');
|
|
145
|
+
lines.push(`Access: \`db.${singularName}\``);
|
|
146
|
+
lines.push('');
|
|
147
|
+
lines.push('```');
|
|
148
|
+
lines.push('METHODS:');
|
|
149
|
+
lines.push(` db.${singularName}.findMany({ select, where?, orderBy?, first?, offset? })`);
|
|
150
|
+
lines.push(` db.${singularName}.findOne({ where: { ${pk.name} }, select })`);
|
|
151
|
+
lines.push(` db.${singularName}.create({ data: { ${editableFields.map((f) => f.name).join(', ')} }, select })`);
|
|
152
|
+
lines.push(` db.${singularName}.update({ where: { ${pk.name} }, data, select })`);
|
|
153
|
+
lines.push(` db.${singularName}.delete({ where: { ${pk.name} } })`);
|
|
154
|
+
lines.push('');
|
|
155
|
+
lines.push('FIELDS:');
|
|
156
|
+
for (const f of scalarFields) {
|
|
157
|
+
const isPk = f.name === pk.name;
|
|
158
|
+
lines.push(` ${f.name}: ${(0, utils_1.fieldTypeToTs)(f.type)}${isPk ? ' (primary key)' : ''}`);
|
|
159
|
+
}
|
|
160
|
+
lines.push('');
|
|
161
|
+
lines.push('EDITABLE FIELDS:');
|
|
162
|
+
for (const f of editableFields) {
|
|
163
|
+
lines.push(` ${f.name}: ${(0, utils_1.fieldTypeToTs)(f.type)}`);
|
|
164
|
+
}
|
|
165
|
+
lines.push('');
|
|
166
|
+
lines.push('OUTPUT: Promise<JSON>');
|
|
167
|
+
lines.push(` findMany: [{ ${scalarFields.map((f) => f.name).join(', ')} }]`);
|
|
168
|
+
lines.push(` findOne: { ${scalarFields.map((f) => f.name).join(', ')} }`);
|
|
169
|
+
lines.push(` create: { ${scalarFields.map((f) => f.name).join(', ')} }`);
|
|
170
|
+
lines.push(` update: { ${scalarFields.map((f) => f.name).join(', ')} }`);
|
|
171
|
+
lines.push(` delete: { ${pk.name} }`);
|
|
172
|
+
lines.push('```');
|
|
173
|
+
lines.push('');
|
|
174
|
+
}
|
|
175
|
+
if (customOperations.length > 0) {
|
|
176
|
+
lines.push('## CUSTOM OPERATIONS');
|
|
177
|
+
lines.push('');
|
|
178
|
+
for (const op of customOperations) {
|
|
179
|
+
const accessor = op.kind === 'query' ? 'query' : 'mutation';
|
|
180
|
+
lines.push(`### OPERATION: ${op.name}`);
|
|
181
|
+
lines.push('');
|
|
182
|
+
lines.push(op.description || op.name);
|
|
183
|
+
lines.push('');
|
|
184
|
+
lines.push('```');
|
|
185
|
+
lines.push(`TYPE: ${op.kind}`);
|
|
186
|
+
lines.push(`ACCESS: db.${accessor}.${op.name}`);
|
|
187
|
+
if (op.args.length > 0) {
|
|
188
|
+
lines.push(`USAGE: db.${accessor}.${op.name}({ ${op.args.map((a) => `${a.name}: <value>`).join(', ')} }).execute()`);
|
|
189
|
+
lines.push('');
|
|
190
|
+
lines.push('INPUT:');
|
|
191
|
+
for (const arg of op.args) {
|
|
192
|
+
lines.push(` ${arg.name}: ${(0, docs_utils_1.formatArgType)(arg)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
lines.push(`USAGE: db.${accessor}.${op.name}().execute()`);
|
|
197
|
+
lines.push('');
|
|
198
|
+
lines.push('INPUT: none');
|
|
199
|
+
}
|
|
200
|
+
lines.push('');
|
|
201
|
+
lines.push('OUTPUT: Promise<JSON>');
|
|
202
|
+
lines.push('```');
|
|
203
|
+
lines.push('');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
lines.push('## PATTERNS');
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push('```typescript');
|
|
209
|
+
lines.push('// All methods require .execute() to run');
|
|
210
|
+
lines.push('const result = await db.modelName.findMany({ select: { id: true } }).execute();');
|
|
211
|
+
lines.push('');
|
|
212
|
+
lines.push('// Select specific fields');
|
|
213
|
+
lines.push('const partial = await db.modelName.findMany({ select: { id: true, name: true } }).execute();');
|
|
214
|
+
lines.push('');
|
|
215
|
+
lines.push('// Filter with where clause');
|
|
216
|
+
lines.push("const filtered = await db.modelName.findMany({ select: { id: true }, where: { name: 'test' } }).execute();");
|
|
217
|
+
lines.push('```');
|
|
218
|
+
lines.push('');
|
|
219
|
+
return {
|
|
220
|
+
fileName: 'AGENTS.md',
|
|
221
|
+
content: lines.join('\n'),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function getOrmMcpTools(tables, customOperations) {
|
|
225
|
+
const tools = [];
|
|
226
|
+
for (const table of tables) {
|
|
227
|
+
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
228
|
+
const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
|
|
229
|
+
const scalarFields = (0, utils_1.getScalarFields)(table);
|
|
230
|
+
const editableFields = (0, docs_utils_1.getEditableFields)(table);
|
|
231
|
+
tools.push({
|
|
232
|
+
name: `orm_${(0, utils_1.lcFirst)(singularName)}_findMany`,
|
|
233
|
+
description: `List all ${table.name} records via ORM`,
|
|
234
|
+
inputSchema: {
|
|
235
|
+
type: 'object',
|
|
236
|
+
properties: {
|
|
237
|
+
first: {
|
|
238
|
+
type: 'integer',
|
|
239
|
+
description: 'Limit number of results',
|
|
240
|
+
},
|
|
241
|
+
offset: {
|
|
242
|
+
type: 'integer',
|
|
243
|
+
description: 'Offset for pagination',
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
tools.push({
|
|
249
|
+
name: `orm_${(0, utils_1.lcFirst)(singularName)}_findOne`,
|
|
250
|
+
description: `Get a single ${table.name} record by ${pk.name}`,
|
|
251
|
+
inputSchema: {
|
|
252
|
+
type: 'object',
|
|
253
|
+
properties: {
|
|
254
|
+
[pk.name]: {
|
|
255
|
+
type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
|
|
256
|
+
description: `${table.name} ${pk.name}`,
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
required: [pk.name],
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
const createProps = {};
|
|
263
|
+
for (const f of editableFields) {
|
|
264
|
+
createProps[f.name] = {
|
|
265
|
+
type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(f.type.gqlType),
|
|
266
|
+
description: `${table.name} ${f.name}`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
tools.push({
|
|
270
|
+
name: `orm_${(0, utils_1.lcFirst)(singularName)}_create`,
|
|
271
|
+
description: `Create a new ${table.name} record`,
|
|
272
|
+
inputSchema: {
|
|
273
|
+
type: 'object',
|
|
274
|
+
properties: createProps,
|
|
275
|
+
required: editableFields.map((f) => f.name),
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
const updateProps = {
|
|
279
|
+
[pk.name]: {
|
|
280
|
+
type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
|
|
281
|
+
description: `${table.name} ${pk.name}`,
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
for (const f of editableFields) {
|
|
285
|
+
updateProps[f.name] = {
|
|
286
|
+
type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(f.type.gqlType),
|
|
287
|
+
description: `${table.name} ${f.name}`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
tools.push({
|
|
291
|
+
name: `orm_${(0, utils_1.lcFirst)(singularName)}_update`,
|
|
292
|
+
description: `Update an existing ${table.name} record`,
|
|
293
|
+
inputSchema: {
|
|
294
|
+
type: 'object',
|
|
295
|
+
properties: updateProps,
|
|
296
|
+
required: [pk.name],
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
tools.push({
|
|
300
|
+
name: `orm_${(0, utils_1.lcFirst)(singularName)}_delete`,
|
|
301
|
+
description: `Delete a ${table.name} record by ${pk.name}`,
|
|
302
|
+
inputSchema: {
|
|
303
|
+
type: 'object',
|
|
304
|
+
properties: {
|
|
305
|
+
[pk.name]: {
|
|
306
|
+
type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(pk.gqlType),
|
|
307
|
+
description: `${table.name} ${pk.name}`,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
required: [pk.name],
|
|
311
|
+
},
|
|
312
|
+
_meta: {
|
|
313
|
+
fields: scalarFields.map((f) => ({
|
|
314
|
+
name: f.name,
|
|
315
|
+
type: f.type.gqlType,
|
|
316
|
+
editable: editableFields.some((ef) => ef.name === f.name),
|
|
317
|
+
primaryKey: f.name === pk.name,
|
|
318
|
+
})),
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
for (const op of customOperations) {
|
|
323
|
+
const accessor = op.kind === 'query' ? 'query' : 'mutation';
|
|
324
|
+
const props = {};
|
|
325
|
+
const required = [];
|
|
326
|
+
for (const arg of op.args) {
|
|
327
|
+
const isRequired = arg.type.kind === 'NON_NULL';
|
|
328
|
+
const baseType = isRequired && arg.type.ofType ? arg.type.ofType : arg.type;
|
|
329
|
+
props[arg.name] = {
|
|
330
|
+
type: (0, docs_utils_1.gqlTypeToJsonSchemaType)(baseType.name ?? 'String'),
|
|
331
|
+
description: arg.description || arg.name,
|
|
332
|
+
};
|
|
333
|
+
if (isRequired) {
|
|
334
|
+
required.push(arg.name);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
tools.push({
|
|
338
|
+
name: `orm_${accessor}_${op.name}`,
|
|
339
|
+
description: op.description || `Execute ${op.name} ${op.kind}`,
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: 'object',
|
|
342
|
+
properties: props,
|
|
343
|
+
...(required.length > 0 ? { required } : {}),
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
return tools;
|
|
348
|
+
}
|
|
349
|
+
function generateOrmSkills(tables, customOperations) {
|
|
350
|
+
const files = [];
|
|
351
|
+
for (const table of tables) {
|
|
352
|
+
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
353
|
+
const pk = (0, utils_1.getPrimaryKeyInfo)(table)[0];
|
|
354
|
+
const editableFields = (0, docs_utils_1.getEditableFields)(table);
|
|
355
|
+
files.push({
|
|
356
|
+
fileName: `skills/${(0, utils_1.lcFirst)(singularName)}.md`,
|
|
357
|
+
content: (0, docs_utils_1.buildSkillFile)({
|
|
358
|
+
name: `orm-${(0, utils_1.lcFirst)(singularName)}`,
|
|
359
|
+
description: `ORM operations for ${table.name} records`,
|
|
360
|
+
language: 'typescript',
|
|
361
|
+
usage: [
|
|
362
|
+
`db.${(0, utils_1.lcFirst)(singularName)}.findMany({ select: { id: true } }).execute()`,
|
|
363
|
+
`db.${(0, utils_1.lcFirst)(singularName)}.findOne({ where: { ${pk.name}: '<value>' }, select: { id: true } }).execute()`,
|
|
364
|
+
`db.${(0, utils_1.lcFirst)(singularName)}.create({ data: { ${editableFields.map((f) => `${f.name}: '<value>'`).join(', ')} }, select: { id: true } }).execute()`,
|
|
365
|
+
`db.${(0, utils_1.lcFirst)(singularName)}.update({ where: { ${pk.name}: '<value>' }, data: { ${editableFields[0]?.name || 'field'}: '<new>' }, select: { id: true } }).execute()`,
|
|
366
|
+
`db.${(0, utils_1.lcFirst)(singularName)}.delete({ where: { ${pk.name}: '<value>' } }).execute()`,
|
|
367
|
+
],
|
|
368
|
+
examples: [
|
|
369
|
+
{
|
|
370
|
+
description: `List all ${singularName} records`,
|
|
371
|
+
code: [
|
|
372
|
+
`const items = await db.${(0, utils_1.lcFirst)(singularName)}.findMany({`,
|
|
373
|
+
` select: { ${pk.name}: true, ${editableFields[0]?.name || 'name'}: true }`,
|
|
374
|
+
'}).execute();',
|
|
375
|
+
],
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
description: `Create a ${singularName}`,
|
|
379
|
+
code: [
|
|
380
|
+
`const item = await db.${(0, utils_1.lcFirst)(singularName)}.create({`,
|
|
381
|
+
` data: { ${editableFields.map((f) => `${f.name}: 'value'`).join(', ')} },`,
|
|
382
|
+
` select: { ${pk.name}: true }`,
|
|
383
|
+
'}).execute();',
|
|
384
|
+
],
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
}),
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
for (const op of customOperations) {
|
|
391
|
+
const accessor = op.kind === 'query' ? 'query' : 'mutation';
|
|
392
|
+
const callArgs = op.args.length > 0
|
|
393
|
+
? `{ ${op.args.map((a) => `${a.name}: '<value>'`).join(', ')} }`
|
|
394
|
+
: '';
|
|
395
|
+
files.push({
|
|
396
|
+
fileName: `skills/${op.name}.md`,
|
|
397
|
+
content: (0, docs_utils_1.buildSkillFile)({
|
|
398
|
+
name: `orm-${op.name}`,
|
|
399
|
+
description: op.description || `Execute the ${op.name} ${op.kind}`,
|
|
400
|
+
language: 'typescript',
|
|
401
|
+
usage: [
|
|
402
|
+
`db.${accessor}.${op.name}(${callArgs}).execute()`,
|
|
403
|
+
],
|
|
404
|
+
examples: [
|
|
405
|
+
{
|
|
406
|
+
description: `Run ${op.name}`,
|
|
407
|
+
code: [
|
|
408
|
+
`const result = await db.${accessor}.${op.name}(${callArgs}).execute();`,
|
|
409
|
+
],
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
}),
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
return files;
|
|
416
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { GraphQLSDKConfigTarget } from '../../types/config';
|
|
2
|
+
import type { GeneratedDocFile, McpTool } from './docs-utils';
|
|
3
|
+
export interface TargetReadmeOptions {
|
|
4
|
+
hasOrm: boolean;
|
|
5
|
+
hasHooks: boolean;
|
|
6
|
+
hasCli: boolean;
|
|
7
|
+
tableCount: number;
|
|
8
|
+
customQueryCount: number;
|
|
9
|
+
customMutationCount: number;
|
|
10
|
+
config: GraphQLSDKConfigTarget;
|
|
11
|
+
}
|
|
12
|
+
export declare function generateTargetReadme(options: TargetReadmeOptions): GeneratedDocFile;
|
|
13
|
+
export declare function generateCombinedMcpConfig(tools: McpTool[], name: string): GeneratedDocFile;
|
|
14
|
+
export interface RootRootReadmeTarget {
|
|
15
|
+
name: string;
|
|
16
|
+
output: string;
|
|
17
|
+
endpoint?: string;
|
|
18
|
+
generators: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function generateRootRootReadme(targets: RootRootReadmeTarget[]): GeneratedDocFile;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTargetReadme = generateTargetReadme;
|
|
4
|
+
exports.generateCombinedMcpConfig = generateCombinedMcpConfig;
|
|
5
|
+
exports.generateRootRootReadme = generateRootRootReadme;
|
|
6
|
+
const docs_utils_1 = require("./docs-utils");
|
|
7
|
+
function generateTargetReadme(options) {
|
|
8
|
+
const { hasOrm, hasHooks, hasCli, tableCount, customQueryCount, customMutationCount, config, } = options;
|
|
9
|
+
const lines = [];
|
|
10
|
+
lines.push(...(0, docs_utils_1.getReadmeHeader)('Generated GraphQL SDK'));
|
|
11
|
+
lines.push('## Overview');
|
|
12
|
+
lines.push('');
|
|
13
|
+
lines.push(`- **Tables:** ${tableCount}`);
|
|
14
|
+
lines.push(`- **Custom queries:** ${customQueryCount}`);
|
|
15
|
+
lines.push(`- **Custom mutations:** ${customMutationCount}`);
|
|
16
|
+
lines.push('');
|
|
17
|
+
const generators = [];
|
|
18
|
+
if (hasOrm)
|
|
19
|
+
generators.push('ORM');
|
|
20
|
+
if (hasHooks)
|
|
21
|
+
generators.push('React Query');
|
|
22
|
+
if (hasCli)
|
|
23
|
+
generators.push('CLI');
|
|
24
|
+
lines.push(`**Generators:** ${generators.join(', ')}`);
|
|
25
|
+
lines.push('');
|
|
26
|
+
if (config.endpoint) {
|
|
27
|
+
lines.push(`**Endpoint:** \`${config.endpoint}\``);
|
|
28
|
+
lines.push('');
|
|
29
|
+
}
|
|
30
|
+
lines.push('## Modules');
|
|
31
|
+
lines.push('');
|
|
32
|
+
if (hasOrm) {
|
|
33
|
+
lines.push('### ORM Client (`./orm`)');
|
|
34
|
+
lines.push('');
|
|
35
|
+
lines.push('Prisma-like ORM client for programmatic GraphQL access.');
|
|
36
|
+
lines.push('');
|
|
37
|
+
lines.push('```typescript');
|
|
38
|
+
lines.push("import { createClient } from './orm';");
|
|
39
|
+
lines.push('');
|
|
40
|
+
lines.push('const db = createClient({');
|
|
41
|
+
lines.push(" endpoint: 'https://api.example.com/graphql',");
|
|
42
|
+
lines.push('});');
|
|
43
|
+
lines.push('```');
|
|
44
|
+
lines.push('');
|
|
45
|
+
lines.push('See [orm/README.md](./orm/README.md) for full API reference.');
|
|
46
|
+
lines.push('');
|
|
47
|
+
}
|
|
48
|
+
if (hasHooks) {
|
|
49
|
+
lines.push('### React Query Hooks (`./hooks`)');
|
|
50
|
+
lines.push('');
|
|
51
|
+
lines.push('Type-safe React Query hooks for data fetching and mutations.');
|
|
52
|
+
lines.push('');
|
|
53
|
+
lines.push('```typescript');
|
|
54
|
+
lines.push("import { configure } from './hooks';");
|
|
55
|
+
lines.push("import { useCarsQuery } from './hooks';");
|
|
56
|
+
lines.push('');
|
|
57
|
+
lines.push("configure({ endpoint: 'https://api.example.com/graphql' });");
|
|
58
|
+
lines.push('```');
|
|
59
|
+
lines.push('');
|
|
60
|
+
lines.push('See [hooks/README.md](./hooks/README.md) for full hook reference.');
|
|
61
|
+
lines.push('');
|
|
62
|
+
}
|
|
63
|
+
if (hasCli) {
|
|
64
|
+
const toolName = typeof config.cli === 'object' && config.cli?.toolName
|
|
65
|
+
? config.cli.toolName
|
|
66
|
+
: 'app';
|
|
67
|
+
lines.push(`### CLI Commands (\`./cli\`)`);
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(`inquirerer-based CLI commands for \`${toolName}\`.`);
|
|
70
|
+
lines.push('');
|
|
71
|
+
lines.push('See [cli/README.md](./cli/README.md) for command reference.');
|
|
72
|
+
lines.push('');
|
|
73
|
+
}
|
|
74
|
+
lines.push(...(0, docs_utils_1.getReadmeFooter)());
|
|
75
|
+
return {
|
|
76
|
+
fileName: 'README.md',
|
|
77
|
+
content: lines.join('\n'),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function generateCombinedMcpConfig(tools, name) {
|
|
81
|
+
const mcpConfig = {
|
|
82
|
+
name,
|
|
83
|
+
version: '1.0.0',
|
|
84
|
+
description: `MCP tool definitions for ${name} SDK (auto-generated from GraphQL schema)`,
|
|
85
|
+
tools,
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
fileName: 'mcp.json',
|
|
89
|
+
content: JSON.stringify(mcpConfig, null, 2) + '\n',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function generateRootRootReadme(targets) {
|
|
93
|
+
const lines = [];
|
|
94
|
+
lines.push(...(0, docs_utils_1.getReadmeHeader)('GraphQL SDK'));
|
|
95
|
+
lines.push('## APIs');
|
|
96
|
+
lines.push('');
|
|
97
|
+
lines.push('| API | Endpoint | Generators | Docs |');
|
|
98
|
+
lines.push('|-----|----------|------------|------|');
|
|
99
|
+
for (const target of targets) {
|
|
100
|
+
const endpoint = target.endpoint || '-';
|
|
101
|
+
const gens = target.generators.join(', ');
|
|
102
|
+
lines.push(`| ${target.name} | ${endpoint} | ${gens} | [${target.output}/README.md](${target.output}/README.md) |`);
|
|
103
|
+
}
|
|
104
|
+
lines.push('');
|
|
105
|
+
lines.push(...(0, docs_utils_1.getReadmeFooter)());
|
|
106
|
+
return {
|
|
107
|
+
fileName: 'README.md',
|
|
108
|
+
content: lines.join('\n'),
|
|
109
|
+
};
|
|
110
|
+
}
|
package/core/database/index.d.ts
CHANGED
|
@@ -29,15 +29,3 @@ export interface BuildSchemaFromDatabaseResult {
|
|
|
29
29
|
* @returns The path to the generated schema file and the SDL content
|
|
30
30
|
*/
|
|
31
31
|
export declare function buildSchemaFromDatabase(options: BuildSchemaFromDatabaseOptions): Promise<BuildSchemaFromDatabaseResult>;
|
|
32
|
-
/**
|
|
33
|
-
* Build a GraphQL schema SDL string from a PostgreSQL database without writing to file.
|
|
34
|
-
*
|
|
35
|
-
* This is a convenience wrapper around buildSchemaSDL from graphql-server.
|
|
36
|
-
*
|
|
37
|
-
* @param options - Configuration options
|
|
38
|
-
* @returns The SDL content as a string
|
|
39
|
-
*/
|
|
40
|
-
export declare function buildSchemaSDLFromDatabase(options: {
|
|
41
|
-
database: string;
|
|
42
|
-
schemas: string[];
|
|
43
|
-
}): Promise<string>;
|
package/core/database/index.js
CHANGED
|
@@ -39,10 +39,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.buildSchemaFromDatabase = buildSchemaFromDatabase;
|
|
42
|
-
exports.buildSchemaSDLFromDatabase = buildSchemaSDLFromDatabase;
|
|
43
42
|
const fs = __importStar(require("node:fs"));
|
|
44
43
|
const path = __importStar(require("node:path"));
|
|
45
|
-
const
|
|
44
|
+
const graphile_schema_1 = require("graphile-schema");
|
|
46
45
|
/**
|
|
47
46
|
* Build a GraphQL schema from a PostgreSQL database and write it to a file.
|
|
48
47
|
*
|
|
@@ -57,7 +56,7 @@ async function buildSchemaFromDatabase(options) {
|
|
|
57
56
|
// Ensure output directory exists
|
|
58
57
|
await fs.promises.mkdir(outDir, { recursive: true });
|
|
59
58
|
// Build schema SDL from database (PostGraphile v5 preset-driven settings)
|
|
60
|
-
const sdl = await (0,
|
|
59
|
+
const sdl = await (0, graphile_schema_1.buildSchemaSDL)({
|
|
61
60
|
database,
|
|
62
61
|
schemas,
|
|
63
62
|
});
|
|
@@ -66,19 +65,3 @@ async function buildSchemaFromDatabase(options) {
|
|
|
66
65
|
await fs.promises.writeFile(schemaPath, sdl, 'utf-8');
|
|
67
66
|
return { schemaPath, sdl };
|
|
68
67
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Build a GraphQL schema SDL string from a PostgreSQL database without writing to file.
|
|
71
|
-
*
|
|
72
|
-
* This is a convenience wrapper around buildSchemaSDL from graphql-server.
|
|
73
|
-
*
|
|
74
|
-
* @param options - Configuration options
|
|
75
|
-
* @returns The SDL content as a string
|
|
76
|
-
*/
|
|
77
|
-
async function buildSchemaSDLFromDatabase(options) {
|
|
78
|
-
const { database, schemas } = options;
|
|
79
|
-
// PostGraphile v5 resolves role/settings via preset configuration.
|
|
80
|
-
return (0, graphql_server_1.buildSchemaSDL)({
|
|
81
|
-
database,
|
|
82
|
-
schemas,
|
|
83
|
-
});
|
|
84
|
-
}
|
package/core/generate.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { GraphQLSDKConfigTarget } from '../types/config';
|
|
1
|
+
import type { CliConfig, GraphQLSDKConfigTarget } from '../types/config';
|
|
2
|
+
import type { CleanOperation, CleanTable } from '../types/schema';
|
|
2
3
|
export interface GenerateOptions extends GraphQLSDKConfigTarget {
|
|
3
4
|
authorization?: string;
|
|
4
5
|
verbose?: boolean;
|
|
5
6
|
dryRun?: boolean;
|
|
6
7
|
skipCustomOperations?: boolean;
|
|
8
|
+
schemaOnly?: boolean;
|
|
9
|
+
schemaOnlyOutput?: string;
|
|
10
|
+
schemaOnlyFilename?: string;
|
|
7
11
|
}
|
|
8
12
|
export interface GenerateResult {
|
|
9
13
|
success: boolean;
|
|
@@ -12,6 +16,13 @@ export interface GenerateResult {
|
|
|
12
16
|
tables?: string[];
|
|
13
17
|
filesWritten?: string[];
|
|
14
18
|
errors?: string[];
|
|
19
|
+
pipelineData?: {
|
|
20
|
+
tables: CleanTable[];
|
|
21
|
+
customOperations: {
|
|
22
|
+
queries: CleanOperation[];
|
|
23
|
+
mutations: CleanOperation[];
|
|
24
|
+
};
|
|
25
|
+
};
|
|
15
26
|
}
|
|
16
27
|
/**
|
|
17
28
|
* Main generate function - takes a single config and generates code
|
|
@@ -19,4 +30,25 @@ export interface GenerateResult {
|
|
|
19
30
|
* This is the primary entry point for programmatic usage.
|
|
20
31
|
* For multiple configs, call this function in a loop.
|
|
21
32
|
*/
|
|
22
|
-
export
|
|
33
|
+
export interface GenerateInternalOptions {
|
|
34
|
+
skipCli?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function generate(options?: GenerateOptions, internalOptions?: GenerateInternalOptions): Promise<GenerateResult>;
|
|
37
|
+
export declare function expandApiNamesToMultiTarget(config: GraphQLSDKConfigTarget): Record<string, GraphQLSDKConfigTarget> | null;
|
|
38
|
+
export declare function expandSchemaDirToMultiTarget(config: GraphQLSDKConfigTarget): Record<string, GraphQLSDKConfigTarget> | null;
|
|
39
|
+
export interface GenerateMultiOptions {
|
|
40
|
+
configs: Record<string, GraphQLSDKConfigTarget>;
|
|
41
|
+
cliOverrides?: Partial<GraphQLSDKConfigTarget>;
|
|
42
|
+
verbose?: boolean;
|
|
43
|
+
dryRun?: boolean;
|
|
44
|
+
schemaOnly?: boolean;
|
|
45
|
+
unifiedCli?: CliConfig | boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface GenerateMultiResult {
|
|
48
|
+
results: Array<{
|
|
49
|
+
name: string;
|
|
50
|
+
result: GenerateResult;
|
|
51
|
+
}>;
|
|
52
|
+
hasError: boolean;
|
|
53
|
+
}
|
|
54
|
+
export declare function generateMulti(options: GenerateMultiOptions): Promise<GenerateMultiResult>;
|