fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #108 from nicolas-chaulet/fix/config-export-schemas

fix(config): export schemas by default

authored by

Lubos and committed by
GitHub
b553a125 e3fdbf20

+315 -217
+23 -27
README.md
··· 73 73 74 74 ## Configuration 75 75 76 - <!-- `openapi-ts` supports loading configuration from a file inside your project root directory. You can either create a `openapi-ts.config.js` file --> 77 - 78 - `openapi-ts` supports loading configuration from a file inside your project root directory. You just need to create a `openapi-ts.config.js` file 76 + `openapi-ts` supports loading configuration from a file inside your project root directory. You can either create a `openapi-ts.config.cjs` file 79 77 80 78 ```js 81 79 /** @type {import('@nicolas-chaulet/openapi-typescript-codegen').UserConfig} */ 82 - export default { 80 + module.exports = { 83 81 input: 'path/to/openapi.json', 84 82 output: 'src/client', 85 83 } 86 84 ``` 87 85 88 - <!-- or `openapi-ts.config.ts` 86 + or `openapi-ts.config.mjs` 89 87 90 - ```ts 91 - import { defineConfig } from '@nicolas-chaulet/openapi-typescript-codegen'; 92 - 93 - export default defineConfig({ 88 + ```js 89 + /** @type {import('@nicolas-chaulet/openapi-typescript-codegen').UserConfig} */ 90 + export default { 94 91 input: 'path/to/openapi.json', 95 92 output: 'src/client', 96 - }) 97 - ``` --> 93 + } 94 + ``` 95 + 96 + Alternatively, you can use `openapi-ts.config.js` and configure the export statement depending on your project setup. 98 97 99 98 ### Formatting 100 99 101 100 By default, `openapi-ts` will automatically format your client according to your project configuration. To disable automatic formatting, set `format` to false 102 101 103 - ```ts 104 - import { defineConfig } from '@nicolas-chaulet/openapi-typescript-codegen'; 105 - 106 - export default defineConfig({ 102 + ```js 103 + /** @type {import('@nicolas-chaulet/openapi-typescript-codegen').UserConfig} */ 104 + export default { 107 105 format: false, 108 106 input: 'path/to/openapi.json', 109 107 output: 'src/client', 110 - }) 108 + } 111 109 ``` 112 110 113 111 You can also prevent your client from being processed by formatters by adding your output path to the tool's ignore file (e.g. `.prettierignore`). ··· 116 114 117 115 For performance reasons, `openapi-ts` does not automatically lint your client. To enable this feature, set `lint` to true 118 116 119 - ```ts 120 - import { defineConfig } from '@nicolas-chaulet/openapi-typescript-codegen'; 121 - 122 - export default defineConfig({ 117 + ```js 118 + /** @type {import('@nicolas-chaulet/openapi-typescript-codegen').UserConfig} */ 119 + export default { 123 120 input: 'path/to/openapi.json', 124 121 lint: true, 125 122 output: 'src/client', 126 - }) 123 + } 127 124 ``` 128 125 129 126 You can also prevent your client from being processed by linters by adding your output path to the tool's ignore file (e.g. `.eslintignore`). ··· 132 129 133 130 We do not generate TypeScript [enums](https://www.typescriptlang.org/docs/handbook/enums.html) because they are not standard JavaScript and pose [typing challenges](https://dev.to/ivanzm123/dont-use-enums-in-typescript-they-are-very-dangerous-57bh). If you want to iterate through possible field values without manually typing arrays, you can export enums by running 134 131 135 - ```ts 136 - import { defineConfig } from '@nicolas-chaulet/openapi-typescript-codegen'; 137 - 138 - export default defineConfig({ 132 + ```js 133 + /** @type {import('@nicolas-chaulet/openapi-typescript-codegen').UserConfig} */ 134 + export default { 139 135 enums: true, 140 136 input: 'path/to/openapi.json', 141 137 output: 'src/client', 142 - }) 138 + } 143 139 ``` 144 140 145 141 This will export your enums as plain JavaScript objects. For example, `Foo` will generate the following ··· 170 166 --exportCore <value> Write core files to disk (default: true) 171 167 --exportServices <value> Write services to disk [true, false, regexp] (default: true) 172 168 --exportModels <value> Write models to disk [true, false, regexp] (default: true) 173 - --exportSchemas <value> Write schemas to disk (default: false) 169 + --exportSchemas <value> Write schemas to disk (default: true) 174 170 --format Process output folder with formatter? 175 171 --no-format Disable processing output folder with formatter 176 172 --lint Process output folder with linter?
+3 -1
rollup.config.ts
··· 42 42 escapeDescription: true, 43 43 escapeNewline: true, 44 44 exactArray: true, 45 + exportsModels: true, 46 + exportsSchemas: true, 47 + exportsServices: true, 45 48 ifdef: true, 46 49 ifOperationDataOptional: true, 47 50 intersection: true, 48 51 modelImports: true, 49 - modelsExports: true, 50 52 modelUnionType: true, 51 53 nameOperationDataType: true, 52 54 notEquals: true,
+17 -13
src/index.ts
··· 10 10 import type { Config, UserConfig } from './types/config'; 11 11 import { getOpenApiSpec } from './utils/getOpenApiSpec'; 12 12 import { registerHandlebarTemplates } from './utils/handlebars'; 13 + import { isSubDirectory } from './utils/isSubdirectory'; 13 14 import { postProcessClient } from './utils/postProcessClient'; 14 15 import { writeClient } from './utils/write/client'; 15 16 16 17 type Dependencies = Record<string, unknown>; 17 18 18 - // const configFiles = ['openapi-ts.config.js', 'openapi-ts.config.ts']; 19 - // add support for `openapi-ts.config.ts` 20 - const configFiles = ['openapi-ts.config.js']; 19 + // TODO: add support for `openapi-ts.config.ts` 20 + const configFiles = ['openapi-ts.config.js', 'openapi-ts.config.cjs', 'openapi-ts.config.mjs']; 21 21 22 22 export const parseOpenApiSpecification = (openApi: Awaited<ReturnType<typeof getOpenApiSpec>>, config: Config) => { 23 23 if ('openapi' in openApi) { ··· 93 93 enums = false, 94 94 exportCore = true, 95 95 exportModels = true, 96 - exportSchemas = false, 96 + exportSchemas = true, 97 97 exportServices = true, 98 98 format = true, 99 99 input, 100 100 lint = false, 101 101 name, 102 102 operationId = true, 103 - output, 104 103 postfixModels = '', 105 104 postfixServices = 'Service', 106 105 request, ··· 110 109 write = true, 111 110 } = userConfig; 112 111 112 + if (!input) { 113 + throw new Error('🚫 input not provided - provide path to OpenAPI specification'); 114 + } 115 + 116 + if (!userConfig.output) { 117 + throw new Error('🚫 output not provided - provide path where we should generate your client'); 118 + } 119 + 120 + if (!isSubDirectory(process.cwd(), userConfig.output)) { 121 + throw new Error('🚫 output must be within the current working directory'); 122 + } 123 + 113 124 const client = userConfig.client || inferClient(dependencies); 125 + const output = path.resolve(process.cwd(), userConfig.output); 114 126 115 127 const config: Config = { 116 128 base, ··· 134 146 useOptions, 135 147 write, 136 148 }; 137 - 138 - if (!input) { 139 - throw new Error('🚫 input not provided - provide path to OpenAPI specification'); 140 - } 141 - 142 - if (!output) { 143 - throw new Error('🚫 output not provided - provide path where we should generate your client'); 144 - } 145 149 146 150 return config; 147 151 };
+3 -19
src/templates/index.hbs
··· 12 12 export type { OpenAPIConfig } from './core/OpenAPI'; 13 13 {{/if}} 14 14 15 - {{#if @root.$config.exportModels}} 16 - {{#if models}} 17 - {{{modelsExports @root.$config models './models/'}}} 18 - {{/if}} 19 - {{/if}} 15 + {{{exportsModels}}} 20 16 21 - {{#if @root.$config.exportSchemas}} 22 - {{#if models}} 23 - {{#each models}} 24 - export { ${{{name}}} } from './schemas/${{{name}}}'; 25 - {{/each}} 26 - {{/if}} 27 - {{/if}} 17 + {{{exportsSchemas}}} 28 18 29 - {{#if @root.$config.exportServices}} 30 - {{#if services}} 31 - {{#each services}} 32 - export { {{{name}}}{{{@root.$config.postfixServices}}} } from './services/{{{name}}}{{{@root.$config.postfixServices}}}'; 33 - {{/each}} 34 - {{/if}} 35 - {{/if}} 19 + {{{exportsServices}}}
+6 -6
src/types/config.ts
··· 9 9 */ 10 10 client?: 'angular' | 'axios' | 'fetch' | 'node' | 'xhr'; 11 11 /** 12 - * Generate JavaScript objects from enum definitions 12 + * Generate JavaScript objects from enum definitions? 13 13 * @default false 14 14 */ 15 15 enums?: boolean; 16 16 /** 17 - * Generate core client classes 17 + * Generate core client classes? 18 18 * @default true 19 19 */ 20 20 exportCore?: boolean; 21 21 /** 22 - * Generate models 22 + * Generate models? 23 23 * @default true 24 24 */ 25 25 exportModels?: boolean | string; 26 26 /** 27 - * Generate schemas 28 - * @default false 27 + * Generate schemas? 28 + * @default true 29 29 */ 30 30 exportSchemas?: boolean; 31 31 /** 32 - * Generate services 32 + * Generate services? 33 33 * @default true 34 34 */ 35 35 exportServices?: boolean | string;
+12 -8
src/utils/__tests__/isSubdirectory.spec.ts
··· 5 5 import { isSubDirectory } from '../isSubdirectory'; 6 6 7 7 describe('isSubDirectory', () => { 8 - it('should return correct result', () => { 9 - expect(isSubDirectory(path.resolve('/'), path.resolve('/'))).toBeFalsy(); 10 - expect(isSubDirectory(path.resolve('.'), path.resolve('.'))).toBeFalsy(); 11 - expect(isSubDirectory(path.resolve('./project'), path.resolve('./project'))).toBeFalsy(); 12 - expect(isSubDirectory(path.resolve('./project'), path.resolve('../'))).toBeFalsy(); 13 - expect(isSubDirectory(path.resolve('./project'), path.resolve('../../'))).toBeFalsy(); 14 - expect(isSubDirectory(path.resolve('./'), path.resolve('./output'))).toBeTruthy(); 15 - expect(isSubDirectory(path.resolve('./'), path.resolve('../output'))).toBeTruthy(); 8 + it.each([ 9 + ['/', '/', false], 10 + ['.', '.', false], 11 + ['./project', './project', false], 12 + ['./project', '../', false], 13 + ['./project', '../../', false], 14 + ['./', './output', true], 15 + ['./', '../output', false], 16 + ['./', '../../../../../output', false], 17 + ])('isSubDirectory(%s, %s) -> %s', (a, b, expected) => { 18 + const result = isSubDirectory(path.resolve(a), path.resolve(b)); 19 + expect(result).toBe(expected); 16 20 }); 17 21 });
+4 -5
src/utils/getHttpRequestName.ts
··· 1 - import type { UserConfig } from '../types/config'; 1 + import type { Config } from '../types/config'; 2 2 3 3 /** 4 4 * Generate the HttpRequest filename based on the selected client 5 5 * @param client The selected HTTP client (fetch, xhr, node or axios) 6 6 */ 7 - export const getHttpRequestName = (client: UserConfig['client']): string => { 7 + export const getHttpRequestName = (client: Config['client']): string => { 8 8 switch (client) { 9 9 case 'angular': 10 10 return 'AngularHttpRequest'; 11 11 case 'axios': 12 12 return 'AxiosHttpRequest'; 13 + case 'fetch': 14 + return 'FetchHttpRequest'; 13 15 case 'node': 14 16 return 'NodeHttpRequest'; 15 17 case 'xhr': 16 18 return 'XHRHttpRequest'; 17 - case 'fetch': 18 - default: 19 - return 'FetchHttpRequest'; 20 19 } 21 20 };
+45 -7
src/utils/handlebars.ts
··· 87 87 import partialTypeReference from '../templates/partials/typeReference.hbs'; 88 88 import partialTypeUnion from '../templates/partials/typeUnion.hbs'; 89 89 import type { Client, Model, OperationParameter, Service } from '../types/client'; 90 - import type { Config, UserConfig } from '../types/config'; 90 + import type { Config } from '../types/config'; 91 91 import { enumKey, enumName, enumUnionType, enumValue } from './enum'; 92 92 import { escapeName } from './escapeName'; 93 93 import { sortByName } from './sort'; ··· 99 99 .replace(/\/\*/g, '*') 100 100 .replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`); 101 101 102 - const modelsExports = (config: UserConfig, models: Model[], path: string) => { 103 - const output = models.map(model => { 102 + const exportsModels = (config: Config, client: Client) => { 103 + if (!config.exportModels) { 104 + return ''; 105 + } 106 + const path = './models/'; 107 + const output = client.models.map(model => { 104 108 const importedModel = config.postfixModels 105 109 ? `${model.name} as ${model.name + config.postfixModels}` 106 110 : model.name; ··· 116 120 return output.join('\n'); 117 121 }; 118 122 119 - const modelImports = (model: Model | Service, path: string) => { 120 - if (!model.imports.length) { 123 + const exportsSchemas = (config: Config, client: Client) => { 124 + if (!config.exportSchemas) { 121 125 return ''; 122 126 } 127 + const path = './schemas/'; 128 + const output = client.models.map(model => { 129 + const name = `$${model.name}`; 130 + const result = [`export { ${name} } from '${path + name}';`]; 131 + return result.join('\n'); 132 + }); 133 + return output.join('\n'); 134 + }; 135 + 136 + const exportsServices = (config: Config, client: Client) => { 137 + if (!config.exportServices) { 138 + return ''; 139 + } 140 + const path = './services/'; 141 + const output = client.services.map(service => { 142 + const name = service.name + config.postfixServices; 143 + const result = [`export { ${name} } from '${path + name}';`]; 144 + return result.join('\n'); 145 + }); 146 + return output.join('\n'); 147 + }; 148 + 149 + const modelImports = (model: Model | Service, path: string) => { 123 150 const output = model.imports.map(item => `import type { ${item} } from '${path + item}';`); 124 151 return output.join('\n'); 125 152 }; ··· 210 237 return options.inverse(this); 211 238 }); 212 239 240 + Handlebars.registerHelper('exportsModels', function () { 241 + return exportsModels(config, client); 242 + }); 243 + 244 + Handlebars.registerHelper('exportsSchemas', function () { 245 + return exportsSchemas(config, client); 246 + }); 247 + 248 + Handlebars.registerHelper('exportsServices', function () { 249 + return exportsServices(config, client); 250 + }); 251 + 213 252 Handlebars.registerHelper('ifdef', function (this: unknown, ...args): string { 214 253 const options = args.pop(); 215 254 if (!args.every(value => !value)) { ··· 240 279 ); 241 280 242 281 Handlebars.registerHelper('modelImports', modelImports); 243 - Handlebars.registerHelper('modelsExports', modelsExports); 244 282 245 283 Handlebars.registerHelper( 246 284 'modelUnionType', ··· 269 307 270 308 Handlebars.registerHelper( 271 309 'useDateType', 272 - function (this: unknown, config: UserConfig, format: string | undefined, options: Handlebars.HelperOptions) { 310 + function (this: unknown, config: Config, format: string | undefined, options: Handlebars.HelperOptions) { 273 311 return config.useDateType && format === 'date-time' ? options.fn(this) : options.inverse(this); 274 312 } 275 313 );
+4 -1
src/utils/isSubdirectory.ts
··· 1 1 import path from 'node:path'; 2 2 3 - export const isSubDirectory = (parent: string, child: string) => path.relative(child, parent).startsWith('..'); 3 + export const isSubDirectory = (parent: string, child: string) => { 4 + const relative = path.relative(parent, child); 5 + return Boolean(relative) && !relative.startsWith('..') && !path.isAbsolute(relative); 6 + };
+2 -2
src/utils/operation.ts
··· 1 1 import camelCase from 'camelcase'; 2 2 3 - import type { UserConfig } from '../types/config'; 3 + import type { Config } from '../types/config'; 4 4 import sanitizeOperationName from './sanitizeOperationName'; 5 5 6 6 /** ··· 11 11 export const getOperationName = ( 12 12 url: string, 13 13 method: string, 14 - options: Pick<Required<UserConfig>, 'operationId'>, 14 + options: Pick<Config, 'operationId'>, 15 15 operationId?: string 16 16 ): string => { 17 17 if (options.operationId && operationId) {
+14
src/utils/write/__tests__/class.spec.ts
··· 39 39 await writeClientClass(client, templates, './dist', { 40 40 client: 'fetch', 41 41 enums: true, 42 + exportCore: true, 43 + exportModels: true, 44 + exportSchemas: true, 45 + exportServices: true, 46 + format: false, 47 + input: '', 48 + lint: false, 42 49 name: 'AppClient', 50 + operationId: true, 51 + output: '', 52 + postfixModels: '', 43 53 postfixServices: '', 54 + serviceResponse: 'body', 55 + useDateType: false, 56 + useOptions: true, 57 + write: true, 44 58 }); 45 59 46 60 expect(writeFileSync).toHaveBeenCalled();
+42
src/utils/write/__tests__/core.spec.ts
··· 43 43 44 44 const config: Parameters<typeof writeClientCore>[3] = { 45 45 client: 'fetch', 46 + enums: true, 47 + exportCore: true, 48 + exportModels: true, 49 + exportSchemas: true, 50 + exportServices: true, 51 + format: false, 46 52 input: '', 53 + lint: false, 54 + name: 'AppClient', 55 + operationId: true, 47 56 output: '', 57 + postfixModels: '', 58 + postfixServices: '', 48 59 serviceResponse: 'body', 60 + useDateType: false, 61 + useOptions: true, 62 + write: true, 49 63 }; 50 64 51 65 await writeClientCore(client, templates, '/', config); ··· 69 83 70 84 const config: Parameters<typeof writeClientCore>[3] = { 71 85 client: 'fetch', 86 + enums: true, 87 + exportCore: true, 88 + exportModels: true, 89 + exportSchemas: true, 90 + exportServices: true, 91 + format: false, 72 92 input: '', 93 + lint: false, 94 + name: 'AppClient', 95 + operationId: true, 73 96 output: '', 97 + postfixModels: '', 98 + postfixServices: '', 74 99 serviceResponse: 'body', 100 + useDateType: false, 101 + useOptions: true, 102 + write: true, 75 103 }; 76 104 77 105 await writeClientCore(client, templates, '/', config); ··· 95 123 const config: Parameters<typeof writeClientCore>[3] = { 96 124 base: 'foo', 97 125 client: 'fetch', 126 + enums: true, 127 + exportCore: true, 128 + exportModels: true, 129 + exportSchemas: true, 130 + exportServices: true, 131 + format: false, 98 132 input: '', 133 + lint: false, 134 + name: 'AppClient', 135 + operationId: true, 99 136 output: '', 137 + postfixModels: '', 138 + postfixServices: '', 100 139 serviceResponse: 'body', 140 + useDateType: false, 141 + useOptions: true, 142 + write: true, 101 143 }; 102 144 103 145 await writeClientCore(client, templates, '/', config);
+12 -2
src/utils/write/__tests__/index.spec.ts
··· 38 38 }; 39 39 40 40 await writeClientIndex(client, templates, '/', { 41 + client: 'fetch', 41 42 enums: true, 42 43 exportCore: true, 43 - exportServices: true, 44 44 exportModels: true, 45 45 exportSchemas: true, 46 - postfixServices: 'Service', 46 + exportServices: true, 47 + format: false, 48 + input: '', 49 + lint: false, 50 + operationId: true, 51 + output: '', 47 52 postfixModels: '', 53 + postfixServices: 'Service', 54 + serviceResponse: 'body', 55 + useDateType: false, 56 + useOptions: true, 57 + write: true, 48 58 }); 49 59 50 60 expect(writeFileSync).toHaveBeenCalledWith(path.resolve('/', '/index.ts'), 'index');
+15
src/utils/write/__tests__/models.spec.ts
··· 59 59 await writeClientModels(client, templates, '/', { 60 60 client: 'fetch', 61 61 enums: true, 62 + exportCore: true, 63 + exportModels: true, 64 + exportSchemas: true, 65 + exportServices: true, 66 + format: false, 67 + input: '', 68 + lint: false, 69 + name: 'AppClient', 70 + operationId: true, 71 + output: '', 72 + postfixModels: '', 73 + postfixServices: '', 74 + serviceResponse: 'body', 62 75 useDateType: false, 76 + useOptions: true, 77 + write: true, 63 78 }); 64 79 65 80 expect(writeFileSync).toHaveBeenCalledWith(path.resolve('/', '/User.ts'), 'model');
+16
src/utils/write/__tests__/schemas.spec.ts
··· 59 59 await writeClientSchemas(client, templates, '/', { 60 60 client: 'fetch', 61 61 enums: true, 62 + exportCore: true, 63 + exportModels: true, 64 + exportSchemas: true, 65 + exportServices: true, 66 + format: false, 67 + input: '', 68 + lint: false, 69 + name: 'AppClient', 70 + operationId: true, 71 + output: '', 72 + postfixModels: '', 73 + postfixServices: '', 74 + serviceResponse: 'body', 75 + useDateType: false, 76 + useOptions: true, 77 + write: true, 62 78 }); 63 79 64 80 expect(writeFileSync).toHaveBeenCalledWith(path.resolve('/', '/$User.ts'), 'schema');
+7 -8
src/utils/write/class.ts
··· 2 2 import path from 'node:path'; 3 3 4 4 import type { Client } from '../../types/client'; 5 - import type { UserConfig } from '../../types/config'; 5 + import type { Config } from '../../types/config'; 6 6 import { getHttpRequestName } from '../getHttpRequestName'; 7 7 import type { Templates } from '../handlebars'; 8 8 import { sortByName } from '../sort'; ··· 14 14 * @param client Client containing models, schemas, and services 15 15 * @param templates The loaded handlebar templates 16 16 * @param outputPath Directory to write the generated files to 17 - * @param options Options passed to the `generate()` function 17 + * @param config {@link Config} passed to the `createClient()` method 18 18 */ 19 19 export const writeClientClass = async ( 20 20 client: Client, 21 21 templates: Templates, 22 22 outputPath: string, 23 - options: Pick<Required<UserConfig>, 'client' | 'enums' | 'name' | 'postfixServices'> 23 + config: Config 24 24 ): Promise<void> => { 25 25 const templateResult = templates.client({ 26 - $config: options, 27 - httpRequest: getHttpRequestName(options.client), 26 + $config: config, 27 + ...client, 28 + httpRequest: getHttpRequestName(config.client), 28 29 models: sortByName(client.models), 29 - server: client.server, 30 30 services: sortByName(client.services), 31 - version: client.version, 32 31 }); 33 32 34 - await writeFileSync(path.resolve(outputPath, `${options.name}.ts`), templateResult); 33 + await writeFileSync(path.resolve(outputPath, `${config.name}.ts`), templateResult); 35 34 };
+56 -72
src/utils/write/client.ts
··· 4 4 import type { Client } from '../../types/client'; 5 5 import type { Config } from '../../types/config'; 6 6 import type { Templates } from '../handlebars'; 7 - import { isSubDirectory } from '../isSubdirectory'; 8 7 import { writeClientClass } from './class'; 9 8 import { writeClientCore } from './core'; 10 9 import { writeClientIndex } from './index'; ··· 16 15 * Write our OpenAPI client, using the given templates at the given output 17 16 * @param client Client containing models, schemas, and services 18 17 * @param templates Templates wrapper with all loaded Handlebars templates 19 - * @param options {@link Config} passed to the `createClient()` method 18 + * @param config {@link Config} passed to the `createClient()` method 20 19 */ 21 - export const writeClient = async (client: Client, templates: Templates, options: Config): Promise<void> => { 22 - const outputPath = path.resolve(process.cwd(), options.output); 23 - 24 - if (!isSubDirectory(process.cwd(), options.output)) { 25 - throw new Error(`Output folder is not a subdirectory of the current working directory`); 26 - } 20 + export const writeClient = async (client: Client, templates: Templates, config: Config): Promise<void> => { 21 + await rmSync(config.output, { 22 + force: true, 23 + recursive: true, 24 + }); 27 25 28 - if (typeof options.exportServices === 'string') { 29 - const regexp = new RegExp(options.exportServices); 26 + if (typeof config.exportServices === 'string') { 27 + const regexp = new RegExp(config.exportServices); 30 28 client.services = client.services.filter(service => regexp.test(service.name)); 31 29 } 32 30 33 - if (typeof options.exportModels === 'string') { 34 - const regexp = new RegExp(options.exportModels); 31 + if (typeof config.exportModels === 'string') { 32 + const regexp = new RegExp(config.exportModels); 35 33 client.models = client.models.filter(model => regexp.test(model.name)); 36 34 } 37 35 38 - if (options.exportCore) { 39 - const outputPathCore = path.resolve(outputPath, 'core'); 40 - await rmSync(outputPathCore, { 41 - force: true, 42 - recursive: true, 43 - }); 44 - await mkdirSync(outputPathCore, { 45 - recursive: true, 46 - }); 47 - await writeClientCore(client, templates, outputPathCore, options); 48 - } 49 - 50 - if (options.exportSchemas) { 51 - const outputPathSchemas = path.resolve(outputPath, 'schemas'); 52 - await rmSync(outputPathSchemas, { 53 - force: true, 54 - recursive: true, 55 - }); 56 - await mkdirSync(outputPathSchemas, { 57 - recursive: true, 58 - }); 59 - await writeClientSchemas(client, templates, outputPathSchemas, options); 60 - } 61 - 62 - if (options.exportModels) { 63 - const outputPathModels = path.resolve(outputPath, 'models'); 64 - await rmSync(outputPathModels, { 65 - force: true, 66 - recursive: true, 67 - }); 68 - await mkdirSync(outputPathModels, { 69 - recursive: true, 70 - }); 71 - await writeClientModels(client, templates, outputPathModels, options); 72 - } 73 - 74 - if (options.exportServices) { 75 - const outputPathServices = path.resolve(outputPath, 'services'); 76 - await rmSync(outputPathServices, { 77 - force: true, 78 - recursive: true, 79 - }); 80 - await mkdirSync(outputPathServices, { 81 - recursive: true, 82 - }); 83 - await writeClientServices(client, templates, outputPathServices, options); 84 - } 36 + const sections = [ 37 + { 38 + dir: 'core', 39 + enabled: config.exportCore, 40 + fn: writeClientCore, 41 + }, 42 + { 43 + dir: 'schemas', 44 + enabled: config.exportSchemas, 45 + fn: writeClientSchemas, 46 + }, 47 + { 48 + dir: 'models', 49 + enabled: config.exportModels, 50 + fn: writeClientModels, 51 + }, 52 + { 53 + dir: 'services', 54 + enabled: config.exportServices, 55 + fn: writeClientServices, 56 + }, 57 + { 58 + dir: '', 59 + enabled: config.name, 60 + fn: writeClientClass, 61 + }, 62 + ] as const; 85 63 86 - if (options.name) { 87 - await mkdirSync(outputPath, { 88 - recursive: true, 89 - }); 90 - await writeClientClass(client, templates, outputPath, { 91 - ...options, 92 - name: options.name, 93 - }); 64 + for (const section of sections) { 65 + if (section.enabled) { 66 + const sectionPath = path.resolve(config.output, section.dir); 67 + if (section.dir) { 68 + await rmSync(sectionPath, { 69 + force: true, 70 + recursive: true, 71 + }); 72 + } 73 + await mkdirSync(sectionPath, { 74 + recursive: true, 75 + }); 76 + await section.fn(client, templates, sectionPath, { 77 + ...config, 78 + name: config.name!, 79 + }); 80 + } 94 81 } 95 82 96 - if (options.exportCore || options.exportServices || options.exportSchemas || options.exportModels) { 97 - await mkdirSync(outputPath, { 98 - recursive: true, 99 - }); 100 - await writeClientIndex(client, templates, outputPath, options); 83 + if (sections.some(section => section.enabled)) { 84 + await writeClientIndex(client, templates, config.output, config); 101 85 } 102 86 };
+17 -17
src/utils/write/core.ts
··· 2 2 import path from 'node:path'; 3 3 4 4 import type { Client } from '../../types/client'; 5 - import type { UserConfig } from '../../types/config'; 5 + import type { Config } from '../../types/config'; 6 6 import { getHttpRequestName } from '../getHttpRequestName'; 7 7 import type { Templates } from '../handlebars'; 8 8 ··· 11 11 * @param client Client containing models, schemas, and services 12 12 * @param templates The loaded handlebar templates 13 13 * @param outputPath Directory to write the generated files to 14 - * @param options Options passed to the `generate()` function 14 + * @param config {@link Config} passed to the `createClient()` method 15 15 */ 16 16 export const writeClientCore = async ( 17 17 client: Client, 18 18 templates: Templates, 19 19 outputPath: string, 20 - options: Pick<Required<UserConfig>, 'client' | 'serviceResponse'> & Omit<UserConfig, 'client' | 'serviceResponse'> 20 + config: Config 21 21 ): Promise<void> => { 22 22 const context = { 23 - httpRequest: getHttpRequestName(options.client), 24 - server: options.base !== undefined ? options.base : client.server, 23 + httpRequest: getHttpRequestName(config.client), 24 + server: config.base !== undefined ? config.base : client.server, 25 25 version: client.version, 26 26 }; 27 27 28 28 await writeFileSync( 29 29 path.resolve(outputPath, 'OpenAPI.ts'), 30 30 templates.core.settings({ 31 - $config: options, 31 + $config: config, 32 32 ...context, 33 33 }) 34 34 ); 35 35 await writeFileSync( 36 36 path.resolve(outputPath, 'ApiError.ts'), 37 37 templates.core.apiError({ 38 - $config: options, 38 + $config: config, 39 39 ...context, 40 40 }) 41 41 ); 42 42 await writeFileSync( 43 43 path.resolve(outputPath, 'ApiRequestOptions.ts'), 44 44 templates.core.apiRequestOptions({ 45 - $config: options, 45 + $config: config, 46 46 ...context, 47 47 }) 48 48 ); 49 49 await writeFileSync( 50 50 path.resolve(outputPath, 'ApiResult.ts'), 51 51 templates.core.apiResult({ 52 - $config: options, 52 + $config: config, 53 53 ...context, 54 54 }) 55 55 ); 56 56 await writeFileSync( 57 57 path.resolve(outputPath, 'CancelablePromise.ts'), 58 58 templates.core.cancelablePromise({ 59 - $config: options, 59 + $config: config, 60 60 ...context, 61 61 }) 62 62 ); 63 63 await writeFileSync( 64 64 path.resolve(outputPath, 'request.ts'), 65 65 templates.core.request({ 66 - $config: options, 66 + $config: config, 67 67 ...context, 68 68 }) 69 69 ); 70 70 await writeFileSync( 71 71 path.resolve(outputPath, 'types.ts'), 72 72 templates.core.types({ 73 - $config: options, 73 + $config: config, 74 74 ...context, 75 75 }) 76 76 ); 77 77 78 - if (options.name) { 78 + if (config.name) { 79 79 await writeFileSync( 80 80 path.resolve(outputPath, 'BaseHttpRequest.ts'), 81 81 templates.core.baseHttpRequest({ 82 - $config: options, 82 + $config: config, 83 83 ...context, 84 84 }) 85 85 ); 86 86 await writeFileSync( 87 87 path.resolve(outputPath, `${context.httpRequest}.ts`), 88 88 templates.core.httpRequest({ 89 - $config: options, 89 + $config: config, 90 90 ...context, 91 91 }) 92 92 ); 93 93 } 94 94 95 - if (options.request) { 96 - const requestFile = path.resolve(process.cwd(), options.request); 95 + if (config.request) { 96 + const requestFile = path.resolve(process.cwd(), config.request); 97 97 const requestFileExists = await existsSync(requestFile); 98 98 if (!requestFileExists) { 99 99 throw new Error(`Custom request file "${requestFile}" does not exists`);
+5 -16
src/utils/write/index.ts
··· 2 2 import path from 'node:path'; 3 3 4 4 import type { Client } from '../../types/client'; 5 - import type { UserConfig } from '../../types/config'; 5 + import type { Config } from '../../types/config'; 6 6 import { Templates } from '../handlebars'; 7 7 import { sortByName } from '../sort'; 8 8 ··· 13 13 * @param client Client containing models, schemas, and services 14 14 * @param templates The loaded handlebar templates 15 15 * @param outputPath Directory to write the generated files to 16 - * @param options Options passed to the `generate()` function 16 + * @param config {@link Config} passed to the `createClient()` method 17 17 */ 18 18 export const writeClientIndex = async ( 19 19 client: Client, 20 20 templates: Templates, 21 21 outputPath: string, 22 - options: Pick< 23 - Required<UserConfig>, 24 - | 'enums' 25 - | 'exportCore' 26 - | 'exportServices' 27 - | 'exportModels' 28 - | 'exportSchemas' 29 - | 'postfixServices' 30 - | 'postfixModels' 31 - > & 32 - Pick<UserConfig, 'name'> 22 + config: Config 33 23 ): Promise<void> => { 34 24 const templateResult = templates.index({ 35 - $config: options, 25 + $config: config, 26 + ...client, 36 27 models: sortByName(client.models), 37 - server: client.server, 38 28 services: sortByName(client.services), 39 - version: client.version, 40 29 }); 41 30 42 31 await writeFileSync(path.resolve(outputPath, 'index.ts'), templateResult);
+4 -4
src/utils/write/models.ts
··· 2 2 import path from 'node:path'; 3 3 4 4 import type { Client } from '../../types/client'; 5 - import type { UserConfig } from '../../types/config'; 5 + import type { Config } from '../../types/config'; 6 6 import type { Templates } from '../handlebars'; 7 7 8 8 /** ··· 10 10 * @param client Client containing models, schemas, and services 11 11 * @param templates The loaded handlebar templates 12 12 * @param outputPath Directory to write the generated files to 13 - * @param options Options passed to the `generate()` function 13 + * @param config {@link Config} passed to the `createClient()` method 14 14 */ 15 15 export const writeClientModels = async ( 16 16 client: Client, 17 17 templates: Templates, 18 18 outputPath: string, 19 - options: Pick<Required<UserConfig>, 'client' | 'enums' | 'useDateType'> 19 + config: Config 20 20 ): Promise<void> => { 21 21 for (const model of client.models) { 22 22 const file = path.resolve(outputPath, `${model.name}.ts`); 23 23 const templateResult = templates.exports.model({ 24 - $config: options, 24 + $config: config, 25 25 ...model, 26 26 }); 27 27 await writeFileSync(file, templateResult);
+4 -4
src/utils/write/schemas.ts
··· 2 2 import path from 'node:path'; 3 3 4 4 import type { Client } from '../../types/client'; 5 - import type { UserConfig } from '../../types/config'; 5 + import type { Config } from '../../types/config'; 6 6 import type { Templates } from '../handlebars'; 7 7 8 8 /** ··· 10 10 * @param client Client containing models, schemas, and services 11 11 * @param templates The loaded handlebar templates 12 12 * @param outputPath Directory to write the generated files to 13 - * @param options Options passed to the `generate()` function 13 + * @param config {@link Config} passed to the `createClient()` method 14 14 */ 15 15 export const writeClientSchemas = async ( 16 16 client: Client, 17 17 templates: Templates, 18 18 outputPath: string, 19 - options: Pick<Required<UserConfig>, 'client' | 'enums'> 19 + config: Config 20 20 ): Promise<void> => { 21 21 for (const model of client.models) { 22 22 const file = path.resolve(outputPath, `$${model.name}.ts`); 23 23 const templateResult = templates.exports.schema({ 24 - $config: options, 24 + $config: config, 25 25 ...model, 26 26 }); 27 27 await writeFileSync(file, templateResult);
+4 -4
src/utils/write/services.ts
··· 10 10 * @param client Client containing models, schemas, and services 11 11 * @param templates The loaded handlebar templates 12 12 * @param outputPath Directory to write the generated files to 13 - * @param options {@link Config} passed to the `createClient()` method 13 + * @param config {@link Config} passed to the `createClient()` method 14 14 */ 15 15 export const writeClientServices = async ( 16 16 client: Client, 17 17 templates: Templates, 18 18 outputPath: string, 19 - options: Config 19 + config: Config 20 20 ): Promise<void> => { 21 21 for (const service of client.services) { 22 - const file = path.resolve(outputPath, `${service.name}${options.postfixServices}.ts`); 22 + const file = path.resolve(outputPath, `${service.name}${config.postfixServices}.ts`); 23 23 const templateResult = templates.exports.service({ 24 - $config: options, 24 + $config: config, 25 25 ...service, 26 26 }); 27 27 await writeFileSync(file, templateResult);
-1
test/sample.cjs
··· 5 5 const config = { 6 6 client: 'fetch', 7 7 enums: true, 8 - exportSchemas: true, 9 8 input: './test/spec/v3.json', 10 9 output: './test/generated/v3/', 11 10 useOptions: true,