From 571bc8a32b55647083bb506d4a5b575c4736cb94 Mon Sep 17 00:00:00 2001 From: Lubos Date: Tue, 10 Mar 2026 17:29:30 +0100 Subject: [PATCH] fix: show environment value in development --- .changeset/cute-hotels-write.md | 5 ++ .changeset/proud-geckos-grab.md | 5 ++ .changeset/smart-pugs-jog.md | 5 ++ package.json | 4 +- packages/openapi-python/src/cli/index.ts | 3 +- .../src/generate/__tests__/client.test.ts | 86 ------------------- .../openapi-python/src/generate/client.ts | 18 +--- packages/openapi-ts/src/cli/index.ts | 3 +- packages/openapi-ts/src/generate/client.ts | 18 +--- .../src/__tests__/cli.test.ts} | 31 +++---- packages/shared/src/cli.ts | 12 ++- packages/shared/src/index.ts | 2 +- 12 files changed, 52 insertions(+), 140 deletions(-) create mode 100644 .changeset/cute-hotels-write.md create mode 100644 .changeset/proud-geckos-grab.md create mode 100644 .changeset/smart-pugs-jog.md delete mode 100644 packages/openapi-python/src/generate/__tests__/client.test.ts rename packages/{openapi-ts/src/generate/__tests__/client.test.ts => shared/src/__tests__/cli.test.ts} (73%) diff --git a/.changeset/cute-hotels-write.md b/.changeset/cute-hotels-write.md new file mode 100644 index 000000000..a8f562df7 --- /dev/null +++ b/.changeset/cute-hotels-write.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +**cli**: show environment value in development diff --git a/.changeset/proud-geckos-grab.md b/.changeset/proud-geckos-grab.md new file mode 100644 index 000000000..123392bd4 --- /dev/null +++ b/.changeset/proud-geckos-grab.md @@ -0,0 +1,5 @@ +--- +"@hey-api/shared": patch +--- + +**cli**: export isEnvironment function diff --git a/.changeset/smart-pugs-jog.md b/.changeset/smart-pugs-jog.md new file mode 100644 index 000000000..84f85644c --- /dev/null +++ b/.changeset/smart-pugs-jog.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-python": patch +--- + +**cli**: show environment value in development diff --git a/package.json b/package.json index 824ae7a6a..adbb8b716 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ "tu": "turbo run build && vitest watch --update --project", "tb": "turbo run build --filter", "ty": "turbo run typecheck --filter", - "dev:ts": "cd dev && OPENAPI_TS_DEV_MODE=1 tsx watch --clear-screen=false ../packages/openapi-ts/src/run.ts", - "dev:py": "cd dev && OPENAPI_TS_DEV_MODE=1 tsx watch --clear-screen=false ../packages/openapi-python/src/run.ts" + "dev:ts": "cd dev && HEYAPI_CODEGEN_ENV=development tsx watch --clear-screen=false ../packages/openapi-ts/src/run.ts", + "dev:py": "cd dev && HEYAPI_CODEGEN_ENV=development tsx watch --clear-screen=false ../packages/openapi-python/src/run.ts" }, "devDependencies": { "@arethetypeswrong/cli": "0.18.2", diff --git a/packages/openapi-python/src/cli/index.ts b/packages/openapi-python/src/cli/index.ts index 40f74181f..5fc811367 100644 --- a/packages/openapi-python/src/cli/index.ts +++ b/packages/openapi-python/src/cli/index.ts @@ -1,3 +1,4 @@ +import { isEnvironment } from '@hey-api/shared'; import { Command, CommanderError } from 'commander'; import pkg from '../../package.json'; @@ -9,7 +10,7 @@ const binName = Object.keys(pkg.bin)[0]!; const program = new Command() .name(binName) .description('Generate Python code from OpenAPI specifications') - .version(pkg.version); + .version(isEnvironment('development') ? '[DEVELOPMENT]' : pkg.version); program .option('-i, --input ', 'OpenAPI specification (path, URL, or string)') diff --git a/packages/openapi-python/src/generate/__tests__/client.test.ts b/packages/openapi-python/src/generate/__tests__/client.test.ts deleted file mode 100644 index 2868d4e43..000000000 --- a/packages/openapi-python/src/generate/__tests__/client.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { isDevMode } from '../client'; - -/** - * Replicates the outputHeaderToPrefix logic from generate/client.ts for testing. - */ -function outputHeaderToPrefix(header: unknown): string { - if (header == null || typeof header === 'function') return ''; - const lines = - typeof header === 'string' - ? header.split(/\r?\n/) - : (header as string[]).flatMap((line) => line.split(/\r?\n/)); - const content = lines.join('\n'); - return content ? `${content}\n\n` : ''; -} - -describe('outputHeaderToPrefix logic', () => { - it('returns default comment for string header', () => { - const result = outputHeaderToPrefix('# This file is auto-generated by @hey-api/openapi-python'); - expect(result).toBe('# This file is auto-generated by @hey-api/openapi-python\n\n'); - }); - - it('returns joined lines for array header', () => { - const result = outputHeaderToPrefix([ - '# This file is auto-generated by @hey-api/openapi-python', - '# type: ignore', - ]); - expect(result).toBe( - '# This file is auto-generated by @hey-api/openapi-python\n# type: ignore\n\n', - ); - }); - - it('returns empty string for null header', () => { - expect(outputHeaderToPrefix(null)).toBe(''); - }); - - it('returns empty string for undefined header', () => { - expect(outputHeaderToPrefix(undefined)).toBe(''); - }); - - it('returns empty string for function header', () => { - expect(outputHeaderToPrefix(() => '# dynamic')).toBe(''); - }); - - it('handles string with embedded newlines', () => { - const result = outputHeaderToPrefix('# line1\n# line2'); - expect(result).toBe('# line1\n# line2\n\n'); - }); -}); - -describe('isDevMode logic', () => { - const originalEnv = process.env; - - beforeEach(() => { - process.env = { ...originalEnv }; - delete process.env.OPENAPI_TS_DEV_MODE; - }); - - afterAll(() => { - process.env = originalEnv; - }); - - it('returns false when env var is not set', () => { - expect(isDevMode()).toBe(false); - }); - - it('returns true when env var is set to "true"', () => { - process.env.OPENAPI_TS_DEV_MODE = 'true'; - expect(isDevMode()).toBe(true); - }); - - it('returns true when env var is set to "1"', () => { - process.env.OPENAPI_TS_DEV_MODE = '1'; - expect(isDevMode()).toBe(true); - }); - - it('returns false when env var is set to other values', () => { - process.env.OPENAPI_TS_DEV_MODE = '0'; - expect(isDevMode()).toBe(false); - - process.env.OPENAPI_TS_DEV_MODE = 'false'; - expect(isDevMode()).toBe(false); - - process.env.OPENAPI_TS_DEV_MODE = 'anything'; - expect(isDevMode()).toBe(false); - }); -}); diff --git a/packages/openapi-python/src/generate/client.ts b/packages/openapi-python/src/generate/client.ts index 3df26f83b..f118014fe 100644 --- a/packages/openapi-python/src/generate/client.ts +++ b/packages/openapi-python/src/generate/client.ts @@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url'; import type { IProject } from '@hey-api/codegen-core'; import type { DefinePlugin, OutputHeader } from '@hey-api/shared'; -import { ensureDirSync, outputHeaderToPrefix } from '@hey-api/shared'; +import { ensureDirSync, isEnvironment, outputHeaderToPrefix } from '@hey-api/shared'; import type { Config } from '../config/types'; import type { Client } from '../plugins/@hey-api/client-core/types'; @@ -13,13 +13,6 @@ import { getClientPlugin } from '../plugins/@hey-api/client-core/utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -/** - * Dev mode: determined by OPENAPI_TS_DEV_MODE environment variable - */ -export function isDevMode(): boolean { - return process.env.OPENAPI_TS_DEV_MODE === 'true' || process.env.OPENAPI_TS_DEV_MODE === '1'; -} - /** * Returns paths to client bundle files based on execution context */ @@ -29,7 +22,7 @@ function getClientBundlePaths(pluginName: string): { } { const clientName = pluginName.slice('@hey-api/client-'.length); - if (isDevMode()) { + if (isEnvironment('development')) { // Dev: source bundle folders at src/plugins/@hey-api/{client}/bundle const pluginsDir = path.resolve(__dirname, '..', 'plugins', '@hey-api'); return { @@ -107,18 +100,16 @@ function renameFile({ function replaceImports({ filePath, header, - isDevMode, renamed, }: { filePath: string; header?: string; - isDevMode?: boolean; renamed: Map; }): void { let content = fs.readFileSync(filePath, 'utf8'); // Dev mode: rewrite source bundle imports to match output structure - if (isDevMode) { + if (isEnvironment('development')) { // ...client_core.bundle.foo -> ..core.foo content = content.replace( /from\s+(\.{3,})\.?client_core\.bundle\./g, @@ -163,7 +154,6 @@ export function generateClientBundle({ project: IProject; }): Map | undefined { const renamed = new Map(); - const devMode = isDevMode(); const headerPrefix = outputHeaderToPrefix(header, project); // copy Hey API clients to output @@ -206,7 +196,6 @@ export function generateClientBundle({ // for (const file of coreFiles) { // replaceImports({ // filePath: path.resolve(coreOutputPath, file), - // isDevMode: devMode, // renamed, // }); // } @@ -216,7 +205,6 @@ export function generateClientBundle({ replaceImports({ filePath: path.resolve(clientOutputPath, file), header: headerPrefix, - isDevMode: devMode, renamed, }); } diff --git a/packages/openapi-ts/src/cli/index.ts b/packages/openapi-ts/src/cli/index.ts index 7d374faa3..e429773a9 100644 --- a/packages/openapi-ts/src/cli/index.ts +++ b/packages/openapi-ts/src/cli/index.ts @@ -1,3 +1,4 @@ +import { isEnvironment } from '@hey-api/shared'; import { Command, CommanderError } from 'commander'; import pkg from '../../package.json'; @@ -9,7 +10,7 @@ const binName = Object.keys(pkg.bin)[0]!; const program = new Command() .name(binName) .description('Generate TypeScript code from OpenAPI specifications') - .version(pkg.version); + .version(isEnvironment('development') ? '[DEVELOPMENT]' : pkg.version); program .option('-i, --input ', 'OpenAPI specification (path, URL, or string)') diff --git a/packages/openapi-ts/src/generate/client.ts b/packages/openapi-ts/src/generate/client.ts index a7d300c72..a72170b59 100644 --- a/packages/openapi-ts/src/generate/client.ts +++ b/packages/openapi-ts/src/generate/client.ts @@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url'; import type { IProject, ProjectRenderMeta } from '@hey-api/codegen-core'; import type { DefinePlugin, OutputHeader } from '@hey-api/shared'; -import { ensureDirSync, outputHeaderToPrefix } from '@hey-api/shared'; +import { ensureDirSync, isEnvironment, outputHeaderToPrefix } from '@hey-api/shared'; import type { Config } from '../config/types'; import type { Client } from '../plugins/@hey-api/client-core/types'; @@ -13,13 +13,6 @@ import { getClientPlugin } from '../plugins/@hey-api/client-core/utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -/** - * Dev mode: determined by OPENAPI_TS_DEV_MODE environment variable - */ -export function isDevMode(): boolean { - return process.env.OPENAPI_TS_DEV_MODE === 'true' || process.env.OPENAPI_TS_DEV_MODE === '1'; -} - /** * Returns paths to client bundle files based on execution context */ @@ -29,7 +22,7 @@ function getClientBundlePaths(pluginName: string): { } { const clientName = pluginName.slice('@hey-api/client-'.length); - if (isDevMode()) { + if (isEnvironment('development')) { // Dev: source bundle folders at src/plugins/@hey-api/{client}/bundle const pluginsDir = path.resolve(__dirname, '..', 'plugins', '@hey-api'); return { @@ -107,20 +100,18 @@ function renameFile({ function replaceImports({ filePath, header, - isDevMode, meta, renamed, }: { filePath: string; header?: string; - isDevMode?: boolean; meta: ProjectRenderMeta; renamed: Map; }): void { let content = fs.readFileSync(filePath, 'utf8'); // Dev mode: rewrite source bundle imports to match output structure - if (isDevMode) { + if (isEnvironment('development')) { // ../../client-core/bundle/foo -> ../core/foo content = content.replace(/from\s+['"]\.\.\/\.\.\/client-core\/bundle\//g, "from '../core/"); // ../../client-core/bundle' (index import) @@ -166,7 +157,6 @@ export function generateClientBundle({ project: IProject; }): Map | undefined { const renamed = new Map(); - const devMode = isDevMode(); const headerPrefix = outputHeaderToPrefix(header, project); // copy Hey API clients to output @@ -209,7 +199,6 @@ export function generateClientBundle({ replaceImports({ filePath: path.resolve(coreOutputPath, file), header: headerPrefix, - isDevMode: devMode, meta, renamed, }); @@ -220,7 +209,6 @@ export function generateClientBundle({ replaceImports({ filePath: path.resolve(clientOutputPath, file), header: headerPrefix, - isDevMode: devMode, meta, renamed, }); diff --git a/packages/openapi-ts/src/generate/__tests__/client.test.ts b/packages/shared/src/__tests__/cli.test.ts similarity index 73% rename from packages/openapi-ts/src/generate/__tests__/client.test.ts rename to packages/shared/src/__tests__/cli.test.ts index ec1183192..274d32d3e 100644 --- a/packages/openapi-ts/src/generate/__tests__/client.test.ts +++ b/packages/shared/src/__tests__/cli.test.ts @@ -1,4 +1,4 @@ -import { isDevMode } from '../client'; +import { isEnvironment } from '../cli'; /** * Replicates the outputHeaderToPrefix logic from generate/client.ts for testing. @@ -47,12 +47,12 @@ describe('outputHeaderToPrefix logic', () => { }); }); -describe('isDevMode logic', () => { +describe('isEnvironment', () => { const originalEnv = process.env; beforeEach(() => { process.env = { ...originalEnv }; - delete process.env.OPENAPI_TS_DEV_MODE; + delete process.env.HEYAPI_CODEGEN_ENV; }); afterAll(() => { @@ -60,27 +60,22 @@ describe('isDevMode logic', () => { }); it('returns false when env var is not set', () => { - expect(isDevMode()).toBe(false); + expect(isEnvironment('development')).toBe(false); }); - it('returns true when env var is set to "true"', () => { - process.env.OPENAPI_TS_DEV_MODE = 'true'; - expect(isDevMode()).toBe(true); - }); - - it('returns true when env var is set to "1"', () => { - process.env.OPENAPI_TS_DEV_MODE = '1'; - expect(isDevMode()).toBe(true); + it('returns true when env var is set to "development"', () => { + process.env.HEYAPI_CODEGEN_ENV = 'development'; + expect(isEnvironment('development')).toBe(true); }); it('returns false when env var is set to other values', () => { - process.env.OPENAPI_TS_DEV_MODE = '0'; - expect(isDevMode()).toBe(false); + process.env.HEYAPI_CODEGEN_ENV = '0'; + expect(isEnvironment('development')).toBe(false); - process.env.OPENAPI_TS_DEV_MODE = 'false'; - expect(isDevMode()).toBe(false); + process.env.HEYAPI_CODEGEN_ENV = 'false'; + expect(isEnvironment('development')).toBe(false); - process.env.OPENAPI_TS_DEV_MODE = 'anything'; - expect(isDevMode()).toBe(false); + process.env.HEYAPI_CODEGEN_ENV = 'anything'; + expect(isEnvironment('development')).toBe(false); }); }); diff --git a/packages/shared/src/cli.ts b/packages/shared/src/cli.ts index 5df16c169..f87389ccd 100644 --- a/packages/shared/src/cli.ts +++ b/packages/shared/src/cli.ts @@ -38,6 +38,13 @@ const asciiToLines = ( return { lines, maxLineLength }; }; +/** + * Checks the current environment based on the HEYAPI_CODEGEN_ENV environment variable. + */ +export function isEnvironment(value: 'development'): boolean { + return process.env.HEYAPI_CODEGEN_ENV === value; +} + // TODO: show ascii logo only in `--help` and `--version` commands export function printCliIntro(initialDir: string, showLogo: boolean = false): void { const packageJson = loadPackageJson(initialDir); @@ -48,7 +55,10 @@ export function printCliIntro(initialDir: string, showLogo: boolean = false): vo console.log(colors.cyan(line)); } } - console.log(colors.gray(`${packageJson.name} v${packageJson.version}`)); + const versionString = isEnvironment('development') + ? '[DEVELOPMENT]' + : `v${packageJson.version}`; + console.log(colors.gray(`${packageJson.name} ${versionString}`)); } console.log(''); } diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index d5c5cd295..5f7b8d597 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,4 +1,4 @@ -export { printCliIntro } from './cli'; +export { isEnvironment, printCliIntro } from './cli'; export { checkNodeVersion } from './config/engine'; export { getInput } from './config/input/input'; export { compileInputPath, logInputPaths } from './config/input/path'; -- 2.51.2