Skip to content

Commit 2d7c585

Browse files
committed
refactor: cli
1 parent 081615f commit 2d7c585

37 files changed

Lines changed: 383 additions & 310 deletions

.changeset/fair-points-sin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hey-api/codegen-cli": minor
3+
---
4+
5+
feat: initial release

packages/codegen-cli/package.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"name": "@hey-api/codegen-cli",
3+
"version": "0.0.1",
4+
"description": "⚡ Shared CLI framework for Hey API code generators.",
5+
"keywords": [
6+
"cli",
7+
"codegen",
8+
"generator",
9+
"javascript",
10+
"node",
11+
"typescript"
12+
],
13+
"homepage": "https://heyapi.dev/",
14+
"bugs": {
15+
"url": "https://github.com/hey-api/hey-api/issues"
16+
},
17+
"license": "MIT",
18+
"author": {
19+
"name": "Hey API",
20+
"email": "[email protected]",
21+
"url": "https://heyapi.dev"
22+
},
23+
"repository": {
24+
"type": "git",
25+
"url": "git+https://github.com/hey-api/hey-api.git",
26+
"directory": "packages/codegen-cli"
27+
},
28+
"funding": "https://github.com/sponsors/hey-api",
29+
"files": [
30+
"dist",
31+
"LICENSE.md",
32+
"README.md"
33+
],
34+
"type": "module",
35+
"main": "./dist/index.mjs",
36+
"types": "./dist/index.d.mts",
37+
"exports": {
38+
".": {
39+
"types": "./dist/index.d.mts",
40+
"import": "./dist/index.mjs"
41+
},
42+
"./package.json": "./package.json"
43+
},
44+
"scripts": {
45+
"build": "tsdown",
46+
"dev": "tsdown --watch",
47+
"prepublishOnly": "pnpm build",
48+
"typecheck": "tsgo --noEmit"
49+
},
50+
"dependencies": {
51+
"citty": "0.2.2"
52+
},
53+
"devDependencies": {
54+
"eslint": "9.39.4",
55+
"typescript": "6.0.3"
56+
},
57+
"engines": {
58+
"node": ">=22.18.0"
59+
}
60+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import type { CliConfig } from './types';
2+
3+
interface RawCliArgs {
4+
client?: string;
5+
debug?: boolean;
6+
dryRun?: boolean;
7+
file?: string;
8+
input?: string;
9+
logFile?: boolean;
10+
logs?: string;
11+
output?: string;
12+
plugins?: string;
13+
silent?: boolean;
14+
watch?: string;
15+
}
16+
17+
function splitComma(value: string): string | Array<string> {
18+
const parts = value
19+
.split(',')
20+
.map((s) => s.trim())
21+
.filter(Boolean);
22+
return parts.length === 1 ? parts[0]! : parts;
23+
}
24+
25+
export function cliToConfig(args: RawCliArgs): CliConfig {
26+
const config: CliConfig = {};
27+
28+
if (args.input) config.input = splitComma(args.input);
29+
if (args.output) config.output = splitComma(args.output);
30+
if (args.file) config.configFile = args.file;
31+
if (args.dryRun !== undefined) config.dryRun = args.dryRun;
32+
33+
const plugins: Array<string> = [];
34+
if (args.plugins) {
35+
plugins.push(...args.plugins.split(',').map((p) => p.trim()));
36+
}
37+
if (args.client) plugins.push(args.client);
38+
if (plugins.length) config.plugins = plugins;
39+
40+
if (args.debug || args.silent || args.logs || args.logFile === false) {
41+
config.logs = {
42+
...(args.debug && { level: 'debug' as const }),
43+
...(args.logFile === false && { file: false }),
44+
...(args.logs && { path: args.logs }),
45+
...(args.silent && { level: 'silent' as const }),
46+
};
47+
}
48+
49+
if (args.watch !== undefined) {
50+
if (args.watch === '') {
51+
config.watch = true;
52+
} else {
53+
const interval = Number.parseInt(args.watch, 10);
54+
config.watch = Number.isNaN(interval) ? true : interval;
55+
}
56+
}
57+
58+
return config;
59+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { defineCommand } from 'citty';
2+
3+
import { cliToConfig } from './adapter';
4+
import type { RunCliOptions } from './types';
5+
6+
export function createCommand(options: RunCliOptions) {
7+
return defineCommand({
8+
args: {
9+
client: {
10+
alias: 'c',
11+
description: 'HTTP client to generate',
12+
type: 'string',
13+
},
14+
debug: {
15+
alias: 'd',
16+
description: 'Enable debug logging',
17+
type: 'boolean',
18+
},
19+
'dry-run': {
20+
description: 'Skip writing files',
21+
type: 'boolean',
22+
},
23+
file: {
24+
alias: 'f',
25+
description: 'Path to config file',
26+
type: 'string',
27+
},
28+
input: {
29+
alias: 'i',
30+
description: 'OpenAPI specification(s), comma-separated (path, URL, or string)',
31+
type: 'string',
32+
valueHint: 'paths',
33+
},
34+
'log-file': {
35+
default: true,
36+
negativeDescription: 'Disable log file output',
37+
type: 'boolean',
38+
},
39+
logs: {
40+
alias: 'l',
41+
description: 'Logs folder path',
42+
type: 'string',
43+
},
44+
output: {
45+
alias: 'o',
46+
description: 'Output folder(s), comma-separated',
47+
type: 'string',
48+
valueHint: 'paths',
49+
},
50+
plugins: {
51+
alias: 'p',
52+
description: 'Plugins to use (comma-separated)',
53+
type: 'string',
54+
valueHint: 'names',
55+
},
56+
silent: {
57+
alias: 's',
58+
description: 'Suppress all output',
59+
type: 'boolean',
60+
},
61+
watch: {
62+
alias: 'w',
63+
description: 'Watch for changes (optional interval in ms)',
64+
type: 'string',
65+
valueHint: 'ms',
66+
},
67+
},
68+
meta: {
69+
description: options.meta.description,
70+
name: options.meta.name,
71+
version:
72+
process.env.HEYAPI_CODEGEN_ENV === 'development' ? '[DEVELOPMENT]' : options.meta.version,
73+
},
74+
async run({ args }) {
75+
const config = cliToConfig(args);
76+
console.log('[args]', args);
77+
console.log('[config]', config);
78+
const context = await options.createClient(config);
79+
const hasActiveWatch = context[0]?.config.input.some((input) => input.watch?.enabled);
80+
if (!hasActiveWatch) {
81+
process.exit(0);
82+
}
83+
},
84+
});
85+
}

packages/codegen-cli/src/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { runMain } from 'citty';
2+
3+
import { createCommand } from './command';
4+
import type { RunCliOptions } from './types';
5+
6+
export async function runCli(options: RunCliOptions): Promise<void> {
7+
const command = createCommand(options);
8+
await runMain(command);
9+
}
10+
11+
export type { CliConfig, CliContext, RunCliOptions } from './types';

packages/codegen-cli/src/types.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export interface CliConfig {
2+
configFile?: string;
3+
dryRun?: boolean;
4+
input?: string | Array<string>;
5+
logs?: {
6+
file?: false;
7+
level?: 'debug' | 'silent';
8+
path?: string;
9+
};
10+
output?: string | Array<string>;
11+
plugins?: Array<string>;
12+
watch?: boolean | number;
13+
}
14+
15+
export interface CliContext {
16+
config: {
17+
input: ReadonlyArray<{
18+
watch?: {
19+
enabled?: boolean;
20+
};
21+
}>;
22+
};
23+
}
24+
25+
export interface RunCliOptions {
26+
createClient: (...args: Array<any>) => Promise<ReadonlyArray<CliContext>>;
27+
meta: {
28+
description: string;
29+
name: string;
30+
version: string;
31+
};
32+
}

packages/codegen-cli/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"composite": true,
5+
"outDir": "dist",
6+
"rootDir": "src",
7+
"types": ["vitest/globals", "node"]
8+
},
9+
"include": ["src"]
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { defineConfig } from 'tsdown';
2+
3+
export default defineConfig({
4+
attw: {
5+
ignoreRules: ['cjs-resolves-to-esm'],
6+
profile: 'esm-only',
7+
},
8+
publint: true,
9+
sourcemap: true,
10+
});

packages/codegen-cli/turbo.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "../../node_modules/turbo/schema.json",
3+
"extends": ["//"],
4+
"tasks": {
5+
"build": {
6+
"dependsOn": [],
7+
"outputs": ["dist/**"]
8+
}
9+
}
10+
}

packages/codegen-core/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
},
2222
"repository": {
2323
"type": "git",
24-
"url": "git+https://github.com/hey-api/hey-api.git"
24+
"url": "git+https://github.com/hey-api/hey-api.git",
25+
"directory": "packages/codegen-core"
2526
},
2627
"funding": "https://github.com/sponsors/hey-api",
2728
"files": [

0 commit comments

Comments
 (0)