Skip to content

Commit b6e78b9

Browse files
authored
Merge pull request #677 from constructive-io/update/cli-unify-case
Unify codegen cli to hyphen case
2 parents 3eb4d7c + c20606e commit b6e78b9

9 files changed

Lines changed: 2561 additions & 7080 deletions

File tree

graphql/codegen/README.md

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ Filter patterns support wildcards:
661661

662662
The CLI provides a convenient way to run code generation from the command line.
663663

664-
### `graphql-sdk generate`
664+
### `graphql-codegen`
665665

666666
Generate React Query hooks and/or ORM client from various sources.
667667

@@ -682,62 +682,57 @@ Database Options (for pgpm modes):
682682
Generator Options:
683683
--react-query Generate React Query hooks
684684
--orm Generate ORM client
685-
-t, --target <name> Target name in config file
686685
-o, --output <dir> Output directory
686+
-t, --target <name> Target name (for multi-target configs)
687687
-a, --authorization <token> Authorization header value
688688
--browser-compatible Generate browser-compatible code (default: true)
689689
Set to false for Node.js with localhost DNS fix
690690
--skip-custom-operations Only generate table CRUD operations
691691
--dry-run Preview without writing files
692-
--keep-db Keep ephemeral database after generation (pgpm modes)
693692
-v, --verbose Show detailed output
694-
695-
Watch Mode Options:
696-
-w, --watch Watch for schema changes and regenerate
697-
--poll-interval <ms> Polling interval in milliseconds (default: 5000)
698-
--debounce <ms> Debounce delay in milliseconds (default: 500)
699-
--touch <path> Touch file after regeneration
700-
--no-clear Don't clear console on regeneration
693+
--keep-db Keep ephemeral database after generation (pgpm modes)
694+
-h, --help Show help message
695+
--version Show version number
701696
```
702697

703698
Examples:
704699

705700
```bash
706701
# Generate React Query hooks from an endpoint
707-
npx graphql-sdk generate --endpoint https://api.example.com/graphql --output ./generated --react-query
702+
npx @constructive-io/graphql-codegen --endpoint https://api.example.com/graphql --output ./generated --react-query
708703

709704
# Generate ORM client from an endpoint
710-
npx graphql-sdk generate --endpoint https://api.example.com/graphql --output ./generated --orm
705+
npx @constructive-io/graphql-codegen --endpoint https://api.example.com/graphql --output ./generated --orm
711706

712707
# Generate both React Query hooks and ORM client
713-
npx graphql-sdk generate --endpoint https://api.example.com/graphql --output ./generated --react-query --orm
708+
npx @constructive-io/graphql-codegen --endpoint https://api.example.com/graphql --output ./generated --react-query --orm
714709

715-
# Generate from a PGPM module
716-
npx graphql-sdk generate --pgpm-module-path ./packages/my-module --schemas public --react-query
710+
# Generate from schema file
711+
npx @constructive-io/graphql-codegen --schema-file ./schema.graphql --output ./generated --react-query
717712

