Skip to content

Commit 5665daa

Browse files
authored
Merge pull request #737 from constructive-io/devin/1771925145-codegen-upstream-fixes
fix(codegen): upstream CLI fixes - no-arg query, field defaults, NodeHttpAdapter as top-level option
2 parents 62d333e + 09eb43b commit 5665daa

11 files changed

Lines changed: 425 additions & 35 deletions

File tree

graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ export default async (argv: Partial<Record<string, unknown>>, prompter: Inquirer
11531153
}
11541154
const client = getClient();
11551155
const selectFields = buildSelectFromPaths(argv.select ?? "");
1156-
const result = await client.query.currentUser({}, {
1156+
const result = await client.query.currentUser({
11571157
select: selectFields
11581158
}).execute();
11591159
console.log(JSON.stringify(result, null, 2));

graphql/codegen/src/core/codegen/cli/custom-command-generator.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,21 @@ function buildOrmCustomCall(
143143
opName: string,
144144
argsExpr: t.Expression,
145145
selectExpr?: t.Expression,
146+
hasArgs: boolean = true,
146147
): t.Expression {
147-
const callArgs: t.Expression[] = [argsExpr];
148-
if (selectExpr) {
148+
const callArgs: t.Expression[] = [];
149+
if (hasArgs) {
150+
// Operation has arguments: pass args as first param, select as second
151+
callArgs.push(argsExpr);
152+
if (selectExpr) {
153+
callArgs.push(
154+
t.objectExpression([
155+
t.objectProperty(t.identifier('select'), selectExpr),
156+
]),
157+
);
158+
}
159+
} else if (selectExpr) {
160+
// No arguments: pass { select } as the only param (ORM signature)
149161
callArgs.push(
150162
t.objectExpression([
151163
t.objectProperty(t.identifier('select'), selectExpr),
@@ -343,12 +355,13 @@ export function generateCustomCommand(op: CleanOperation, options?: CustomComman
343355
selectExpr = t.identifier('selectFields');
344356
}
345357

358+
const hasArgs = op.args.length > 0;
346359
bodyStatements.push(
347360
t.variableDeclaration('const', [
348361
t.variableDeclarator(
349362
t.identifier('result'),
350363
t.awaitExpression(
351-
buildOrmCustomCall(opKind, op.name, argsExpr, selectExpr),
364+
buildOrmCustomCall(opKind, op.name, argsExpr, selectExpr, hasArgs),
352365
),
353366
),
354367
]),

graphql/codegen/src/core/codegen/cli/executor-generator.ts

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,21 @@ function createImportDeclaration(
3030
return decl;
3131
}
3232

33-
export function generateExecutorFile(toolName: string): GeneratedFile {
33+
export interface ExecutorOptions {
34+
/** Enable NodeHttpAdapter for *.localhost subdomain routing */
35+
nodeHttpAdapter?: boolean;
36+
}
37+
38+
export function generateExecutorFile(toolName: string, options?: ExecutorOptions): GeneratedFile {
3439
const statements: t.Statement[] = [];
3540

41+
// Import NodeHttpAdapter for *.localhost subdomain routing
42+
if (options?.nodeHttpAdapter) {
43+
statements.push(
44+
createImportDeclaration('./node-fetch', ['NodeHttpAdapter']),
45+
);
46+
}
47+
3648
statements.push(
3749
createImportDeclaration('appstash', ['createConfigStore']),
3850
);
@@ -191,20 +203,39 @@ export function generateExecutorFile(toolName: string): GeneratedFile {
191203
]),
192204
),
193205

194-
t.returnStatement(
195-
t.callExpression(t.identifier('createClient'), [
196-
t.objectExpression([
197-
t.objectProperty(
198-
t.identifier('endpoint'),
199-
t.memberExpression(t.identifier('ctx'), t.identifier('endpoint')),
206+
// Build createClient config — use NodeHttpAdapter for *.localhost endpoints
207+
...(options?.nodeHttpAdapter
208+
? [
209+
t.returnStatement(
210+
t.callExpression(t.identifier('createClient'), [
211+
t.objectExpression([
212+
t.objectProperty(
213+
t.identifier('adapter'),
214+
t.newExpression(t.identifier('NodeHttpAdapter'), [
215+
t.memberExpression(t.identifier('ctx'), t.identifier('endpoint')),
216+
t.identifier('headers'),
217+
]),
218+
),
219+
]),
220+
]),
200221
),
201-
t.objectProperty(
202-
t.identifier('headers'),
203-
t.identifier('headers'),
222+
]
223+
: [
224+
t.returnStatement(
225+
t.callExpression(t.identifier('createClient'), [
226+
t.objectExpression([
227+
t.objectProperty(
228+
t.identifier('endpoint'),
229+
t.memberExpression(t.identifier('ctx'), t.identifier('endpoint')),
230+
),
231+
t.objectProperty(
232+
t.identifier('headers'),
233+
t.identifier('headers'),
234+
),
235+
]),
236+
]),
204237
),
205238
]),
206-
]),
207-
),
208239
]);
209240

210241
const getClientFunc = t.functionDeclaration(
@@ -226,9 +257,17 @@ export function generateExecutorFile(toolName: string): GeneratedFile {
226257
export function generateMultiTargetExecutorFile(
227258
toolName: string,
228259
targets: MultiTargetExecutorInput[],
260+
options?: ExecutorOptions,
229261
): GeneratedFile {
230262
const statements: t.Statement[] = [];
231263

264+
// Import NodeHttpAdapter for *.localhost subdomain routing
265+
if (options?.nodeHttpAdapter) {
266+
statements.push(
267+
createImportDeclaration('./node-fetch', ['NodeHttpAdapter']),
268+
);
269+
}
270+
232271
statements.push(
233272
createImportDeclaration('appstash', ['createConfigStore']),
234273
);
@@ -475,14 +514,33 @@ export function generateMultiTargetExecutorFile(
475514
),
476515
]),
477516
),
478-
t.returnStatement(
479-
t.callExpression(t.identifier('createFn'), [
480-
t.objectExpression([
481-
t.objectProperty(t.identifier('endpoint'), t.identifier('endpoint')),
482-
t.objectProperty(t.identifier('headers'), t.identifier('headers')),
517+
// Build createClient config — use NodeHttpAdapter for *.localhost endpoints
518+
...(options?.nodeHttpAdapter
519+
? [
520+
t.returnStatement(
521+
t.callExpression(t.identifier('createFn'), [
522+
t.objectExpression([
523+
t.objectProperty(
524+
t.identifier('adapter'),
525+
t.newExpression(t.identifier('NodeHttpAdapter'), [
526+
t.identifier('endpoint'),
527+
t.identifier('headers'),
528+
]),
529+
),
530+
]),
531+
]),
532+
),
533+
]
534+
: [
535+
t.returnStatement(
536+
t.callExpression(t.identifier('createFn'), [
537+
t.objectExpression([
538+
t.objectProperty(t.identifier('endpoint'), t.identifier('endpoint')),
539+
t.objectProperty(t.identifier('headers'), t.identifier('headers')),
540+
]),
541+
]),
542+
),
483543
]),
484-
]),
485-
),
486544
]);
487545

488546
const getClientFunc = t.functionDeclaration(

graphql/codegen/src/core/codegen/cli/index.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { BuiltinNames, GraphQLSDKConfigTarget } from '../../../types/config';
2-
import type { CleanOperation, CleanTable } from '../../../types/schema';
2+
import type { CleanOperation, CleanTable, TypeRegistry } from '../../../types/schema';
33
import { generateCommandMap, generateMultiTargetCommandMap } from './command-map-generator';
44
import { generateCustomCommand } from './custom-command-generator';
55
import { generateExecutorFile, generateMultiTargetExecutorFile } from './executor-generator';
@@ -11,7 +11,7 @@ import {
1111
generateMultiTargetContextCommand,
1212
} from './infra-generator';
1313
import { generateTableCommand } from './table-command-generator';
14-
import { generateUtilsFile } from './utils-generator';
14+
import { generateUtilsFile, generateNodeFetchFile } from './utils-generator';
1515

1616
export interface GenerateCliOptions {
1717
tables: CleanTable[];
@@ -20,6 +20,8 @@ export interface GenerateCliOptions {
2020
mutations: CleanOperation[];
2121
};
2222
config: GraphQLSDKConfigTarget;
23+
/** TypeRegistry from introspection, used to check field defaults */
24+
typeRegistry?: TypeRegistry;
2325
}
2426

2527
export interface GenerateCliResult {
@@ -43,20 +45,32 @@ export function generateCli(options: GenerateCliOptions): GenerateCliResult {
4345
? cliConfig.toolName
4446
: 'app';
4547

46-
const executorFile = generateExecutorFile(toolName);
48+
// Use top-level nodeHttpAdapter from config (auto-enabled for CLI by generate.ts)
49+
const useNodeHttpAdapter = !!config.nodeHttpAdapter;
50+
51+
const executorFile = generateExecutorFile(toolName, {
52+
nodeHttpAdapter: useNodeHttpAdapter,
53+
});
4754
files.push(executorFile);
4855

4956
const utilsFile = generateUtilsFile();
5057
files.push(utilsFile);
5158

59+
// Generate node HTTP adapter if configured (for *.localhost subdomain routing)
60+
if (useNodeHttpAdapter) {
61+
files.push(generateNodeFetchFile());
62+
}
63+
5264
const contextFile = generateContextCommand(toolName);
5365
files.push(contextFile);
5466

5567
const authFile = generateAuthCommand(toolName);
5668
files.push(authFile);
5769

5870
for (const table of tables) {
59-
const tableFile = generateTableCommand(table);
71+
const tableFile = generateTableCommand(table, {
72+
typeRegistry: options.typeRegistry,
73+
});
6074
files.push(tableFile);
6175
}
6276

@@ -99,12 +113,16 @@ export interface MultiTargetCliTarget {
99113
mutations: CleanOperation[];
100114
};
101115
isAuthTarget?: boolean;
116+
/** TypeRegistry from introspection, used to check field defaults */
117+
typeRegistry?: TypeRegistry;
102118
}
103119

104120
export interface GenerateMultiTargetCliOptions {
105121
toolName: string;
106122
builtinNames?: BuiltinNames;
107123
targets: MultiTargetCliTarget[];
124+
/** Enable NodeHttpAdapter for *.localhost subdomain routing */
125+
nodeHttpAdapter?: boolean;
108126
}
109127

110128
export function resolveBuiltinNames(
@@ -138,12 +156,19 @@ export function generateMultiTargetCli(
138156
endpoint: t.endpoint,
139157
ormImportPath: t.ormImportPath,
140158
}));
141-
const executorFile = generateMultiTargetExecutorFile(toolName, executorInputs);
159+
const executorFile = generateMultiTargetExecutorFile(toolName, executorInputs, {
160+
nodeHttpAdapter: !!options.nodeHttpAdapter,
161+
});
142162
files.push(executorFile);
143163

144164
const utilsFile = generateUtilsFile();
145165
files.push(utilsFile);
146166

167+
// Generate node HTTP adapter if configured (for *.localhost subdomain routing)
168+
if (options.nodeHttpAdapter) {
169+
files.push(generateNodeFetchFile());
170+
}
171+
147172
const contextFile = generateMultiTargetContextCommand(
148173
toolName,
149174
builtinNames.context,
@@ -174,6 +199,7 @@ export function generateMultiTargetCli(
174199
const tableFile = generateTableCommand(table, {
175200
targetName: target.name,
176201
executorImportPath: '../../executor',
202+
typeRegistry: target.typeRegistry,
177203
});
178204
files.push(tableFile);
179205
}

0 commit comments

Comments
 (0)