diff --git a/packages/kubernetes-typescript-client-codegen-openapi/package.json b/packages/kubernetes-typescript-client-codegen-openapi/package.json index fa72c882..aed49c59 100644 --- a/packages/kubernetes-typescript-client-codegen-openapi/package.json +++ b/packages/kubernetes-typescript-client-codegen-openapi/package.json @@ -1,6 +1,6 @@ { "name": "kubernetes-typescript-client-codegen-openapi", - "version": "0.0.12", + "version": "0.0.13", "main": "lib/index.js", "types": "lib/index.d.ts", "author": "kahirokunn", @@ -20,7 +20,7 @@ "format": "prettier --write \"src/**/*.ts\"", "esm:test:update": "NODE_OPTIONS=--experimental-vm-modules jest --runInBand --updateSnapshot", "test:update": "jest --runInBand --updateSnapshot", - "test": "jest --runInBand", + "test": "jest --runInBand --silent=false", "cli": "esr src/bin/cli.ts" }, "files": [ diff --git a/packages/kubernetes-typescript-client-codegen-openapi/src/generate.ts b/packages/kubernetes-typescript-client-codegen-openapi/src/generate.ts index 36385867..4515dda5 100644 --- a/packages/kubernetes-typescript-client-codegen-openapi/src/generate.ts +++ b/packages/kubernetes-typescript-client-codegen-openapi/src/generate.ts @@ -72,6 +72,7 @@ export async function generateApi( isDataResponse = defaultIsDataResponse, filterEndpoints, unionUndefined = true, + strict = true, }: GenerationOptions ) { const v3Doc = await getV3Doc(spec); @@ -347,7 +348,7 @@ export async function generateApi( [ factory.createPropertyAssignment( factory.createIdentifier('path'), - generatePathExpression(path, pickParams('path'), rootObject) + generatePathExpression(path, pickParams('path'), rootObject, strict) ), verb.toUpperCase() === 'GET' ? undefined @@ -382,13 +383,30 @@ function accessProperty(rootObject: ts.Identifier, propertyName: string) { : factory.createElementAccessExpression(rootObject, factory.createStringLiteral(propertyName)); } -function generatePathExpression(path: string, pathParameters: QueryArgDefinition[], rootObject: ts.Identifier) { +function generatePathExpression(path: string, pathParameters: QueryArgDefinition[], rootObject: ts.Identifier, strict: boolean) { const expressions: Array<[string, string]> = []; const head = path.replace(/\{(.*?)\}(.*?)(?=\{|$)/g, (_, expression, literal) => { - const param = pathParameters.find((p) => p.originalName === expression); + let param = pathParameters.find((p) => p.originalName === expression); if (!param) { - throw new Error(`path parameter ${expression} does not seem to be defined in '${path}'!`); + if (strict) { + throw new Error(`path parameter ${expression} does not seem to be defined in '${path}'!`); + } + param = { + origin: 'param', + name: expression, + originalName: expression, + type: factory.createToken(ts.SyntaxKind.StringKeyword), + required: true, + param: { + name: expression, + in: 'path', + description: 'The name that needs to be deleted', + required: true, + schema: { type: 'string' }, + }, + }; + pathParameters.push(param); } expressions.push([param.name, literal]); return ''; diff --git a/packages/kubernetes-typescript-client-codegen-openapi/src/types.ts b/packages/kubernetes-typescript-client-codegen-openapi/src/types.ts index 002803e3..5ed6fe15 100644 --- a/packages/kubernetes-typescript-client-codegen-openapi/src/types.ts +++ b/packages/kubernetes-typescript-client-codegen-openapi/src/types.ts @@ -55,6 +55,12 @@ export interface CommonOptions { * `true` will generate a union type for `undefined` properties like: `{ id?: string | undefined }` instead of `{ id?: string }` */ unionUndefined?: boolean; + + /** + * defaults to true + * If `true`, an error will occur if the path parameter does not exist, but if `false`, it will be automatically filled in as a string. + */ + strict?: boolean; } export type TextMatcher = string | RegExp | (string | RegExp)[]; diff --git a/packages/kubernetes-typescript-client-codegen-openapi/test/cli.test.ts b/packages/kubernetes-typescript-client-codegen-openapi/test/cli.test.ts index e97d218b..e00884ea 100644 --- a/packages/kubernetes-typescript-client-codegen-openapi/test/cli.test.ts +++ b/packages/kubernetes-typescript-client-codegen-openapi/test/cli.test.ts @@ -4,6 +4,26 @@ import * as fs from 'fs'; import path from 'path'; import del from 'del'; +function strictCli( + args: string[], + cwd: string +): Promise<{ error: ExecException | null; stdout: string; stderr: string }> { + const pwd = (process.env && process.env.PWD) || '.'; + const cmd = `${require.resolve('ts-node/dist/bin')} -T -P ${path.resolve(pwd, 'tsconfig.json')} ${path.resolve( + pwd, + 'src/bin/cli.ts' + )} ${args.join(' ')}`; + return new Promise((resolve) => { + exec(cmd, { cwd }, (error, stdout, stderr) => { + resolve({ + error, + stdout, + stderr, + }); + }); + }); +} + function cli(args: string[], cwd: string): Promise<{ error: ExecException | null; stdout: string; stderr: string }> { const pwd = (process.env && process.env.PWD) || '.'; const cmd = `${require.resolve('ts-node/dist/bin')} -T -P ${path.resolve(pwd, 'tsconfig.json')} ${path.resolve( @@ -33,7 +53,7 @@ afterEach(() => { describe('CLI options testing', () => { test('generation with `config.example.js`', async () => { - const out = await cli([`./config.example.js`], __dirname); + const out = await strictCli([`./config.example.js`], __dirname); expect(out).toEqual({ stdout: `Generating ./tmp/example.ts @@ -47,7 +67,7 @@ Done }, 25000); test('paths are relative to configfile, not to cwd', async () => { - const out = await cli([`../test/config.example.js`], path.resolve(__dirname, '../src')); + const out = await strictCli([`../test/config.example.js`], path.resolve(__dirname, '../src')); expect(out).toEqual({ stdout: `Generating ./tmp/example.ts @@ -61,19 +81,24 @@ Done }, 25000); test('ts, js and json all work the same', async () => { - await cli([`./config.example.js`], __dirname); + await strictCli([`./config.example.js`], __dirname); const fromJs = fs.readFileSync(path.resolve(tmpDir, 'example.ts'), 'utf-8'); - await cli([`./config.example.ts`], __dirname); + await strictCli([`./config.example.ts`], __dirname); const fromTs = fs.readFileSync(path.resolve(tmpDir, 'example.ts'), 'utf-8'); - await cli([`./config.example.json`], __dirname); + await strictCli([`./config.example.json`], __dirname); const fromJson = fs.readFileSync(path.resolve(tmpDir, 'example.ts'), 'utf-8'); expect(fromTs).toEqual(fromJs); expect(fromJson).toEqual(fromJs); }, 45000); - test('missing parameters doesnt fail', async () => { - const out = await cli([`./config.invalid-example.json`], __dirname); + test("missing parameters doesn't fail", async () => { + const out = await strictCli([`./config.invalid-example.json`], __dirname); expect(out.stderr).toContain("Error: path parameter petId does not seem to be defined in '/pet/{petId}'!"); }, 25000); + + test('missing path parameters does fail', async () => { + const out = await cli([`./config.valid-example.ts`], __dirname); + expect(out.stderr).not.toContain("Error: path parameter petId does not seem to be defined in '/pet/{petId}'!"); + }, 25000); }); diff --git a/packages/kubernetes-typescript-client-codegen-openapi/test/config.valid-example.ts b/packages/kubernetes-typescript-client-codegen-openapi/test/config.valid-example.ts new file mode 100644 index 00000000..280b3180 --- /dev/null +++ b/packages/kubernetes-typescript-client-codegen-openapi/test/config.valid-example.ts @@ -0,0 +1,10 @@ +import type { ConfigFile } from 'kahirokunn/kubernetes-typescript-client-codegen-openapi'; + +const config: ConfigFile = { + schemaFile: './fixtures/invalid-petstore.json', + apiFile: './fixtures/k8sApiClient.ts', + outputFile: './tmp/example.ts', + strict: false, +}; + +export default config;