718-
# Generate using apiNames for automatic schema discovery
719-
npx graphql-sdk generate --pgpm-module-path ./packages/my-module --api-names my_api --react-query --orm
720-
```
713+
# Generate from database with schemas
714+
npx @constructive-io/graphql-codegen --schemas public,app_public --output ./generated --react-query
721715

722-
### `graphql-sdk init`
716+
# Generate from database with API names
717+
npx @constructive-io/graphql-codegen --api-names my_api --output ./generated --orm
723718

724-
Create a configuration file.
719+
# Use config file
720+
npx @constructive-io/graphql-codegen --config ./graphql-codegen.config.ts
725721

726-
```bash
727-
Options:
728-
-f, --format <format> Config format: ts, js, json (default: ts)
729-
-o, --output <path> Output path for config file
722+
# Generate specific target from multi-target config
723+
npx @constructive-io/graphql-codegen --config ./graphql-codegen.config.ts --target admin
730724
```
731725

732-
### `graphql-sdk introspect`
726+
### Using with Constructive CLI
733727

734-
Inspect schema without generating code.
728+
The `@constructive-io/cli` package includes the codegen command:
735729

736730
```bash
737-
Options:
738-
-e, --endpoint <url> GraphQL endpoint URL
739-
--json Output as JSON
740-
-v, --verbose Show detailed output
731+
# Install Constructive CLI
732+
npm install -g @constructive-io/cli
733+
734+
# Run codegen via cnc
735+
cnc codegen --endpoint http://localhost:5555/graphql --output ./codegen --react-query
741736
```
742737

743738
## Architecture

graphql/codegen/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"find-and-require-package-json": "^0.9.0",
6666
"gql-ast": "workspace:^",
6767
"graphql": "15.10.1",
68-
"inflekt": "^0.3.0",
68+
"inflekt": "^0.3.1",
6969
"inquirerer": "^4.4.0",
7070
"jiti": "^2.6.1",
7171
"oxfmt": "^0.26.0",

graphql/codegen/src/cli/index.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { CLI, CLIOptions, Inquirerer, getPackageJson } from 'inquirerer';
1010
import { generate } from '../core/generate';
1111
import { findConfigFile, loadConfigFile } from '../core/config';
1212
import type { GraphQLSDKConfigTarget } from '../types/config';
13-
import { codegenQuestions, printResult, type CodegenAnswers } from './shared';
13+
import { camelizeArgv, codegenQuestions, printResult, type CodegenAnswers } from './shared';
1414

1515
const usage = `
1616
graphql-codegen - GraphQL SDK generator for Constructive databases
@@ -108,23 +108,26 @@ export const commands = async (
108108
// No config file - prompt for options using shared questions
109109
const answers = await prompter.prompt<CodegenAnswers>(argv as CodegenAnswers, codegenQuestions);
110110

111+
// Convert kebab-case CLI args to camelCase for internal use
112+
const camelized = camelizeArgv(answers) as CodegenAnswers;
113+
111114
// Build db config if schemas or apiNames provided
112-
const db = (answers.schemas || answers.apiNames) ? {
113-
schemas: answers.schemas,
114-
apiNames: answers.apiNames,
115+
const db = (camelized.schemas || camelized.apiNames) ? {
116+
schemas: camelized.schemas,
117+
apiNames: camelized.apiNames,
115118
} : undefined;
116119

117120
const result = await generate({
118-
endpoint: answers.endpoint,
119-
schemaFile: answers.schemaFile,
121+
endpoint: camelized.endpoint,
122+
schemaFile: camelized.schemaFile,
120123
db,
121-
output: answers.output,
122-
authorization: answers.authorization,
123-
reactQuery: answers.reactQuery,
124-
orm: answers.orm,
125-
browserCompatible: answers.browserCompatible,
126-
dryRun: answers.dryRun,
127-
verbose: answers.verbose,
124+
output: camelized.output,
125+
authorization: camelized.authorization,
126+
reactQuery: camelized.reactQuery,
127+
orm: camelized.orm,
128+
browserCompatible: camelized.browserCompatible,
129+
dryRun: camelized.dryRun,
130+
verbose: camelized.verbose,
128131
});
129132

130133
printResult(result);

graphql/codegen/src/cli/shared.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77
import type { Question } from 'inquirerer';
88
import type { GenerateResult } from '../core/generate';
9+
import { camelize } from 'inflekt';
10+
import { inflektTree } from 'inflekt/transform-keys';
911

1012
/**
1113
* Sanitize function that splits comma-separated strings into arrays
@@ -17,6 +19,7 @@ export const splitCommas = (input: string | undefined): string[] | undefined =>
1719

1820
/**
1921
* Interface for codegen CLI answers
22+
* CLI accepts kebab-case arguments, converted to camelCase for internal use
2023
*/
2124
export interface CodegenAnswers {
2225
endpoint?: string;
@@ -43,7 +46,7 @@ export const codegenQuestions: Question[] = [
4346
required: false,
4447
},
4548
{
46-
name: 'schemaFile',
49+
name: 'schema-file',
4750
message: 'Path to GraphQL schema file',
4851
type: 'text',
4952
required: false,
@@ -64,14 +67,14 @@ export const codegenQuestions: Question[] = [
6467
sanitize: splitCommas,
6568
},
6669
{
67-
name: 'apiNames',
70+
name: 'api-names',
6871
message: 'API names (comma-separated)',
6972
type: 'text',
7073
required: false,
7174
sanitize: splitCommas,
7275
},
7376
{
74-
name: 'reactQuery',
77+
name: 'react-query',
7578
message: 'Generate React Query hooks?',
7679
type: 'confirm',
7780
required: false,
@@ -87,7 +90,7 @@ export const codegenQuestions: Question[] = [
8790
useDefault: true,
8891
},
8992
{
90-
name: 'browserCompatible',
93+
name: 'browser-compatible',
9194
message: 'Generate browser-compatible code?',
9295
type: 'confirm',
9396
required: false,
@@ -101,7 +104,7 @@ export const codegenQuestions: Question[] = [
101104
required: false,
102105
},
103106
{
104-
name: 'dryRun',
107+
name: 'dry-run',
105108
message: 'Preview without writing files?',
106109
type: 'confirm',
107110
required: false,
@@ -133,3 +136,16 @@ export function printResult(result: GenerateResult): void {
133136
process.exit(1);
134137
}
135138
}
139+
140+
const isTopLevel = (_key: string, path: string[]) => path.length === 0;
141+
export const camelizeArgv = (argv: Record<string, any>) =>
142+
inflektTree(argv, (key) => {
143+
// inflection.camelize expects underscores, so replace hyphens first
144+
const underscored = key.replace(/-/g, '_');
145+
return camelize(underscored, true);
146+
}, {
147+
skip: (key, path) =>
148+
!isTopLevel(key, path) ||
149+
key === '_' ||
150+
key.startsWith('_')
151+
});

graphql/codegen/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export type { GenerateOptions, GenerateResult } from './core/generate';
2929
export { findConfigFile, loadConfigFile } from './core/config';
3030

3131
// CLI shared utilities (for packages/cli to import)
32-
export { codegenQuestions, splitCommas, printResult } from './cli/shared';
32+
export { codegenQuestions, splitCommas, printResult, camelizeArgv } from './cli/shared';
3333
export type { CodegenAnswers } from './cli/shared';
3434

3535
// Database schema utilities (re-exported from core for convenience)

packages/cli/README.md

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,40 @@ cnc explorer --origin http://localhost:3000
6161
Generate TypeScript types, operations, and SDK from a GraphQL schema or endpoint.
6262

6363
```bash
64-
# From endpoint
65-
cnc codegen --endpoint http://localhost:5555/graphql --out ./codegen
64+
# Generate React Query hooks from endpoint
65+
cnc codegen --endpoint http://localhost:5555/graphql --output ./codegen --react-query
6666

67-
# From database
68-
cnc codegen --database constructive_db --out ./codegen --verbose
67+
# Generate ORM client from endpoint
68+
cnc codegen --endpoint http://localhost:5555/graphql --output ./codegen --orm
69+
70+
# Generate both React Query hooks and ORM client
71+
cnc codegen --endpoint http://localhost:5555/graphql --output ./codegen --react-query --orm
72+
73+
# From schema file
74+
cnc codegen --schema-file ./schema.graphql --output ./codegen --react-query
75+
76+
# From database with schemas
77+
cnc codegen --schemas public,app_public --output ./codegen --react-query
78+
79+
# From database with API names
80+
cnc codegen --api-names my_api --output ./codegen --orm
6981
```
7082

7183
**Options:**
7284

85+
- `--config <path>` - Path to config file
7386
- `--endpoint <url>` - GraphQL endpoint URL
74-
- `--auth <token>` - Authorization header value (e.g., "Bearer 123")
75-
- `--out <dir>` - Output directory (default: graphql/codegen/dist)
87+
- `--schema-file <path>` - Path to GraphQL schema file
88+
- `--schemas <list>` - Comma-separated PostgreSQL schemas
89+
- `--api-names <list>` - Comma-separated API names
90+
- `--react-query` - Generate React Query hooks
91+
- `--orm` - Generate ORM client
92+
- `--output <dir>` - Output directory (default: ./codegen)
93+
- `--authorization <token>` - Authorization header value
94+
- `--browser-compatible` - Generate browser-compatible code (default: true)
7695
- `--dry-run` - Preview without writing files
7796
- `--verbose` - Verbose output
7897

79-
- `--database <name>` - Database override for DB mode (defaults to PGDATABASE)
80-
- `--schemas <list>` - Comma-separated schemas (required unless using --endpoint)
81-
8298
### `cnc get-graphql-schema`
8399

84100
Fetch or build GraphQL schema SDL.

packages/cli/__tests__/codegen.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jest.mock('@constructive-io/graphql-codegen', () => {
3535
process.exit(1);
3636
}
3737
}),
38+
camelizeArgv: jest.fn((argv: Record<string, any>) => argv),
3839
};
3940
})
4041

packages/cli/src/commands/codegen.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
findConfigFile,
55
codegenQuestions,
66
printResult,
7+
camelizeArgv,
78
type CodegenAnswers,
89
} from '@constructive-io/graphql-codegen';
910

@@ -15,20 +16,20 @@ Constructive GraphQL Codegen:
1516
Source Options (choose one):
1617
--config <path> Path to graphql-codegen config file
1718
--endpoint <url> GraphQL endpoint URL
18-
--schemaFile <path> Path to GraphQL schema file
19+
--schema-file <path> Path to GraphQL schema file
1920
2021
Database Options:
2122
--schemas <list> Comma-separated PostgreSQL schemas
22-
--apiNames <list> Comma-separated API names
23+
--api-names <list> Comma-separated API names
2324
2425
Generator Options:
25-
--reactQuery Generate React Query hooks (default)
26+
--react-query Generate React Query hooks (default)
2627
--orm Generate ORM client
2728
--output <dir> Output directory (default: codegen)
2829
--authorization <token> Authorization header value
29-
--browserCompatible Generate browser-compatible code (default: true)
30+
--browser-compatible Generate browser-compatible code (default: true)
3031
Set to false for Node.js with localhost DNS fix
31-
--dryRun Preview without writing files
32+
--dry-run Preview without writing files
3233
--verbose Verbose output
3334
3435
--help, -h Show this help message
@@ -55,24 +56,26 @@ export default async (
5556

5657
// No config file - prompt for options using shared questions
5758
const answers = await prompter.prompt<CodegenAnswers>(argv as CodegenAnswers, codegenQuestions);
59+
// Convert kebab-case CLI args to camelCase for internal use
60+
const camelized = camelizeArgv(answers);
5861

5962
// Build db config if schemas or apiNames provided
60-
const db = (answers.schemas || answers.apiNames) ? {
61-
schemas: answers.schemas,
62-
apiNames: answers.apiNames,
63+
const db = (camelized.schemas || camelized.apiNames) ? {
64+
schemas: camelized.schemas,
65+
apiNames: camelized.apiNames,
6366
} : undefined;
6467

6568
const result = await generate({
66-
endpoint: answers.endpoint,
67-
schemaFile: answers.schemaFile,
69+
endpoint: camelized.endpoint,
70+
schemaFile: camelized.schemaFile,
6871
db,
69-
output: answers.output,
70-
authorization: answers.authorization,
71-
reactQuery: answers.reactQuery,
72-
orm: answers.orm,
73-
browserCompatible: answers.browserCompatible,
74-
dryRun: answers.dryRun,
75-
verbose: answers.verbose,
72+
output: camelized.output,
73+
authorization: camelized.authorization,
74+
reactQuery: camelized.reactQuery,
75+
orm: camelized.orm,
76+
browserCompatible: camelized.browserCompatible,
77+
dryRun: camelized.dryRun,
78+
verbose: camelized.verbose,
7679
});
7780

7881
printResult(result);

0 commit comments

Comments
 (0)