diff --git a/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/constants.ts b/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/constants.ts new file mode 100644 index 00000000..8a09e733 --- /dev/null +++ b/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/constants.ts @@ -0,0 +1,9 @@ +export const NEVER_DEFINITION = { + name: undefined, + definition: 'never', +}; + +export const UNKNOWN_DEFINITION = { + name: undefined, + definition: 'unknown', +}; diff --git a/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/helpers.ts b/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/helpers.ts new file mode 100644 index 00000000..92d34388 --- /dev/null +++ b/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/helpers.ts @@ -0,0 +1,82 @@ +import { OpenAPIV3ReferenceableSchemaObject, OperationObject, PathItemObject, PathItemParameters } from '../../types'; +import { OpenAPIV3 } from 'openapi-types'; +import { isReferenceObject } from '../../helpers'; + +export function getResponseSchema(operation: OperationObject): OpenAPIV3ReferenceableSchemaObject | undefined { + const schemas = Object.entries(operation.responses ?? {}) + .map(([status, response]) => { + const statusCode = parseInt(status, 10); + + if (isNaN(statusCode) || statusCode < 200 || statusCode > 299) { + return; + } + + // @ts-ignore Handle $ref content + return response.content?.['application/json'].schema; + }) + .filter(Boolean); + + return schemas.length === 0 + ? undefined + : { + oneOf: schemas, + }; +} + +export function getRequestBodySchema(args: { + operation: OperationObject; +}): OpenAPIV3ReferenceableSchemaObject | undefined { + if (!args.operation.requestBody) { + return; + } + + if (isReferenceObject(args.operation.requestBody)) { + return args.operation.requestBody; + } + + return { + description: args.operation.requestBody.description, + ...args.operation.requestBody.content?.['application/json']?.schema, + }; +} + +export function getParameterSchemaFor(args: { + pathItem: PathItemObject; + operation: OperationObject; + inName: 'path' | 'query'; +}): OpenAPIV3.NonArraySchemaObject | undefined { + const pathParameters = ([] as PathItemParameters) + .concat(args.pathItem.parameters ?? []) + .concat(args.operation.parameters ?? []) + .filter((parameter) => { + // @ts-ignore Handle $ref + return parameter.in === args.inName; + }); + + if (pathParameters.length === 0) { + return; + } + + return pathParameters.reduce( + (schema, parameter) => { + // TODO: Follow up. Technically parameters are never a $ref based on the spec. + const param = parameter as OpenAPIV3.ParameterObject; + + if (param.required) { + schema.required!.push(param.name); + } + + schema.properties[param.name] = { + description: param.description, + ...param.schema, + }; + + return schema; + }, + { + type: 'object', + properties: {}, + required: [], + } as Required> + ); +} diff --git a/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/index.ts b/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/index.ts new file mode 100644 index 00000000..7e79d47a --- /dev/null +++ b/packages/@straw-hat/openapi-web-sdk-generator/src/generators/elixir-tesla/index.ts @@ -0,0 +1,42 @@ +import { forEachHttpOperation } from '../../helpers'; +import { CodegenBase } from '../../codegen-base'; +import { snakeCase } from 'change-case'; +import { OperationObject, PathItemObject } from '../../types'; +import { OutputDir } from '../../output-dir'; + +export interface ElixirTeslaCodegenOptions { + outputDir: string; +} + +export default class ElixirTeslaCodegen extends CodegenBase { + readonly #outputDir: OutputDir; + + constructor(opts: ElixirTeslaCodegenOptions) { + super(opts); + this.#outputDir = new OutputDir(this.options.outputDir); + } + + #processOperation = async (args: { + operationMethod: string; + operationPath: string; + pathItem: PathItemObject; + operation: OperationObject; + }) => { + const functionName = snakeCase(args.operation.operationId); + await this.#outputDir.appendFile( + 'api.ex', + ` + def ${functionName}() + :ok + end + ` + ); + }; + + async generate() { + await this.#outputDir.resetDir(); + await this.#outputDir.createDir('components'); + await this.#outputDir.writeFile('api.ex', ''); + await forEachHttpOperation(this.document, this.#processOperation); + } +} diff --git a/packages/@straw-hat/openapi-web-sdk-generator/tests/jest/__snapshots__/elixir-tesla.test.ts.snap b/packages/@straw-hat/openapi-web-sdk-generator/tests/jest/__snapshots__/elixir-tesla.test.ts.snap new file mode 100644 index 00000000..3ff4ef24 --- /dev/null +++ b/packages/@straw-hat/openapi-web-sdk-generator/tests/jest/__snapshots__/elixir-tesla.test.ts.snap @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`elixir-tesla generator: api.ex 1`] = ` +" + def update_pet() + :ok + end + + def add_pet() + :ok + end + + def find_pets_by_status() + :ok + end + + def find_pets_by_tags() + :ok + end + + def get_pet_by_id() + :ok + end + + def update_pet_with_form() + :ok + end + + def delete_pet() + :ok + end + + def upload_file() + :ok + end + + def get_inventory() + :ok + end + + def place_order() + :ok + end + + def get_order_by_id() + :ok + end + + def delete_order() + :ok + end + + def create_user() + :ok + end + + def create_users_with_list_input() + :ok + end + + def login_user() + :ok + end + + def logout_user() + :ok + end + + def get_user_by_name() + :ok + end + + def update_user() + :ok + end + + def delete_user() + :ok + end + " +`; diff --git a/packages/@straw-hat/openapi-web-sdk-generator/tests/jest/elixir-tesla.test.ts b/packages/@straw-hat/openapi-web-sdk-generator/tests/jest/elixir-tesla.test.ts new file mode 100644 index 00000000..e3bdfc2a --- /dev/null +++ b/packages/@straw-hat/openapi-web-sdk-generator/tests/jest/elixir-tesla.test.ts @@ -0,0 +1,22 @@ +import { createTmpDir, readPetStoreSpec } from './support-files'; +import * as path from 'path'; +import ElixirTeslaCodegen from '../../src/generators/elixir-tesla'; + +test('elixir-tesla generator', async () => { + // GIVEN + const tmpDir = await createTmpDir(['elixir-tesla']); + const openapiDocument = await readPetStoreSpec(); + + const generator = new ElixirTeslaCodegen({ + outputDir: tmpDir.path, + }).setDocument(openapiDocument); + + // WHEN + await generator.generate(); + + // THEN + for await (const filePath of tmpDir.walkFiles('.')) { + const snapshotName = path.relative(tmpDir.path, filePath); + expect(await tmpDir.readFile(filePath)).toMatchSnapshot(snapshotName); + } +});