UNPKG

@infinite-debugger/swagger-to-ts

Version:

swagger-to-ts is a powerful library that allows you to generate TypeScript code from Swagger documentation or OpenAPI specifications. It simplifies the process of integrating API definitions into your TypeScript projects, saving you time and effort.

745 lines • 70.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateTypescriptAPI = exports.RequestOperationNameSourceValidationSchema = void 0; require("@infinite-debugger/rmk-js-extensions/String"); const fs_1 = require("fs"); const fs_extra_1 = require("fs-extra"); const pluralize_1 = __importDefault(require("pluralize")); const prettier_1 = __importDefault(require("prettier")); const walk_sync_1 = __importDefault(require("walk-sync")); const zod_1 = require("zod"); const config_1 = require("../config"); const models_1 = require("../models"); const Prettier_1 = require("../models/Prettier"); const TypescriptAPIGenerator_1 = require("../models/TypescriptAPIGenerator"); const APIFunctionsCodeGenerator_1 = require("./APIFunctionsCodeGenerator"); const ModelCodeGenerator_1 = require("./ModelCodeGenerator"); const ModelPrefixer_1 = require("./ModelPrefixer"); const PermissionsCodeGenerator_1 = require("./PermissionsCodeGenerator"); const SchemaGenerator_1 = require("./SchemaGenerator"); const TSEDControllersCodeGenerator_1 = require("./TSEDControllersCodeGenerator"); const Utils_1 = require("./Utils"); exports.RequestOperationNameSourceValidationSchema = zod_1.z.enum([ 'requestSummary', 'requestOperationId', ]); const generateTypescriptAPI = async ({ openAPISpecification: inputOpenAPISpecification, outputRootPath, outputInternalState = false, generateTsEDControllers = false, requestOperationNameSource = 'requestSummary', inferTypeFromValidationSchema, tsEDAuthenticateDecoratorImportPath, tsEDAuthorizeDecoratorImportPath, tsedControllerNamePrefix, tsedControllerNameSuffix, propagateRequestHeaders, scopeName, }) => { //#region Validate OpenAPI specification console.log('\nšŸ” Validate OpenAPI specification.'); const debugOutputFolderName = `__${config_1.pkg.name .replace(/\//g, ' ') .toSnakeCase()}_debug_output__/${new Date() .toISOString() .replace(/:/g, '_')}`; const debugOutputRootPath = `${outputRootPath}/${debugOutputFolderName}`; const validOpenAPISpecification = (() => { try { console.log(' -> šŸ” Validating OpenAPI specification...'); return models_1.OpenAPISpecificationValidationSchema.parse(inputOpenAPISpecification); } catch (err) { const errorFilePath = `${debugOutputRootPath}/openapi_spec_validation.error.json`; (0, fs_extra_1.ensureDirSync)(debugOutputRootPath); console.error(` -> šŸ˜ž Oops! Something went wrong while validating your OpenAPI specification. See ${errorFilePath} for details.`); (0, fs_extra_1.writeFileSync)(errorFilePath, JSON.stringify(err, null, 2)); process.exit(1); } })(); console.log(' -> šŸ‘ OpenAPI specification is valid.'); //#endregion //#region Initialization console.log('\nšŸš€ Generate Typescript API.'); const clientName = validOpenAPISpecification.info.title.toTitleCase(); const autogeneratedFileWarningComment = (0, Utils_1.getGeneratedFileWarningComment)(); const scopedModelPrefix = (() => { if (scopeName) { return scopeName.toPascalCase(); } })(); //#endregion //#region Prefix all models and model references const openAPISpecification = (() => { if (scopedModelPrefix) { return (0, ModelPrefixer_1.prefixModelsAndModelReferences)({ openAPISpecification: validOpenAPISpecification, prefix: scopedModelPrefix, }); } return validOpenAPISpecification; })(); //#endregion //#region Find all requests and group them by tag console.log(` -> Grouping API requests by tag...`); const requestGroupings = Object.keys(openAPISpecification.paths).reduce((accumulator, path) => { Object.keys(openAPISpecification.paths[path]).forEach((method) => { const request = openAPISpecification.paths[path][method]; //#region Generate anonymous schemas for all responses and request bodies that are not referenced by any other schema const { requestBody } = request; const operationName = (() => { if (requestOperationNameSource === 'requestSummary' && request.summary) { return request.summary; } if (request.operationId) { return request.operationId.split(/\W/g).reverse()[0]; } throw new Error(`Could not determine operation name. ${JSON.stringify(request, null, 2)}`); })().trim(); const camelCaseOperationName = operationName.toCamelCase(); const pascalCaseOperationName = operationName.toPascalCase(); if (requestBody) { const { content } = requestBody; if (content && content['application/json']?.schema && 'type' in content['application/json'].schema && content['application/json'].schema.type === 'object') { const schemaName = `${pascalCaseOperationName}RequestPayload`; openAPISpecification.components.schemas[schemaName] = content['application/json'].schema; content['application/json'].schema = { $ref: `#/components/schemas/${schemaName}`, }; } } //#endregion request.tags.forEach((tagName) => { if (!accumulator[tagName]) { const tag = openAPISpecification.tags.find(({ name }) => name === tagName); accumulator[tagName] = { name: tag?.name || tagName, description: tag?.description, permissons: tag?.['x-permissions'], imports: {}, requests: [], }; } const { requests } = accumulator[tagName]; const typePrefix = (() => { const match = /^\[(.+)\]\s/g.exec(tagName); if (match) { return match[1].toPascalCase(); } return scopedModelPrefix || ''; })(); requests.push({ ...request, method: method, requestPath: path, operationName: camelCaseOperationName, pascalCaseOperationName, requestPathName: operationName.replace(/\s/g, '_').toUpperCase() + `_ENDPOINT_PATH`, operationDescription: (() => { if (requestOperationNameSource === 'requestSummary' && request.summary) { return request.summary; } })(), requestBodySchemaName: (() => { if (request.requestBody?.content && request.requestBody.content['application/json']?.schema && '$ref' in request.requestBody.content['application/json'].schema) { const requestBodySchemaName = request.requestBody.content['application/json'].schema.$ref.replace('#/components/schemas/', ''); return requestBodySchemaName; } })(), ...(() => { if (request.requestBody?.content) { const { content } = request.requestBody; if (content['application/json']?.schema && 'type' in content['application/json'].schema && content['application/json'].schema.type === 'array') { const { schema } = content['application/json']; if (schema.items) { if ('$ref' in schema.items) { const requestBodySchemaName = schema.items.$ref.replace('#/components/schemas/', ''); return { requestBodyType: `${requestBodySchemaName}[]`, requestBodyTypeDependentSchemaName: requestBodySchemaName, }; } if ('type' in schema.items && schema.items.type && [ 'boolean', 'number', 'string', ].includes(schema.items.type)) { return { requestBodyType: `${schema.items.type}[]`, }; } } return { requestBodyType: 'any[]', }; } } })(), // TODO: Deal with oneof schema types successResponseSchemas: (() => { const successResponses = Object.entries(request.responses) .filter(([responseCode]) => responseCode.startsWith('2')) .reduce((accumulator, [httpStatusCode, response]) => { if (response.content) { Object.entries(response.content).forEach(([contentType, content]) => { accumulator.push([ httpStatusCode, { ...response, content: { [contentType]: content, }, }, ]); }); } return accumulator; }, []); if (successResponses.length > 0) { return successResponses .filter(([, response]) => { return response.content; }) .flatMap(([successResponse, response]) => { const httpStatusCode = +successResponse; const content = response.content; const description = response.description; return Object.entries(content).map(([contentType, content]) => { return { contentType, description, httpStatusCode, ...(() => { switch (contentType) { case 'image/png': case 'application/pdf': return { name: TypescriptAPIGenerator_1.BINARY_RESPONSE_TYPE_MODEL_NAME, }; } if ('$ref' in content.schema) { const successResponseSchemaName = content.schema.$ref.replace('#/components/schemas/', ''); return { name: successResponseSchemaName, }; } else if ('type' in content.schema) { switch (content.schema.type) { case 'boolean': case 'integer': case 'number': case 'string': return { type: (0, SchemaGenerator_1.getPrimitiveSchemaType)(content.schema), }; case 'array': if (content.schema.items) { if ('$ref' in content.schema.items) { const schemaReference = content.schema.items.$ref; const successResponseSchemaName = schemaReference.replace('#/components/schemas/', ''); return { name: successResponseSchemaName, isArray: true, }; } else if ('type' in content.schema.items) { return { type: (0, SchemaGenerator_1.getPrimitiveSchemaType)(content.schema.items), isArray: true, }; } } } } })(), }; }); }) .filter((schema) => schema); } })(), //#region Path parameters ...(() => { if (request.parameters) { const pathParameters = request.parameters.filter((parameter) => parameter.in === 'path'); if (pathParameters.length > 0) { return { pathParameters, }; } } })(), //#endregion //#region Header parameters ...(() => { if (request.parameters) { const headerParameters = request.parameters.filter((parameter) => { return (parameter.in === 'header' && !parameter.name.match(/authorization/gi)); }); if (headerParameters.length > 0) { const headerParametersModelReference = `${typePrefix}${pascalCaseOperationName}HeaderParams`; openAPISpecification.components.schemas[headerParametersModelReference] = (0, SchemaGenerator_1.generateSchemaFromRequestParameters)({ requestParameters: headerParameters, }); return { headerParameters, headerParametersModelReference, }; } } })(), //#endregion //#region Query parameters ...(() => { if (request.parameters) { const queryParameters = request.parameters.filter((parameter) => parameter.in === 'query'); if (queryParameters.length > 0) { const queryParametersModelReference = `${typePrefix}${pascalCaseOperationName}QueryParams`; openAPISpecification.components.schemas[queryParametersModelReference] = (0, SchemaGenerator_1.generateSchemaFromRequestParameters)({ requestParameters: queryParameters, }); return { queryParameters, queryParametersModelReference, }; } } })(), //#endregion }); }); }); return accumulator; }, {}); //#endregion //#region Group request tag groups by scope console.log(` -> Grouping request tag groups by scope...`); const requestTagGroupsByScope = Object.entries(requestGroupings).reduce((accumulator, [tag, requestGrouping]) => { const match = /^\[(.+)\]\s/g.exec(tag); const scopeName = match ? match[1] : 'Root'; if (!accumulator[scopeName]) { accumulator[scopeName] = {}; } accumulator[scopeName][tag.replace(/^\[(.+)\]\s*/g, '').trim()] = requestGrouping; return accumulator; }, {}); //#endregion //#region Generate scoped code const scopedCode = Object.entries(requestTagGroupsByScope).reduce((accumulator, [localScopeName, requestGroupings]) => { //#region Generate tag to entity mappings console.log(` -> Generating tag to entity mappings...`); const tagToEntityLabelMappings = [ ...Object.keys(requestGroupings), 'Utils', ].reduce((accumulator, tag) => { const labelPlural = tag; const labelSingular = pluralize_1.default.singular(tag); accumulator[tag] = { 'Entities Label': labelPlural, 'Entity Label': labelSingular, 'entities label': labelPlural.toLowerCase(), 'entity label': labelSingular.toLowerCase(), PascalCaseEntities: labelPlural.toPascalCase(), PascalCaseEntity: labelSingular.toPascalCase(), camelCaseEntities: labelPlural.toCamelCase(), camelCaseEntity: labelSingular.toCamelCase(), UPPER_CASE_ENTITIES: labelPlural.replace(/\s/g, '_').toUpperCase(), UPPER_CASE_ENTITY: labelSingular.replace(/\s/g, '_').toUpperCase(), 'kebab-case-entities': labelPlural.toKebabCase(), 'kebab-case-entity': labelSingular.toKebabCase(), }; return accumulator; }, {}); //#endregion //#region Generate model mappings. console.log(` -> Generating model mappings...`); const modelMappings = (0, ModelCodeGenerator_1.generateModelMappings)({ requestGroupings, openAPISpecification: openAPISpecification, generateTsEDControllers, inferTypeFromValidationSchema, }); const { schemaToEntityMappings, modelsToValidationSchemaMappings } = modelMappings; //#endregion //#region Generate API functions code configuration console.log(` -> Generating API functions code configuration...`); const apiFunctionsCodeConfiguration = (0, APIFunctionsCodeGenerator_1.getAPIFunctionsCodeConfiguration)({ requestGroupings, modelsToValidationSchemaMappings, schemaToEntityMappings, tagToEntityLabelMappings, localScopeName, }); //#endregion //#region Generate TSED controllers code configuration const tsedControllersCodeConfiguration = (() => { if (generateTsEDControllers) { return (0, TSEDControllersCodeGenerator_1.getTSEDControllersCodeConfiguration)({ requestGroupings, schemaToEntityMappings, tagToEntityLabelMappings, authenticateDecoratorImportPath: tsEDAuthenticateDecoratorImportPath, authorizeDecoratorImportPath: tsEDAuthorizeDecoratorImportPath, tsedControllerNamePrefix: (() => { if (scopeName) { return `[${scopeName}] `; } return tsedControllerNamePrefix; })(), tsedControllerNameSuffix, propagateRequestHeaders, openAPISpecification, }); } })(); //#endregion //#region Generate permissions code configuration const permissionsCodeConfiguration = (0, PermissionsCodeGenerator_1.getPermissionsCodeConfiguration)({ requestGroupings, scopeName, }); //#endregion accumulator[localScopeName] = { tagToEntityLabelMappings, modelMappings, apiFunctionsCodeConfiguration, permissionsCodeConfiguration, tsedControllersCodeConfiguration, requestGroupings, }; return accumulator; }, {}); //#endregion //#region Clean up output folder console.log(` -> Cleaning up output folder...`); if ((0, fs_1.existsSync)(outputRootPath)) { (0, walk_sync_1.default)(outputRootPath, { includeBasePath: true, directories: false, }).forEach((filePath) => { const fileContents = (0, fs_extra_1.readFileSync)(filePath, 'utf8'); if (fileContents.match(`automatically generated by the ${config_1.pkg.name} library`)) { console.log(` -> Removing file: ${filePath}`); (0, fs_extra_1.unlinkSync)(filePath); } }); (0, Utils_1.cleanEmptyFoldersRecursively)(outputRootPath); } //#endregion //#region Write debug output files if (outputInternalState) { console.log(` -> Writing debug output files...`); (0, fs_extra_1.ensureDirSync)(debugOutputRootPath); (0, fs_extra_1.writeFileSync)(`${debugOutputRootPath}/api_request_grouped_by_tag.debug.json`, JSON.stringify(requestGroupings, null, 2)); (0, fs_extra_1.writeFileSync)(`${debugOutputRootPath}/api_request_groups_grouped_by_scope.debug.json`, JSON.stringify(requestTagGroupsByScope, null, 2)); } //#endregion //#region Write scoped files Object.entries(scopedCode).forEach(([scopeName, scopedCodeConfiguration]) => { const { apiFunctionsCodeConfiguration, permissionsCodeConfiguration, modelMappings, tagToEntityLabelMappings, tsedControllersCodeConfiguration, requestGroupings, } = scopedCodeConfiguration; const { models, schemaEntityReferences, schemaToEntityMappings, entitySchemaGroups, modelsToValidationSchemaMappings, } = modelMappings; //#region Write debug output files if (outputInternalState) { const scopedDebugOutputRootPath = `${debugOutputRootPath}/${scopeName}`; (0, fs_extra_1.ensureDirSync)(scopedDebugOutputRootPath); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/tag_to_entity_mappings.debug.json`, JSON.stringify(tagToEntityLabelMappings, null, 2)); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/schema_references.debug.json`, JSON.stringify(schemaEntityReferences, null, 2)); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/schema_to_entity_mappings.debug.json`, JSON.stringify(schemaToEntityMappings, null, 2)); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/schemas_grouped_by_tag.debug.json`, JSON.stringify(entitySchemaGroups, null, 2)); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/validation_schemas.debug.json`, JSON.stringify(models, null, 2)); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/models_to_validation_schema_mappings.debug.json`, JSON.stringify(modelsToValidationSchemaMappings, null, 2)); (0, fs_extra_1.writeFileSync)(`${scopedDebugOutputRootPath}/api_functions_code_configuration.debug.json`, JSON.stringify(apiFunctionsCodeConfiguration, null, 2)); } //#endregion const pascalCaseScopeName = scopeName.toPascalCase(); const isRootScope = pascalCaseScopeName === 'Root'; const scopedOutputRootPath = isRootScope ? outputRootPath : `${outputRootPath}/proxies/${pascalCaseScopeName}`; //#region Write model files console.log(` -> Writing model files...`); const modelsOutputFilePath = `${scopedOutputRootPath}/models`; (0, fs_extra_1.ensureDirSync)(modelsOutputFilePath); Object.keys(models).forEach((tag) => { const { PascalCaseEntities } = tagToEntityLabelMappings[tag]; const modelFileName = `${PascalCaseEntities}.ts`; const entityModelsOutputFilePath = `${modelsOutputFilePath}/${modelFileName}`; if (!(0, fs_1.existsSync)(entityModelsOutputFilePath)) { const entityModelsOutputCode = Object.values(models[tag].models) .map((model) => model.zodValidationSchemaCode) .join('\n\n'); (0, fs_extra_1.writeFileSync)(entityModelsOutputFilePath, prettier_1.default.format([ autogeneratedFileWarningComment, ...(0, Utils_1.getImportsCode)({ imports: models[tag].imports, }), entityModelsOutputCode, ].join('\n\n'), { filepath: entityModelsOutputFilePath, ...Prettier_1.prettierConfig, })); } }); const modelsIndexOutputFilePath = `${modelsOutputFilePath}/index.ts`; if (!(0, fs_1.existsSync)(modelsIndexOutputFilePath)) { (0, fs_extra_1.writeFileSync)(modelsIndexOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n` + Object.keys(models) .map((tag) => { return `export * from './${tagToEntityLabelMappings[tag].PascalCaseEntities}';`; }) .join('\n'), { filepath: modelsIndexOutputFilePath, ...Prettier_1.prettierConfig, })); } //#endregion //#region Write API files console.log(` -> Writing API files...`); const apiOutputFilePath = `${scopedOutputRootPath}/api`; (0, fs_extra_1.ensureDirSync)(apiOutputFilePath); Object.keys(apiFunctionsCodeConfiguration).forEach((tag) => { const { PascalCaseEntities } = tagToEntityLabelMappings[tag]; const apiFileName = `${PascalCaseEntities}.ts`; const entityAPIOutputFilePath = `${apiOutputFilePath}/${apiFileName}`; if (!(0, fs_1.existsSync)(entityAPIOutputFilePath)) { const { outputCode, requestPathsOutputCode, imports, dataKeyVariableName, } = apiFunctionsCodeConfiguration[tag]; if (!isRootScope) { const adapterImports = imports['./Adapter']; imports['../../../api/Adapter'] = adapterImports; delete imports['./Adapter']; } (0, fs_extra_1.writeFileSync)(entityAPIOutputFilePath, prettier_1.default.format([ autogeneratedFileWarningComment, ...(0, Utils_1.getImportsCode)({ imports, }), ` //#region Endpoint Paths ${requestPathsOutputCode} //#endregion `.trimIndent(), ` //#region Data Keys export const ${dataKeyVariableName} = '${scopeName !== 'Root' ? scopeName.toPascalCase() : ''}${tagToEntityLabelMappings[tag].PascalCaseEntities}'; //#endregion `.trimIndent(), ` //#region API ${outputCode} //#endregion `.trimIndent(), ].join('\n\n'), { filepath: entityAPIOutputFilePath, ...Prettier_1.prettierConfig, })); } }); if (isRootScope) { const apiAdapterOutputFilePath = `${apiOutputFilePath}/Adapter.ts`; if (!(0, fs_1.existsSync)(apiAdapterOutputFilePath)) { (0, fs_extra_1.writeFileSync)(apiAdapterOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n${(0, APIFunctionsCodeGenerator_1.getAPIAdapterCode)()}`, { filepath: apiAdapterOutputFilePath, ...Prettier_1.prettierConfig, })); } } const apiIndexOutputFilePath = `${apiOutputFilePath}/index.ts`; const exportableFileNames = Object.keys(requestGroupings).map((tag) => { return tagToEntityLabelMappings[tag].PascalCaseEntities; }); if (isRootScope) { exportableFileNames.push('Adapter'); } if (!(0, fs_1.existsSync)(apiIndexOutputFilePath)) { (0, fs_extra_1.writeFileSync)(apiIndexOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n` + exportableFileNames .map((PascalCaseEntities) => { return `export * from './${PascalCaseEntities}';`; }) .join('\n'), { filepath: apiIndexOutputFilePath, ...Prettier_1.prettierConfig, })); } //#endregion //#region Write Permissions files if (generateTsEDControllers) { console.log(` -> Writing Permissions files...`); const permissionsOutputFilePath = `${scopedOutputRootPath}/permissions`; const exportableFileNames = Object.entries(permissionsCodeConfiguration) .filter(([, { outputCode }]) => { return outputCode.length > 0; }) .map(([tag]) => { return tagToEntityLabelMappings[tag].PascalCaseEntities; }); if (exportableFileNames.length > 0) { (0, fs_extra_1.ensureDirSync)(permissionsOutputFilePath); } Object.entries(permissionsCodeConfiguration).forEach(([tag, { outputCode }]) => { const { PascalCaseEntities } = tagToEntityLabelMappings[tag]; const permissionsFileName = `${PascalCaseEntities}.ts`; const entityPermissionsOutputFilePath = `${permissionsOutputFilePath}/${permissionsFileName}`; if (outputCode.length > 0 && !(0, fs_1.existsSync)(entityPermissionsOutputFilePath)) { (0, fs_extra_1.writeFileSync)(entityPermissionsOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n${outputCode}`, { filepath: entityPermissionsOutputFilePath, ...Prettier_1.prettierConfig, })); } }); const permissionsIndexOutputFilePath = `${permissionsOutputFilePath}/index.ts`; if (!(0, fs_1.existsSync)(permissionsIndexOutputFilePath) && exportableFileNames.length > 0) { const permissionImports = {}; const permissionsExportsCode = exportableFileNames .map((PascalCaseEntities) => { return `export * from './${PascalCaseEntities}';`; }) .join('\n'); const allPermissionsExportBodyCode = exportableFileNames .map((PascalCaseEntities) => { (0, Utils_1.addModuleImport)({ imports: permissionImports, importFilePath: `./${PascalCaseEntities}`, importName: `all${PascalCaseEntities}Permissions`, }); return `...all${PascalCaseEntities}Permissions,`; }) .join('\n'); (0, fs_extra_1.writeFileSync)(permissionsIndexOutputFilePath, prettier_1.default.format(` ${autogeneratedFileWarningComment}\n\n ${(0, Utils_1.getImportsCode)({ imports: permissionImports }).join('\n')}\n ${permissionsExportsCode}\n //#region All Permissions export const allPermissions = [ ${allPermissionsExportBodyCode} ]; //#endregion `.trimIndent(), { filepath: permissionsIndexOutputFilePath, ...Prettier_1.prettierConfig, })); } } //#endregion //#region Write TSED controller files if (generateTsEDControllers && tsedControllersCodeConfiguration) { console.log(` -> Writing TSED controller files...`); const tsedControllersOutputFilePath = `${scopedOutputRootPath}/controllers`; (0, fs_extra_1.ensureDirSync)(tsedControllersOutputFilePath); Object.keys(tsedControllersCodeConfiguration).forEach((tag) => { const { PascalCaseEntity } = tagToEntityLabelMappings[tag]; const controllerFileName = `${PascalCaseEntity}Controller.ts`; const controllerOutputFilePath = `${tsedControllersOutputFilePath}/${controllerFileName}`; if (!(0, fs_1.existsSync)(controllerOutputFilePath)) { const { outputCode, imports } = tsedControllersCodeConfiguration[tag]; (0, fs_extra_1.writeFileSync)(controllerOutputFilePath, prettier_1.default.format([ autogeneratedFileWarningComment, ...(0, Utils_1.getImportsCode)({ imports, }), outputCode, ].join('\n\n'), { filepath: controllerOutputFilePath, ...Prettier_1.prettierConfig, })); } }); const tsedControllersIndexOutputFilePath = `${tsedControllersOutputFilePath}/index.ts`; if (!(0, fs_1.existsSync)(tsedControllersIndexOutputFilePath)) { (0, fs_extra_1.writeFileSync)(tsedControllersIndexOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n` + Object.keys(requestGroupings) .map((tag) => { return tagToEntityLabelMappings[tag].PascalCaseEntity; }) .map((PascalCaseEntity) => { return `export * from './${PascalCaseEntity}Controller';`; }) .join('\n'), { filepath: tsedControllersIndexOutputFilePath, ...Prettier_1.prettierConfig, })); } } //#endregion //#region Write index file if (!isRootScope) { console.log(` -> Writing ${scopeName} index file...`); const indexOutputFilePath = `${scopedOutputRootPath}/index.ts`; if (!(0, fs_1.existsSync)(indexOutputFilePath)) { const apiFunctionsCode = Object.values(apiFunctionsCodeConfiguration) .reduce((accumulator, { exports }) => { accumulator.push(...exports); return accumulator; }, []) .join(',\n'); const indexOutputCode = [ `${autogeneratedFileWarningComment}`, `import {${apiFunctionsCode}} from './api';`, ` export const ${pascalCaseScopeName} = { ${apiFunctionsCode} }; `.trimIndent(), ]; (0, fs_extra_1.writeFileSync)(indexOutputFilePath, prettier_1.default.format(indexOutputCode.join('\n\n'), { filepath: indexOutputFilePath, ...Prettier_1.prettierConfig, })); } } //#endregion }); //#endregion //#region Write proxies index file const nonRootScopes = Object.keys(scopedCode) .filter((scopeName) => { return scopeName !== 'Root'; }) .map((scopeName) => { return scopeName.toPascalCase(); }); if (nonRootScopes.length > 0) { const proxiesIndexOutputFilePath = `${outputRootPath}/proxies/index.ts`; if (!(0, fs_1.existsSync)(proxiesIndexOutputFilePath)) { (0, fs_extra_1.writeFileSync)(proxiesIndexOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n` + nonRootScopes .map((PascalCaseScopeName) => { return `export * from './${PascalCaseScopeName}';`; }) .join('\n'), { filepath: proxiesIndexOutputFilePath, ...Prettier_1.prettierConfig, })); } } //#endregion //#region Write index file console.log(`\nšŸ Finish`); console.log(` -> Writing index file...`); const indexOutputFilePath = `${outputRootPath}/index.ts`; if (!(0, fs_1.existsSync)(indexOutputFilePath)) { (0, fs_extra_1.writeFileSync)(indexOutputFilePath, prettier_1.default.format(`${autogeneratedFileWarningComment}\n\n` + ['api', 'models', 'proxies', 'controllers'] .filter((folderName) => { return (0, fs_1.existsSync)(`${outputRootPath}/${folderName}`); }) .map((folderName) => { return `export * from './${folderName}';`; }) .join('\n'), { filepath: indexOutputFilePath, ...Prettier_1.prettierConfig, })); } //#endregion console.log(` -> āœ… Success. ${clientName} typescript client code has been generated in the following directory ${outputRootPath}`); }; exports.generateTypescriptAPI = generateTypescriptAPI; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHlwZXNjcmlwdEFQSUdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvVHlwZXNjcmlwdEFQSUdlbmVyYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSx1REFBcUQ7QUFFckQsMkJBQWdDO0FBRWhDLHVDQUtrQjtBQUNsQiwwREFBa0M7QUFDbEMsd0RBQWdDO0FBQ2hDLDBEQUFpQztBQUNqQyw2QkFBd0I7QUFFeEIsc0NBQWdDO0FBQ2hDLHNDQUltQjtBQUVuQixpREFBb0Q7QUFDcEQsNkVBVTBDO0FBQzFDLDJFQUdxQztBQUNyQyw2REFHOEI7QUFDOUIsbURBQWlFO0FBQ2pFLHlFQUE2RTtBQUM3RSx1REFHMkI7QUFDM0IsaUZBR3dDO0FBQ3hDLG1DQUtpQjtBQUVKLFFBQUEsMENBQTBDLEdBQUcsT0FBQyxDQUFDLElBQUksQ0FBQztJQUMvRCxnQkFBZ0I7SUFDaEIsb0JBQW9CO0NBQ1osQ0FBQyxDQUFDO0FBMERMLE1BQU0scUJBQXFCLEdBQUcsS0FBSyxFQUFFLEVBQzFDLG9CQUFvQixFQUFFLHlCQUF5QixFQUMvQyxjQUFjLEVBQ2QsbUJBQW1CLEdBQUcsS0FBSyxFQUMzQix1QkFBdUIsR0FBRyxLQUFLLEVBQy9CLDBCQUEwQixHQUFHLGdCQUFnQixFQUM3Qyw2QkFBNkIsRUFDN0IsbUNBQW1DLEVBQ25DLGdDQUFnQyxFQUNoQyx3QkFBd0IsRUFDeEIsd0JBQXdCLEVBQ3hCLHVCQUF1QixFQUN2QixTQUFTLEdBQ29CLEVBQUUsRUFBRTtJQUNqQyx3Q0FBd0M7SUFDeEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO0lBQ3BELE1BQU0scUJBQXFCLEdBQUcsS0FBSyxZQUFHLENBQUMsSUFBSTtTQUN4QyxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQztTQUNuQixXQUFXLEVBQUUsbUJBQW1CLElBQUksSUFBSSxFQUFFO1NBQzFDLFdBQVcsRUFBRTtTQUNi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