diff --git a/README.md b/README.md index 53ebf09c..338e40c2 100644 --- a/README.md +++ b/README.md @@ -54,10 +54,22 @@ openapi --input ./api/openapi.json --output ./dist ```javascript const OpenAPI = require('openapi-typescript-codegen'); -OpenAPI.generate( - './api/openapi.json', - './dist' -); +OpenAPI.generate({ + input: './api/openapi.json', + output: './dist' +}); +``` + +Or by providing the JSON directly: + +```javascript +const OpenAPI = require('openapi-typescript-codegen'); +const spec = require('./api/openapi.json'); + +OpenAPI.generate({ + input: spec, + output: './dist' +}); ``` ## Features diff --git a/bin/index.js b/bin/index.js index 72024735..d8e26a0f 100755 --- a/bin/index.js +++ b/bin/index.js @@ -12,15 +12,17 @@ program .option('--output [value]', 'Output directory', './generated') .option('--client [value]', 'HTTP client to generate [fetch, xhr]', 'fetch') .option('--useOptions', 'Use options vs arguments style functions', false) + .option('--useUnionTypes', 'Use inclusive union types', false) .parse(process.argv); const OpenAPI = require(path.resolve(__dirname, '../dist/index.js')); if (OpenAPI) { - OpenAPI.generate( - program.input, - program.output, - program.client, - program.useOptions - ); + OpenAPI.generate({ + input: program.input, + output: program.output, + httpClient: program.client, + useOptions: program.useOptions, + useUnionTypes: program.useUnionTypes + }); } diff --git a/package.json b/package.json index f191511f..63c276f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openapi-typescript-codegen", - "version": "0.1.17", + "version": "0.2.3", "description": "NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.", "author": "Ferdi Koomen", "homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen", diff --git a/src/client/interfaces/Model.d.ts b/src/client/interfaces/Model.d.ts index c3181614..057e52d8 100644 --- a/src/client/interfaces/Model.d.ts +++ b/src/client/interfaces/Model.d.ts @@ -15,4 +15,6 @@ export interface Model extends Schema { enum: Enum[]; enums: Model[]; properties: Model[]; + extendedFrom?: string[]; + extendedBy?: string[]; } diff --git a/src/client/interfaces/OperationResponse.d.ts b/src/client/interfaces/OperationResponse.d.ts index fd359c13..afdb668c 100644 --- a/src/client/interfaces/OperationResponse.d.ts +++ b/src/client/interfaces/OperationResponse.d.ts @@ -1,5 +1,6 @@ import { Model } from './Model'; export interface OperationResponse extends Model { + in: 'response' | 'header'; code: number; } diff --git a/src/client/interfaces/Schema.d.ts b/src/client/interfaces/Schema.d.ts index d03baaf5..b45158d9 100644 --- a/src/client/interfaces/Schema.d.ts +++ b/src/client/interfaces/Schema.d.ts @@ -1,5 +1,5 @@ export interface Schema { - isProperty: boolean; + isDefinition: boolean; isReadOnly: boolean; isRequired: boolean; isNullable: boolean; diff --git a/src/index.spec.ts b/src/index.spec.ts index dd34eac2..c0cd622e 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -2,10 +2,18 @@ import * as OpenAPI from '.'; describe('index', () => { it('parses v2 without issues', () => { - OpenAPI.generate('./test/mock/v2/spec.json', './test/result/v2/', OpenAPI.HttpClient.FETCH, false, false); + OpenAPI.generate({ + input: './test/mock/v2/spec.json', + output: './test/result/v2/', + write: false, + }); }); it('parses v3 without issues', () => { - OpenAPI.generate('./test/mock/v3/spec.json', './test/result/v3/', OpenAPI.HttpClient.FETCH, false, false); + OpenAPI.generate({ + input: './test/mock/v3/spec.json', + output: './test/result/v3/', + write: false, + }); }); }); diff --git a/src/index.ts b/src/index.ts index 68d0b740..77c1f91a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -import * as path from 'path'; -import * as ts from 'typescript'; import { OpenApiVersion, getOpenApiVersion } from './utils/getOpenApiVersion'; import { getOpenApiSpec } from './utils/getOpenApiSpec'; +import { isString } from './utils/isString'; import { parse as parseV2 } from './openApi/v2'; import { parse as parseV3 } from './openApi/v3'; +import { postProcessClient } from './utils/postProcessClient'; import { readHandlebarsTemplates } from './utils/readHandlebarsTemplates'; import { writeClient } from './utils/writeClient'; @@ -12,6 +12,15 @@ export enum HttpClient { XHR = 'xhr', } +export interface Options { + input: string | Record; + output: string; + httpClient?: HttpClient; + useOptions?: boolean; + useUnionTypes?: boolean; + write?: boolean; +} + /** * Generate the OpenAPI client. This method will read the OpenAPI specification and based on the * given language it will generate the client, including the typed models, validation schemas, @@ -20,52 +29,38 @@ export enum HttpClient { * @param output The relative location of the output directory. * @param httpClient The selected httpClient (fetch or XHR). * @param useOptions Use options or arguments functions. - * @param write Write the files to disk (true or false) + * @param useUnionTypes Use inclusive union types. + * @param write Write the files to disk (true or false). */ -export function generate(input: string, output: string, httpClient: HttpClient = HttpClient.FETCH, useOptions: boolean = false, write: boolean = true): void { - const inputPath = path.resolve(process.cwd(), input); - const outputPath = path.resolve(process.cwd(), output); - +export function generate({ input, output, httpClient = HttpClient.FETCH, useOptions = false, useUnionTypes = false, write = true }: Options): void { try { // Load the specification, read the OpenAPI version and load the // handlebar templates for the given language - const openApi = getOpenApiSpec(inputPath); + const openApi = isString(input) ? getOpenApiSpec(input) : input; const openApiVersion = getOpenApiVersion(openApi); const templates = readHandlebarsTemplates(); switch (openApiVersion) { - case OpenApiVersion.V2: - const clientV2 = parseV2(openApi); + case OpenApiVersion.V2: { + const client = parseV2(openApi); + const clientFinal = postProcessClient(client, useUnionTypes); if (write) { - writeClient(clientV2, httpClient, templates, outputPath, useOptions); + writeClient(clientFinal, templates, output, httpClient, useOptions); } break; + } - case OpenApiVersion.V3: - const clientV3 = parseV3(openApi); + case OpenApiVersion.V3: { + const client = parseV3(openApi); + const clientFinal = postProcessClient(client, useUnionTypes); if (write) { - writeClient(clientV3, httpClient, templates, outputPath, useOptions); + writeClient(clientFinal, templates, output, httpClient, useOptions); } break; + } } } catch (e) { console.error(e); process.exit(1); } } - -export function compile(dir: string): void { - const config = { - compilerOptions: { - target: 'esnext', - module: 'commonjs', - moduleResolution: 'node', - }, - include: ['./index.ts'], - }; - const configFile = ts.parseConfigFileTextToJson('tsconfig.json', JSON.stringify(config)); - const configFileResult = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.resolve(process.cwd(), dir), undefined, 'tsconfig.json'); - const compilerHost = ts.createCompilerHost(configFileResult.options); - const compiler = ts.createProgram(configFileResult.fileNames, configFileResult.options, compilerHost); - compiler.emit(); -} diff --git a/src/openApi/v2/index.ts b/src/openApi/v2/index.ts index 734b80d4..4f9055a9 100644 --- a/src/openApi/v2/index.ts +++ b/src/openApi/v2/index.ts @@ -11,10 +11,10 @@ import { getServices } from './parser/getServices'; * @param openApi The OpenAPI spec that we have loaded from disk. */ export function parse(openApi: OpenApi): Client { - return { - version: getServiceVersion(openApi.info.version), - server: getServer(openApi), - models: getModels(openApi), - services: getServices(openApi), - }; + const version = getServiceVersion(openApi.info.version); + const server = getServer(openApi); + const models = getModels(openApi); + const services = getServices(openApi); + + return { version, server, models, services }; } diff --git a/src/openApi/v2/parser/extendEnum.ts b/src/openApi/v2/parser/extendEnum.ts index 92659ac5..39325188 100644 --- a/src/openApi/v2/parser/extendEnum.ts +++ b/src/openApi/v2/parser/extendEnum.ts @@ -4,6 +4,12 @@ import { WithEnumExtension } from '../interfaces/Extensions/WithEnumExtension'; const KEY_ENUM_NAMES = 'x-enum-varnames'; const KEY_ENUM_DESCRIPTIONS = 'x-enum-descriptions'; +/** + * Extend the enum with the x-enum properties. This adds the capability + * to use names and descriptions inside the generated enums. + * @param enumerators + * @param definition + */ export function extendEnum(enumerators: Enum[], definition: WithEnumExtension): Enum[] { const names = definition[KEY_ENUM_NAMES]; const descriptions = definition[KEY_ENUM_DESCRIPTIONS]; diff --git a/src/openApi/v2/parser/getComment.ts b/src/openApi/v2/parser/getComment.ts index b6c0a05f..7c162cfd 100644 --- a/src/openApi/v2/parser/getComment.ts +++ b/src/openApi/v2/parser/getComment.ts @@ -1,5 +1,10 @@ import { EOL } from 'os'; +/** + * Cleanup comment and prefix multiline comments with "*", + * so they look a bit nicer when used in the generated code. + * @param comment + */ export function getComment(comment?: string): string | null { if (comment) { return comment.replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`); diff --git a/src/openApi/v2/parser/getModel.ts b/src/openApi/v2/parser/getModel.ts index 6d0c17cf..223f0930 100644 --- a/src/openApi/v2/parser/getModel.ts +++ b/src/openApi/v2/parser/getModel.ts @@ -9,7 +9,7 @@ import { getEnumFromDescription } from './getEnumFromDescription'; import { getModelProperties } from './getModelProperties'; import { getType } from './getType'; -export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty: boolean = false, name: string = ''): Model { +export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model { const model: Model = { name: name, export: 'interface', @@ -18,7 +18,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty template: null, link: null, description: getComment(definition.description), - isProperty: isProperty, + isDefinition: isDefinition, isReadOnly: definition.readOnly === true, isNullable: false, isRequired: false, @@ -86,7 +86,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty model.imports.push(...arrayItems.imports); return model; } else { - const arrayItems = getModel(openApi, definition.items, true); + const arrayItems = getModel(openApi, definition.items); model.export = 'array'; model.type = arrayItems.type; model.base = arrayItems.base; @@ -129,7 +129,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty definition.allOf.forEach(parent => { if (parent.$ref) { const parentRef = getType(parent.$ref); - model.extends.push(parentRef.type); + model.extends.push(parentRef.base); model.imports.push(parentRef.base); } if (parent.type === 'object' && parent.properties) { diff --git a/src/openApi/v2/parser/getModelProperties.ts b/src/openApi/v2/parser/getModelProperties.ts index 67354713..363621f5 100644 --- a/src/openApi/v2/parser/getModelProperties.ts +++ b/src/openApi/v2/parser/getModelProperties.ts @@ -21,7 +21,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): template: model.template, link: null, description: getComment(property.description), - isProperty: true, + isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, isNullable: false, @@ -55,7 +55,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): template: model.template, link: model.link, description: getComment(property.description), - isProperty: true, + isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, isNullable: false, diff --git a/src/openApi/v2/parser/getModels.ts b/src/openApi/v2/parser/getModels.ts index d654151d..e223f5f9 100644 --- a/src/openApi/v2/parser/getModels.ts +++ b/src/openApi/v2/parser/getModels.ts @@ -4,14 +4,14 @@ import { getModel } from './getModel'; import { getType } from './getType'; export function getModels(openApi: OpenApi): Model[] { - const models = new Map(); + const models: Model[] = []; for (const definitionName in openApi.definitions) { if (openApi.definitions.hasOwnProperty(definitionName)) { const definition = openApi.definitions[definitionName]; const definitionType = getType(definitionName); - const model = getModel(openApi, definition, false, definitionType.base); - models.set(definitionType.base, model); + const model = getModel(openApi, definition, true, definitionType.base); + models.push(model); } } - return Array.from(models.values()); + return models; } diff --git a/src/openApi/v2/parser/getOperationParameter.ts b/src/openApi/v2/parser/getOperationParameter.ts index dea5db3e..c962c488 100644 --- a/src/openApi/v2/parser/getOperationParameter.ts +++ b/src/openApi/v2/parser/getOperationParameter.ts @@ -22,7 +22,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame template: null, link: null, description: getComment(parameter.description), - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: parameter.required === true, isNullable: false, diff --git a/src/openApi/v2/parser/getOperationResponse.ts b/src/openApi/v2/parser/getOperationResponse.ts index aa8a9e4a..26e734c6 100644 --- a/src/openApi/v2/parser/getOperationResponse.ts +++ b/src/openApi/v2/parser/getOperationResponse.ts @@ -8,6 +8,7 @@ import { getType } from './getType'; export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse, responseCode: number): OperationResponse { const operationResponse: OperationResponse = { + in: 'response', name: '', code: responseCode, description: getComment(response.description)!, @@ -16,7 +17,7 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse base: PrimaryType.OBJECT, template: null, link: null, - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: false, isNullable: false, diff --git a/src/openApi/v2/parser/getOperationResponses.ts b/src/openApi/v2/parser/getOperationResponses.ts index 87621291..dd1f5ac5 100644 --- a/src/openApi/v2/parser/getOperationResponses.ts +++ b/src/openApi/v2/parser/getOperationResponses.ts @@ -18,7 +18,8 @@ export function getOperationResponses(openApi: OpenApi, responses: OpenApiRespon const responseCode = getOperationResponseCode(code); if (responseCode) { - operationResponses.push(getOperationResponse(openApi, response, responseCode)); + const operationResponse = getOperationResponse(openApi, response, responseCode); + operationResponses.push(operationResponse); } } } diff --git a/src/openApi/v2/parser/getOperationResults.ts b/src/openApi/v2/parser/getOperationResults.ts index fdb76359..6f8b4429 100644 --- a/src/openApi/v2/parser/getOperationResults.ts +++ b/src/openApi/v2/parser/getOperationResults.ts @@ -21,6 +21,7 @@ export function getOperationResults(operationResponses: OperationResponse[]): Op if (!operationResults.length) { operationResults.push({ + in: 'response', name: '', code: 200, description: '', @@ -29,7 +30,7 @@ export function getOperationResults(operationResponses: OperationResponse[]): Op base: PrimaryType.OBJECT, template: null, link: null, - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: false, isNullable: false, diff --git a/src/openApi/v2/parser/getServices.ts b/src/openApi/v2/parser/getServices.ts index ac61a2c8..2b72cb01 100644 --- a/src/openApi/v2/parser/getServices.ts +++ b/src/openApi/v2/parser/getServices.ts @@ -27,13 +27,11 @@ export function getServices(openApi: OpenApi): Service[] { // If we have already declared a service, then we should fetch that and // append the new method to it. Otherwise we should create a new service object. - const service = - services.get(operation.service) || - ({ - name: operation.service, - operations: [], - imports: [], - } as Service); + const service: Service = services.get(operation.service) || { + name: operation.service, + operations: [], + imports: [], + }; // Push the operation in the service service.operations.push(operation); diff --git a/src/openApi/v2/parser/getType.ts b/src/openApi/v2/parser/getType.ts index 617d68fd..e9fb22d5 100644 --- a/src/openApi/v2/parser/getType.ts +++ b/src/openApi/v2/parser/getType.ts @@ -26,7 +26,7 @@ export function getType(value?: string, template?: string): Type { if (match1.type === PrimaryType.ARRAY) { result.type = `${match2.type}[]`; - result.base = `${match2.type}`; + result.base = match2.type; match1.imports = []; } else if (match2.type) { result.type = `${match1.type}<${match2.type}>`; diff --git a/src/openApi/v3/index.ts b/src/openApi/v3/index.ts index 734b80d4..4f9055a9 100644 --- a/src/openApi/v3/index.ts +++ b/src/openApi/v3/index.ts @@ -11,10 +11,10 @@ import { getServices } from './parser/getServices'; * @param openApi The OpenAPI spec that we have loaded from disk. */ export function parse(openApi: OpenApi): Client { - return { - version: getServiceVersion(openApi.info.version), - server: getServer(openApi), - models: getModels(openApi), - services: getServices(openApi), - }; + const version = getServiceVersion(openApi.info.version); + const server = getServer(openApi); + const models = getModels(openApi); + const services = getServices(openApi); + + return { version, server, models, services }; } diff --git a/src/openApi/v3/parser/extendEnum.ts b/src/openApi/v3/parser/extendEnum.ts index 92659ac5..39325188 100644 --- a/src/openApi/v3/parser/extendEnum.ts +++ b/src/openApi/v3/parser/extendEnum.ts @@ -4,6 +4,12 @@ import { WithEnumExtension } from '../interfaces/Extensions/WithEnumExtension'; const KEY_ENUM_NAMES = 'x-enum-varnames'; const KEY_ENUM_DESCRIPTIONS = 'x-enum-descriptions'; +/** + * Extend the enum with the x-enum properties. This adds the capability + * to use names and descriptions inside the generated enums. + * @param enumerators + * @param definition + */ export function extendEnum(enumerators: Enum[], definition: WithEnumExtension): Enum[] { const names = definition[KEY_ENUM_NAMES]; const descriptions = definition[KEY_ENUM_DESCRIPTIONS]; diff --git a/src/openApi/v3/parser/getComment.ts b/src/openApi/v3/parser/getComment.ts index b6c0a05f..7c162cfd 100644 --- a/src/openApi/v3/parser/getComment.ts +++ b/src/openApi/v3/parser/getComment.ts @@ -1,5 +1,10 @@ import { EOL } from 'os'; +/** + * Cleanup comment and prefix multiline comments with "*", + * so they look a bit nicer when used in the generated code. + * @param comment + */ export function getComment(comment?: string): string | null { if (comment) { return comment.replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`); diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index ee9554d0..b63737af 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -10,7 +10,7 @@ import { getModelDefault } from './getModelDefault'; import { getModelProperties } from './getModelProperties'; import { getType } from './getType'; -export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty: boolean = false, name: string = ''): Model { +export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model { const model: Model = { name: name, export: 'interface', @@ -19,7 +19,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty template: null, link: null, description: getComment(definition.description), - isProperty: isProperty, + isDefinition: isDefinition, isReadOnly: definition.readOnly === true, isNullable: definition.nullable === true, isRequired: false, @@ -77,7 +77,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty model.default = getModelDefault(definition, model); return model; } else { - const arrayItems = getModel(openApi, definition.items, true); + const arrayItems = getModel(openApi, definition.items); model.export = 'array'; model.type = arrayItems.type; model.base = arrayItems.base; @@ -117,7 +117,10 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty if (definition.anyOf && definition.anyOf.length) { model.export = 'generic'; const compositionTypes = definition.anyOf.filter(type => type.$ref).map(type => getType(type.$ref)); - const composition = compositionTypes.map(type => type.type).join(' | '); + const composition = compositionTypes + .map(type => type.type) + .sort() + .join(' | '); model.imports.push(...compositionTypes.map(type => type.base)); model.type = composition; model.base = composition; @@ -127,7 +130,10 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty if (definition.oneOf && definition.oneOf.length) { model.export = 'generic'; const compositionTypes = definition.oneOf.filter(type => type.$ref).map(type => getType(type.$ref)); - const composition = compositionTypes.map(type => type.type).join(' | '); + const composition = compositionTypes + .map(type => type.type) + .sort() + .join(' | '); model.imports.push(...compositionTypes.map(type => type.base)); model.type = composition; model.base = composition; @@ -144,7 +150,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty definition.allOf.forEach(parent => { if (parent.$ref) { const parentRef = getType(parent.$ref); - model.extends.push(parentRef.type); + model.extends.push(parentRef.base); model.imports.push(parentRef.base); } if (parent.type === 'object' && parent.properties) { diff --git a/src/openApi/v3/parser/getModelProperties.ts b/src/openApi/v3/parser/getModelProperties.ts index b98ac8d6..55131337 100644 --- a/src/openApi/v3/parser/getModelProperties.ts +++ b/src/openApi/v3/parser/getModelProperties.ts @@ -21,7 +21,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): template: model.template, link: null, description: getComment(property.description), - isProperty: true, + isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, isNullable: property.nullable === true, @@ -55,7 +55,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): template: model.template, link: model.link, description: getComment(property.description), - isProperty: true, + isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, isNullable: property.nullable === true, diff --git a/src/openApi/v3/parser/getModels.ts b/src/openApi/v3/parser/getModels.ts index 4baa34af..e4faece4 100644 --- a/src/openApi/v3/parser/getModels.ts +++ b/src/openApi/v3/parser/getModels.ts @@ -4,16 +4,16 @@ import { getModel } from './getModel'; import { getType } from './getType'; export function getModels(openApi: OpenApi): Model[] { - const models = new Map(); + const models: Model[] = []; if (openApi.components) { for (const definitionName in openApi.components.schemas) { if (openApi.components.schemas.hasOwnProperty(definitionName)) { const definition = openApi.components.schemas[definitionName]; const definitionType = getType(definitionName); - const model = getModel(openApi, definition, false, definitionType.base); - models.set(definitionType.base, model); + const model = getModel(openApi, definition, true, definitionType.base); + models.push(model); } } } - return Array.from(models.values()); + return models; } diff --git a/src/openApi/v3/parser/getOperationParameter.ts b/src/openApi/v3/parser/getOperationParameter.ts index 2fb16202..0c6b42df 100644 --- a/src/openApi/v3/parser/getOperationParameter.ts +++ b/src/openApi/v3/parser/getOperationParameter.ts @@ -19,7 +19,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame template: null, link: null, description: getComment(parameter.description), - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: parameter.required === true, isNullable: parameter.nullable === true, diff --git a/src/openApi/v3/parser/getOperationRequestBody.ts b/src/openApi/v3/parser/getOperationRequestBody.ts index da5a0a7b..e6fb5e5c 100644 --- a/src/openApi/v3/parser/getOperationRequestBody.ts +++ b/src/openApi/v3/parser/getOperationRequestBody.ts @@ -19,7 +19,7 @@ export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequ link: null, description: getComment(parameter.description), default: undefined, - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: parameter.required === true, isNullable: parameter.nullable === true, diff --git a/src/openApi/v3/parser/getOperationResponse.ts b/src/openApi/v3/parser/getOperationResponse.ts index 91edb706..895fb807 100644 --- a/src/openApi/v3/parser/getOperationResponse.ts +++ b/src/openApi/v3/parser/getOperationResponse.ts @@ -9,6 +9,7 @@ import { getType } from './getType'; export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse, responseCode: number): OperationResponse { const operationResponse: OperationResponse = { + in: 'response', name: '', code: responseCode, description: getComment(response.description)!, @@ -17,7 +18,7 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse base: PrimaryType.OBJECT, template: null, link: null, - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: false, isNullable: false, diff --git a/src/openApi/v3/parser/getOperationResults.ts b/src/openApi/v3/parser/getOperationResults.ts index fdb76359..6f8b4429 100644 --- a/src/openApi/v3/parser/getOperationResults.ts +++ b/src/openApi/v3/parser/getOperationResults.ts @@ -21,6 +21,7 @@ export function getOperationResults(operationResponses: OperationResponse[]): Op if (!operationResults.length) { operationResults.push({ + in: 'response', name: '', code: 200, description: '', @@ -29,7 +30,7 @@ export function getOperationResults(operationResponses: OperationResponse[]): Op base: PrimaryType.OBJECT, template: null, link: null, - isProperty: false, + isDefinition: false, isReadOnly: false, isRequired: false, isNullable: false, diff --git a/src/templates/core/OpenAPI.hbs b/src/templates/core/OpenAPI.hbs index e47cff6d..71c2f415 100644 --- a/src/templates/core/OpenAPI.hbs +++ b/src/templates/core/OpenAPI.hbs @@ -3,9 +3,16 @@ /* eslint-disable */ /* prettier-ignore */ -export namespace OpenAPI { - export let BASE = '{{{server}}}'; - export let VERSION = '{{{version}}}'; - export let CLIENT = '{{{httpClient}}}'; - export let TOKEN = ''; +interface Config { + BASE: string; + VERSION: string; + CLIENT: 'fetch' | 'xhr'; + TOKEN: string; } + +export const OpenAPI: Config = { + BASE: '{{{server}}}', + VERSION: '{{{version}}}', + CLIENT: '{{{httpClient}}}', + TOKEN: '', +}; diff --git a/src/utils/exportModel.ts b/src/utils/exportModel.ts deleted file mode 100644 index d4fb9718..00000000 --- a/src/utils/exportModel.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Model } from '../client/interfaces/Model'; - -export function exportModel(model: Model): Model { - return { - ...model, - imports: model.imports - .filter(name => { - return model.name !== name; - }) - .filter((name, index, arr) => { - return arr.indexOf(name) === index; - }) - .sort((a, b) => { - const nameA = a.toLowerCase(); - const nameB = b.toLowerCase(); - return nameA.localeCompare(nameB); - }), - enums: model.enums.filter((property, index, arr) => { - return arr.findIndex(item => item.name === property.name) === index; - }), - enum: model.enum.filter((enumerator, index, arr) => { - return arr.findIndex(item => item.name === enumerator.name) === index; - }), - }; -} diff --git a/src/utils/exportService.ts b/src/utils/exportService.ts deleted file mode 100644 index 60c70d91..00000000 --- a/src/utils/exportService.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Service } from '../client/interfaces/Service'; - -export function exportService(service: Service): Service { - const names = new Map(); - return { - ...service, - imports: service.imports - .filter(name => { - return service.name !== name; - }) - .filter((name, index, arr) => { - return arr.indexOf(name) === index; - }) - .sort((a, b) => { - const nameA = a.toLowerCase(); - const nameB = b.toLowerCase(); - return nameA.localeCompare(nameB); - }), - operations: service.operations.map(operation => { - const name = operation.name; - const index = names.get(name) || 0; - if (index > 0) { - operation.name = `${name}${index}`; - } - names.set(name, index + 1); - return operation; - }), - }; -} diff --git a/src/utils/getExtendedByList.ts b/src/utils/getExtendedByList.ts new file mode 100644 index 00000000..11da9abf --- /dev/null +++ b/src/utils/getExtendedByList.ts @@ -0,0 +1,23 @@ +import { Client } from '../client/interfaces/Client'; +import { Model } from '../client/interfaces/Model'; +import { unique } from './unique'; + +/** + * Get the full list of models that are extended by the given model. + * This list is used when we have the flag "useUnionTypes" enabled. + * @param model + * @param client + */ +export function getExtendedByList(model: Model, client: Client): Model[] { + const extendedBy = client.models.filter(ref => { + const names = model.isDefinition ? [model.name] : model.base.split(' | '); + return names.find(name => { + return ref.extends.includes(name); + }); + }); + + if (extendedBy.length) { + extendedBy.push(...extendedBy.flatMap(ref => getExtendedByList(ref, client))); + } + return extendedBy.filter(unique); +} diff --git a/src/utils/getExtendedFromList.ts b/src/utils/getExtendedFromList.ts new file mode 100644 index 00000000..b67a85cc --- /dev/null +++ b/src/utils/getExtendedFromList.ts @@ -0,0 +1,23 @@ +import { Client } from '../client/interfaces/Client'; +import { Model } from '../client/interfaces/Model'; +import { unique } from './unique'; + +/** + * Get the full list of models that are extended from the given model. + * This list is used when we have the flag "useUnionTypes" enabled. + * @param model + * @param client + */ +export function getExtendedFromList(model: Model, client: Client): Model[] { + const extendedFrom = client.models.filter(ref => { + const names = ref.isDefinition ? [ref.name] : ref.base.split(' | '); + return names.find(name => { + return model.extends.includes(name); + }); + }); + + if (extendedFrom.length) { + extendedFrom.push(...extendedFrom.flatMap(ref => getExtendedFromList(ref, client))); + } + return extendedFrom.filter(unique); +} diff --git a/src/utils/getModelNames.spec.ts b/src/utils/getModelNames.spec.ts index 478e9248..5769aef0 100644 --- a/src/utils/getModelNames.spec.ts +++ b/src/utils/getModelNames.spec.ts @@ -12,7 +12,7 @@ describe('getModelNames', () => { template: null, link: null, description: null, - isProperty: false, + isDefinition: true, isReadOnly: false, isRequired: false, isNullable: false, @@ -30,7 +30,7 @@ describe('getModelNames', () => { template: null, link: null, description: null, - isProperty: false, + isDefinition: true, isReadOnly: false, isRequired: false, isNullable: false, @@ -48,7 +48,7 @@ describe('getModelNames', () => { template: null, link: null, description: null, - isProperty: false, + isDefinition: true, isReadOnly: false, isRequired: false, isNullable: false, diff --git a/src/utils/getModelNames.ts b/src/utils/getModelNames.ts index 4cc86dfb..c53f2039 100644 --- a/src/utils/getModelNames.ts +++ b/src/utils/getModelNames.ts @@ -1,11 +1,6 @@ import { Model } from '../client/interfaces/Model'; +import { sort } from './sort'; export function getModelNames(models: Model[]): string[] { - return models - .map(model => model.name) - .sort((a, b) => { - const nameA = a.toLowerCase(); - const nameB = b.toLowerCase(); - return nameA.localeCompare(nameB, 'en'); - }); + return models.map(model => model.name).sort(sort); } diff --git a/src/utils/getOpenApiSpec.ts b/src/utils/getOpenApiSpec.ts index 709de0f9..a75f31d5 100644 --- a/src/utils/getOpenApiSpec.ts +++ b/src/utils/getOpenApiSpec.ts @@ -21,25 +21,26 @@ function read(filePath: string): string { * Load and parse te open api spec. If the file extension is ".yml" or ".yaml" * we will try to parse the file as a YAML spec, otherwise we will fallback * on parsing the file as JSON. - * @param filePath + * @param input */ -export function getOpenApiSpec(filePath: string): any { - const content = read(filePath); - const extname = path.extname(filePath).toLowerCase(); +export function getOpenApiSpec(input: string): any { + const file = path.resolve(process.cwd(), input); + const extname = path.extname(file).toLowerCase(); + const content = read(file); switch (extname) { case '.yml': case '.yaml': try { return yaml.safeLoad(content); } catch (e) { - throw new Error(`Could not parse OpenApi YAML: "${filePath}"`); + throw new Error(`Could not parse OpenApi YAML: "${file}"`); } default: try { return JSON.parse(content); } catch (e) { - throw new Error(`Could not parse OpenApi JSON: "${filePath}"`); + throw new Error(`Could not parse OpenApi JSON: "${file}"`); } } } diff --git a/src/utils/getServiceNames.ts b/src/utils/getServiceNames.ts index 6df0a1cf..f00197ad 100644 --- a/src/utils/getServiceNames.ts +++ b/src/utils/getServiceNames.ts @@ -1,11 +1,6 @@ import { Service } from '../client/interfaces/Service'; +import { sort } from './sort'; export function getServiceNames(services: Service[]): string[] { - return services - .map(service => service.name) - .sort((a, b) => { - const nameA = a.toLowerCase(); - const nameB = b.toLowerCase(); - return nameA.localeCompare(nameB, 'en'); - }); + return services.map(service => service.name).sort(sort); } diff --git a/src/utils/isString.ts b/src/utils/isString.ts new file mode 100644 index 00000000..4f5dd374 --- /dev/null +++ b/src/utils/isString.ts @@ -0,0 +1,3 @@ +export function isString(val: any): val is string { + return typeof val === 'string'; +} diff --git a/src/utils/postProcessClient.ts b/src/utils/postProcessClient.ts new file mode 100644 index 00000000..2ee9303c --- /dev/null +++ b/src/utils/postProcessClient.ts @@ -0,0 +1,16 @@ +import { Client } from '../client/interfaces/Client'; +import { postProcessModel } from './postProcessModel'; +import { postProcessService } from './postProcessService'; + +/** + * Post process client + * @param client Client object with all the models, services, etc. + * @param useUnionTypes Use inclusive union types. + */ +export function postProcessClient(client: Client, useUnionTypes: boolean): Client { + return { + ...client, + models: client.models.map(model => postProcessModel(model, client, useUnionTypes)), + services: client.services.map(service => postProcessService(service, client, useUnionTypes)), + }; +} diff --git a/src/utils/postProcessModel.ts b/src/utils/postProcessModel.ts new file mode 100644 index 00000000..ae002d37 --- /dev/null +++ b/src/utils/postProcessModel.ts @@ -0,0 +1,24 @@ +import { Client } from '../client/interfaces/Client'; +import { Model } from '../client/interfaces/Model'; +import { postProcessModelEnum } from './postProcessModelEnum'; +import { postProcessModelEnums } from './postProcessModelEnums'; +import { postProcessModelImports } from './postProcessModelImports'; +import { postProcessUnionTypes } from './postProcessUnionTypes'; + +/** + * Post process the model. If needed this will convert types to union types, + * see the "useUnionTypes" flag in the documentation. Plus this will cleanup + * any double imports or enum values. + * @param model + * @param client + * @param useUnionTypes + */ +export function postProcessModel(model: Model, client: Client, useUnionTypes: boolean): Model { + const clone = postProcessUnionTypes(model, client, useUnionTypes); + return { + ...clone, + imports: postProcessModelImports(clone), + enums: postProcessModelEnums(clone), + enum: postProcessModelEnum(clone), + }; +} diff --git a/src/utils/postProcessModelEnum.ts b/src/utils/postProcessModelEnum.ts new file mode 100644 index 00000000..ee367386 --- /dev/null +++ b/src/utils/postProcessModelEnum.ts @@ -0,0 +1,12 @@ +import { Enum } from '../client/interfaces/Enum'; +import { Model } from '../client/interfaces/Model'; + +/** + * Set unique enum values for the model + * @param model + */ +export function postProcessModelEnum(model: Model): Enum[] { + return model.enum.filter((property, index, arr) => { + return arr.findIndex(item => item.name === property.name) === index; + }); +} diff --git a/src/utils/postProcessModelEnums.ts b/src/utils/postProcessModelEnums.ts new file mode 100644 index 00000000..4ab3a787 --- /dev/null +++ b/src/utils/postProcessModelEnums.ts @@ -0,0 +1,11 @@ +import { Model } from '../client/interfaces/Model'; + +/** + * Set unique enum values for the model + * @param model The model that is post-processed + */ +export function postProcessModelEnums(model: Model): Model[] { + return model.enums.filter((property, index, arr) => { + return arr.findIndex(item => item.name === property.name) === index; + }); +} diff --git a/src/utils/postProcessModelImports.ts b/src/utils/postProcessModelImports.ts new file mode 100644 index 00000000..02252ec2 --- /dev/null +++ b/src/utils/postProcessModelImports.ts @@ -0,0 +1,14 @@ +import { Model } from '../client/interfaces/Model'; +import { sort } from './sort'; +import { unique } from './unique'; + +/** + * Set unique imports, sorted by name + * @param model The model that is post-processed + */ +export function postProcessModelImports(model: Model): string[] { + return model.imports + .filter(unique) + .sort(sort) + .filter(name => model.name !== name); +} diff --git a/src/utils/postProcessService.ts b/src/utils/postProcessService.ts new file mode 100644 index 00000000..b114a7de --- /dev/null +++ b/src/utils/postProcessService.ts @@ -0,0 +1,14 @@ +import { Client } from '../client/interfaces/Client'; +import { Service } from '../client/interfaces/Service'; +import { postProcessServiceImports } from './postProcessServiceImports'; +import { postProcessServiceOperations } from './postProcessServiceOperations'; + +export function postProcessService(service: Service, client: Client, useUnionTypes: boolean): Service { + const clone = { ...service }; + clone.operations = postProcessServiceOperations(clone, client, useUnionTypes); + clone.operations.forEach(operation => { + clone.imports.push(...operation.imports); + }); + clone.imports = postProcessServiceImports(clone); + return clone; +} diff --git a/src/utils/postProcessServiceImports.ts b/src/utils/postProcessServiceImports.ts new file mode 100644 index 00000000..adb15333 --- /dev/null +++ b/src/utils/postProcessServiceImports.ts @@ -0,0 +1,14 @@ +import { Service } from '../client/interfaces/Service'; +import { sort } from './sort'; +import { unique } from './unique'; + +/** + * Set unique imports, sorted by name + * @param service + */ +export function postProcessServiceImports(service: Service): string[] { + return service.imports + .filter(unique) + .sort(sort) + .filter(name => service.name !== name); +} diff --git a/src/utils/postProcessServiceOperations.ts b/src/utils/postProcessServiceOperations.ts new file mode 100644 index 00000000..05783a7c --- /dev/null +++ b/src/utils/postProcessServiceOperations.ts @@ -0,0 +1,30 @@ +import { Client } from '../client/interfaces/Client'; +import { Operation } from '../client/interfaces/Operation'; +import { Service } from '../client/interfaces/Service'; +import { postProcessUnionTypes } from './postProcessUnionTypes'; + +export function postProcessServiceOperations(service: Service, client: Client, useUnionTypes: boolean = false): Operation[] { + const names = new Map(); + + return service.operations.map(operation => { + const clone = { ...operation }; + + // Parse the service parameters and results, very similar to how we parse + // properties of models. These methods will extend the type if needed. + clone.parameters = clone.parameters.map(parameter => postProcessUnionTypes(parameter, client, useUnionTypes)); + clone.results = clone.results.map(result => postProcessUnionTypes(result, client, useUnionTypes)); + clone.imports.push(...clone.parameters.flatMap(parameter => parameter.imports)); + clone.imports.push(...clone.results.flatMap(result => result.imports)); + + // Check of the operation name + let name = clone.name; + const index = names.get(name) || 0; + if (index > 0) { + clone.name = `${name}${index}`; + name = `${name}${index}`; + } + names.set(name, index + 1); + + return clone; + }); +} diff --git a/src/utils/postProcessUnionTypes.ts b/src/utils/postProcessUnionTypes.ts new file mode 100644 index 00000000..f4c3b9ea --- /dev/null +++ b/src/utils/postProcessUnionTypes.ts @@ -0,0 +1,41 @@ +import { Client } from '../client/interfaces/Client'; +import { Model } from '../client/interfaces/Model'; +import { getExtendedByList } from './getExtendedByList'; + +/** + * This post processor will convert types to union types. For more information + * please check the documentation. In a nutshell: By setting the "useUnionTypes" + * flag we will convert base types to a union of types that are extended from + * the base type. + * @param model + * @param client + * @param useUnionTypes + */ +export function postProcessUnionTypes(model: T, client: Client, useUnionTypes: boolean): T { + const clone = { ...model }; + + if (useUnionTypes) { + // If this is not a root definition, then new need to check the base type + if (!clone.isDefinition) { + const extendedBy = getExtendedByList(clone, client); + const extendedByNames = extendedBy.map(m => m.name); + clone.base = [clone.base, ...extendedByNames].sort().join(' | '); + clone.imports = clone.imports.concat(...extendedByNames); + } + + // In any case we need to check the properties of a model. + // When the types get extended, we also need to make sure we update the imports. + clone.properties = clone.properties.map(property => postProcessUnionTypes(property, client, useUnionTypes)); + clone.properties.forEach(property => { + clone.imports.push(...property.imports); + }); + + // When the model has a link (in case of an Array or Dictionary), + // then we also process this linked model and again update the imports. + clone.link = clone.link ? postProcessUnionTypes(clone.link, client, useUnionTypes) : null; + if (clone.link) { + clone.imports.push(...clone.link.imports); + } + } + return clone; +} diff --git a/src/utils/readHandlebarsTemplate.ts b/src/utils/readHandlebarsTemplate.ts index e721f2f2..fa3ea1ec 100644 --- a/src/utils/readHandlebarsTemplate.ts +++ b/src/utils/readHandlebarsTemplate.ts @@ -12,6 +12,7 @@ export function readHandlebarsTemplate(filePath: string): Handlebars.TemplateDel .readFileSync(filePath, 'utf8') .toString() .trim(); + return Handlebars.compile(template, { strict: true, noEscape: true, diff --git a/src/utils/readHandlebarsTemplates.ts b/src/utils/readHandlebarsTemplates.ts index a5fc2af3..6e81efd0 100644 --- a/src/utils/readHandlebarsTemplates.ts +++ b/src/utils/readHandlebarsTemplates.ts @@ -31,7 +31,9 @@ export function readHandlebarsTemplates(): Templates { const partials = path.resolve(__dirname, `../../src/templates/partials`); const partialsFiles = glob.sync('*.hbs', { cwd: partials }); partialsFiles.forEach(partial => { - Handlebars.registerPartial(path.basename(partial, '.hbs'), readHandlebarsTemplate(path.resolve(partials, partial))); + const templateName = path.basename(partial, '.hbs'); + const template = readHandlebarsTemplate(path.resolve(partials, partial)); + Handlebars.registerPartial(templateName, template); }); return templates; diff --git a/src/utils/sort.ts b/src/utils/sort.ts new file mode 100644 index 00000000..9d41d840 --- /dev/null +++ b/src/utils/sort.ts @@ -0,0 +1,5 @@ +export function sort(a: string, b: string): number { + const nameA = a.toLowerCase(); + const nameB = b.toLowerCase(); + return nameA.localeCompare(nameB, 'en'); +} diff --git a/src/utils/unique.ts b/src/utils/unique.ts new file mode 100644 index 00000000..02ca1378 --- /dev/null +++ b/src/utils/unique.ts @@ -0,0 +1,3 @@ +export function unique(val: T, index: number, arr: T[]): boolean { + return arr.indexOf(val) === index; +} diff --git a/src/utils/writeClient.spec.ts b/src/utils/writeClient.spec.ts index 95d7bc28..a2ad0b57 100644 --- a/src/utils/writeClient.spec.ts +++ b/src/utils/writeClient.spec.ts @@ -36,7 +36,7 @@ describe('writeClient', () => { globSync.mockReturnValue([]); - writeClient(client, HttpClient.FETCH, templates, '/'); + writeClient(client, templates, '/', HttpClient.FETCH, false); expect(rimrafSync).toBeCalled(); expect(mkdirpSync).toBeCalled(); diff --git a/src/utils/writeClient.ts b/src/utils/writeClient.ts index 7da82915..bc209dea 100644 --- a/src/utils/writeClient.ts +++ b/src/utils/writeClient.ts @@ -15,12 +15,13 @@ import { writeClientSettings } from './writeClientSettings'; /** * Write our OpenAPI client, using the given templates at the given output path. * @param client Client object with all the models, services, etc. - * @param httpClient The selected httpClient (fetch or XHR). * @param templates Templates wrapper with all loaded Handlebars templates. - * @param outputPath Directory to write the generated files to. + * @param output Directory to write the generated files to. + * @param httpClient The selected httpClient (fetch or XHR). * @param useOptions Use options or arguments functions. */ -export function writeClient(client: Client, httpClient: HttpClient, templates: Templates, outputPath: string, useOptions: boolean): void { +export function writeClient(client: Client, templates: Templates, output: string, httpClient: HttpClient, useOptions: boolean): void { + const outputPath = path.resolve(process.cwd(), output); const outputPathCore = path.resolve(outputPath, 'core'); const outputPathModels = path.resolve(outputPath, 'models'); const outputPathSchemas = path.resolve(outputPath, 'schemas'); @@ -30,7 +31,7 @@ export function writeClient(client: Client, httpClient: HttpClient, templates: T try { rimraf.sync(outputPath); } catch (e) { - throw new Error(`Could not clean output directory`); + throw new Error('Could not clean output directory'); } // Create new directories @@ -41,11 +42,11 @@ export function writeClient(client: Client, httpClient: HttpClient, templates: T mkdirp.sync(outputPathSchemas); mkdirp.sync(outputPathServices); } catch (e) { - throw new Error(`Could not create output directories`); + throw new Error('Could not create output directories'); } // Copy all support files - const supportFiles = path.resolve(__dirname, `../../src/templates/`); + const supportFiles = path.resolve(__dirname, '../../src/templates/'); const supportFilesList = glob.sync('**/*.ts', { cwd: supportFiles }); supportFilesList.forEach(file => { fs.copyFileSync( @@ -58,6 +59,6 @@ export function writeClient(client: Client, httpClient: HttpClient, templates: T writeClientModels(client.models, templates, outputPathModels); writeClientSchemas(client.models, templates, outputPathSchemas); writeClientServices(client.services, templates, outputPathServices, useOptions); - writeClientSettings(client, httpClient, templates, outputPathCore); + writeClientSettings(client, templates, outputPathCore, httpClient); writeClientIndex(client, templates, outputPath); } diff --git a/src/utils/writeClientModels.spec.ts b/src/utils/writeClientModels.spec.ts index cedacb51..cb416e97 100644 --- a/src/utils/writeClientModels.spec.ts +++ b/src/utils/writeClientModels.spec.ts @@ -9,25 +9,26 @@ const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction { it('should write to filesystem', () => { - const models: Model[] = []; - models.push({ - export: 'interface', - name: 'Item', - type: 'Item', - base: 'Item', - template: null, - link: null, - description: null, - isProperty: false, - isReadOnly: false, - isRequired: false, - isNullable: false, - imports: [], - extends: [], - enum: [], - enums: [], - properties: [], - }); + const models: Model[] = [ + { + export: 'interface', + name: 'Item', + type: 'Item', + base: 'Item', + template: null, + link: null, + description: null, + isDefinition: true, + isReadOnly: false, + isRequired: false, + isNullable: false, + imports: [], + extends: [], + enum: [], + enums: [], + properties: [], + }, + ]; const templates: Templates = { index: () => 'dummy', diff --git a/src/utils/writeClientModels.ts b/src/utils/writeClientModels.ts index ddf0004e..40369e08 100644 --- a/src/utils/writeClientModels.ts +++ b/src/utils/writeClientModels.ts @@ -2,7 +2,6 @@ import * as fs from 'fs'; import * as path from 'path'; import { Model } from '../client/interfaces/Model'; import { Templates } from './readHandlebarsTemplates'; -import { exportModel } from './exportModel'; import { format } from './format'; /** @@ -14,8 +13,7 @@ import { format } from './format'; export function writeClientModels(models: Model[], templates: Templates, outputPath: string): void { models.forEach(model => { const file = path.resolve(outputPath, `${model.name}.ts`); - const templateData = exportModel(model); - const templateResult = templates.model(templateData); + const templateResult = templates.model(model); fs.writeFileSync(file, format(templateResult)); }); } diff --git a/src/utils/writeClientSchemas.spec.ts b/src/utils/writeClientSchemas.spec.ts index cedacb51..cb416e97 100644 --- a/src/utils/writeClientSchemas.spec.ts +++ b/src/utils/writeClientSchemas.spec.ts @@ -9,25 +9,26 @@ const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction { it('should write to filesystem', () => { - const models: Model[] = []; - models.push({ - export: 'interface', - name: 'Item', - type: 'Item', - base: 'Item', - template: null, - link: null, - description: null, - isProperty: false, - isReadOnly: false, - isRequired: false, - isNullable: false, - imports: [], - extends: [], - enum: [], - enums: [], - properties: [], - }); + const models: Model[] = [ + { + export: 'interface', + name: 'Item', + type: 'Item', + base: 'Item', + template: null, + link: null, + description: null, + isDefinition: true, + isReadOnly: false, + isRequired: false, + isNullable: false, + imports: [], + extends: [], + enum: [], + enums: [], + properties: [], + }, + ]; const templates: Templates = { index: () => 'dummy', diff --git a/src/utils/writeClientSchemas.ts b/src/utils/writeClientSchemas.ts index 7ce3a8b7..493361f7 100644 --- a/src/utils/writeClientSchemas.ts +++ b/src/utils/writeClientSchemas.ts @@ -2,7 +2,6 @@ import * as fs from 'fs'; import * as path from 'path'; import { Model } from '../client/interfaces/Model'; import { Templates } from './readHandlebarsTemplates'; -import { exportModel } from './exportModel'; import { format } from './format'; /** @@ -14,8 +13,7 @@ import { format } from './format'; export function writeClientSchemas(models: Model[], templates: Templates, outputPath: string): void { models.forEach(model => { const file = path.resolve(outputPath, `$${model.name}.ts`); - const templateData = exportModel(model); - const templateResult = templates.schema(templateData); + const templateResult = templates.schema(model); fs.writeFileSync(file, format(templateResult)); }); } diff --git a/src/utils/writeClientServices.spec.ts b/src/utils/writeClientServices.spec.ts index e7e5e2db..6809c498 100644 --- a/src/utils/writeClientServices.spec.ts +++ b/src/utils/writeClientServices.spec.ts @@ -9,12 +9,13 @@ const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction { it('should write to filesystem', () => { - const services: Service[] = []; - services.push({ - name: 'Item', - operations: [], - imports: [], - }); + const services: Service[] = [ + { + name: 'Item', + operations: [], + imports: [], + }, + ]; const templates: Templates = { index: () => 'dummy', @@ -24,7 +25,7 @@ describe('writeClientServices', () => { settings: () => 'dummy', }; - writeClientServices(services, templates, '/'); + writeClientServices(services, templates, '/', false); expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy'); }); diff --git a/src/utils/writeClientServices.ts b/src/utils/writeClientServices.ts index 486d59ae..dc65ff9a 100644 --- a/src/utils/writeClientServices.ts +++ b/src/utils/writeClientServices.ts @@ -2,7 +2,6 @@ import * as fs from 'fs'; import * as path from 'path'; import { Service } from '../client/interfaces/Service'; import { Templates } from './readHandlebarsTemplates'; -import { exportService } from './exportService'; import { format } from './format'; /** @@ -15,9 +14,8 @@ import { format } from './format'; export function writeClientServices(services: Service[], templates: Templates, outputPath: string, useOptions: boolean): void { services.forEach(service => { const file = path.resolve(outputPath, `${service.name}.ts`); - const templateData = exportService(service); const templateResult = templates.service({ - ...templateData, + ...service, useOptions, }); fs.writeFileSync(file, format(templateResult)); diff --git a/src/utils/writeClientSettings.ts b/src/utils/writeClientSettings.ts index f538f481..fb2d6c81 100644 --- a/src/utils/writeClientSettings.ts +++ b/src/utils/writeClientSettings.ts @@ -4,7 +4,14 @@ import { Client } from '../client/interfaces/Client'; import { HttpClient } from '../index'; import { Templates } from './readHandlebarsTemplates'; -export function writeClientSettings(client: Client, httpClient: HttpClient, templates: Templates, outputPath: string): void { +/** + * Generate OpenAPI configuration file "OpenAPI.ts" + * @param client Client object, containing, models, schemas and services. + * @param templates The loaded handlebar templates. + * @param outputPath Directory to write the generated files to. + * @param httpClient The selected httpClient (fetch or XHR). + */ +export function writeClientSettings(client: Client, templates: Templates, outputPath: string, httpClient: HttpClient): void { fs.writeFileSync( path.resolve(outputPath, 'OpenAPI.ts'), templates.settings({ diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 3c061e72..904967bc 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -67,12 +67,19 @@ exports[`generation v2 file(./test/result/v2/core/OpenAPI.ts): ./test/result/v2/ /* eslint-disable */ /* prettier-ignore */ -export namespace OpenAPI { - export let BASE = 'http://localhost:8080/api'; - export let VERSION = '9.0'; - export let CLIENT = 'fetch'; - export let TOKEN = ''; -}" +interface Config { + BASE: string; + VERSION: string; + CLIENT: 'fetch' | 'xhr'; + TOKEN: string; +} + +export const OpenAPI: Config = { + BASE: 'http://localhost:8080/api', + VERSION: '9.0', + CLIENT: 'fetch', + TOKEN: '', +};" `; exports[`generation v2 file(./test/result/v2/core/RequestOptions.ts): ./test/result/v2/core/RequestOptions.ts 1`] = ` @@ -520,12 +527,14 @@ exports[`generation v2 file(./test/result/v2/models/ArrayWithArray.ts): ./test/r /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a simple array containing an array */ -export type ArrayWithArray = Array>;" +export type ArrayWithArray = Array>;" `; exports[`generation v2 file(./test/result/v2/models/ArrayWithBooleans.ts): ./test/result/v2/models/ArrayWithBooleans.ts 1`] = ` @@ -616,12 +625,14 @@ exports[`generation v2 file(./test/result/v2/models/DictionaryWithArray.ts): ./t /* prettier-ignore */ import { Dictionary } from './Dictionary'; +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a complex dictionary */ -export type DictionaryWithArray = Dictionary>;" +export type DictionaryWithArray = Dictionary>;" `; exports[`generation v2 file(./test/result/v2/models/DictionaryWithDictionary.ts): ./test/result/v2/models/DictionaryWithDictionary.ts 1`] = ` @@ -783,6 +794,7 @@ exports[`generation v2 file(./test/result/v2/models/ModelThatExtends.ts): ./test /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** @@ -790,7 +802,7 @@ import { ModelWithString } from './ModelWithString'; */ export interface ModelThatExtends extends ModelWithString { propExtendsA?: string; - propExtendsB?: ModelWithString; + propExtendsB?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -809,7 +821,7 @@ import { ModelWithString } from './ModelWithString'; */ export interface ModelThatExtendsExtends extends ModelWithString, ModelThatExtends { propExtendsC?: string; - propExtendsD?: ModelWithString; + propExtendsD?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -820,13 +832,15 @@ exports[`generation v2 file(./test/result/v2/models/ModelWithArray.ts): ./test/r /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a model with one property containing an array */ export interface ModelWithArray { - prop?: Array; + prop?: Array; propWithFile?: Array; propWithNumber?: Array; } @@ -891,15 +905,17 @@ exports[`generation v2 file(./test/result/v2/models/ModelWithDuplicateImports.ts /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a model with duplicated imports */ export interface ModelWithDuplicateImports { - propA?: ModelWithString; - propB?: ModelWithString; - propC?: ModelWithString; + propA?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; + propB?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; + propC?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -910,13 +926,15 @@ exports[`generation v2 file(./test/result/v2/models/ModelWithDuplicateProperties /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a model with duplicated properties */ export interface ModelWithDuplicateProperties { - prop?: ModelWithString; + prop?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -1088,6 +1106,8 @@ exports[`generation v2 file(./test/result/v2/models/ModelWithProperties.ts): ./t /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** @@ -1099,7 +1119,7 @@ export interface ModelWithProperties { string?: string; number?: number; boolean?: boolean; - reference?: ModelWithString; + reference?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -1417,7 +1437,7 @@ export const $ModelThatExtends = { type: 'string', }, propExtendsB: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -1440,7 +1460,7 @@ export const $ModelThatExtendsExtends = { type: 'string', }, propExtendsD: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -1521,13 +1541,13 @@ exports[`generation v2 file(./test/result/v2/schemas/$ModelWithDuplicateImports. export const $ModelWithDuplicateImports = { properties: { propA: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, propB: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, propC: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -1542,7 +1562,7 @@ exports[`generation v2 file(./test/result/v2/schemas/$ModelWithDuplicateProperti export const $ModelWithDuplicateProperties = { properties: { prop: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -1709,7 +1729,7 @@ export const $ModelWithProperties = { type: 'boolean', }, reference: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -1817,6 +1837,8 @@ exports[`generation v2 file(./test/result/v2/services/ComplexService.ts): ./test /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from '../models/ModelThatExtends'; +import { ModelThatExtendsExtends } from '../models/ModelThatExtendsExtends'; import { ModelWithString } from '../models/ModelWithString'; import { ApiError, catchGenericError } from '../core/ApiError'; import { request as __request } from '../core/request'; @@ -1838,8 +1860,8 @@ export class ComplexService { }, }, }, - parameterReference: ModelWithString, - ): Promise> { + parameterReference: ModelThatExtends | ModelThatExtendsExtends | ModelWithString, + ): Promise> { const result = await __request({ method: 'get', @@ -1871,6 +1893,8 @@ exports[`generation v2 file(./test/result/v2/services/DefaultsService.ts): ./tes /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from '../models/ModelThatExtends'; +import { ModelThatExtendsExtends } from '../models/ModelThatExtendsExtends'; import { ModelWithString } from '../models/ModelWithString'; import { ApiError, catchGenericError } from '../core/ApiError'; import { request as __request } from '../core/request'; @@ -1891,7 +1915,7 @@ export class DefaultsService { parameterNumber: number = 123, parameterBoolean: boolean = true, parameterEnum: ('Success' | 'Warning' | 'Error') = 'Success', - parameterModel: ModelWithString = { + parameterModel: ModelThatExtends | ModelThatExtendsExtends | ModelWithString = { \\"prop\\": \\"Hello World\\" }, ): Promise { @@ -2024,7 +2048,7 @@ export class ResponseService { * @result ModelWithString Message for default response * @throws ApiError */ - public static async callWithResponse(): Promise { + public static async callWithResponse(): Promise { const result = await __request({ method: 'get', @@ -2040,7 +2064,7 @@ export class ResponseService { * @result ModelWithString Message for default response * @throws ApiError */ - public static async callWithDuplicateResponses(): Promise { + public static async callWithDuplicateResponses(): Promise { const result = await __request({ method: 'post', @@ -2066,7 +2090,7 @@ export class ResponseService { * @result ModelThatExtendsExtends Message for 202 response * @throws ApiError */ - public static async callWithResponses(): Promise { + public static async callWithResponses(): Promise { const result = await __request({ method: 'put', @@ -2337,12 +2361,19 @@ exports[`generation v3 file(./test/result/v3/core/OpenAPI.ts): ./test/result/v3/ /* eslint-disable */ /* prettier-ignore */ -export namespace OpenAPI { - export let BASE = '/api'; - export let VERSION = '1'; - export let CLIENT = 'fetch'; - export let TOKEN = ''; -}" +interface Config { + BASE: string; + VERSION: string; + CLIENT: 'fetch' | 'xhr'; + TOKEN: string; +} + +export const OpenAPI: Config = { + BASE: '/api', + VERSION: '1', + CLIENT: 'fetch', + TOKEN: '', +};" `; exports[`generation v3 file(./test/result/v3/core/RequestOptions.ts): ./test/result/v3/core/RequestOptions.ts 1`] = ` @@ -2796,12 +2827,14 @@ exports[`generation v3 file(./test/result/v3/models/ArrayWithArray.ts): ./test/r /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a simple array containing an array */ -export type ArrayWithArray = Array>;" +export type ArrayWithArray = Array>;" `; exports[`generation v3 file(./test/result/v3/models/ArrayWithBooleans.ts): ./test/result/v3/models/ArrayWithBooleans.ts 1`] = ` @@ -2892,12 +2925,14 @@ exports[`generation v3 file(./test/result/v3/models/DictionaryWithArray.ts): ./t /* prettier-ignore */ import { Dictionary } from './Dictionary'; +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a complex dictionary */ -export type DictionaryWithArray = Dictionary>;" +export type DictionaryWithArray = Dictionary>;" `; exports[`generation v3 file(./test/result/v3/models/DictionaryWithDictionary.ts): ./test/result/v3/models/DictionaryWithDictionary.ts 1`] = ` @@ -3059,6 +3094,7 @@ exports[`generation v3 file(./test/result/v3/models/ModelThatExtends.ts): ./test /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** @@ -3066,7 +3102,7 @@ import { ModelWithString } from './ModelWithString'; */ export interface ModelThatExtends extends ModelWithString { propExtendsA?: string; - propExtendsB?: ModelWithString; + propExtendsB?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -3085,7 +3121,7 @@ import { ModelWithString } from './ModelWithString'; */ export interface ModelThatExtendsExtends extends ModelWithString, ModelThatExtends { propExtendsC?: string; - propExtendsD?: ModelWithString; + propExtendsD?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -3096,6 +3132,8 @@ exports[`generation v3 file(./test/result/v3/models/ModelWithAnyOf.ts): ./test/r /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithArray } from './ModelWithArray'; import { ModelWithDictionary } from './ModelWithDictionary'; import { ModelWithEnum } from './ModelWithEnum'; @@ -3105,7 +3143,7 @@ import { ModelWithString } from './ModelWithString'; * This is a model with one property with a 'any of' relationship */ export interface ModelWithAnyOf { - propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; + propA?: ModelThatExtends | ModelThatExtendsExtends | ModelWithArray | ModelWithDictionary | ModelWithEnum | ModelWithString; } " `; @@ -3116,13 +3154,15 @@ exports[`generation v3 file(./test/result/v3/models/ModelWithArray.ts): ./test/r /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a model with one property containing an array */ export interface ModelWithArray { - prop?: Array; + prop?: Array; propWithFile?: Array; propWithNumber?: Array; } @@ -3187,15 +3227,17 @@ exports[`generation v3 file(./test/result/v3/models/ModelWithDuplicateImports.ts /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a model with duplicated imports */ export interface ModelWithDuplicateImports { - propA?: ModelWithString; - propB?: ModelWithString; - propC?: ModelWithString; + propA?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; + propB?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; + propC?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -3206,13 +3248,15 @@ exports[`generation v3 file(./test/result/v3/models/ModelWithDuplicateProperties /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** * This is a model with duplicated properties */ export interface ModelWithDuplicateProperties { - prop?: ModelWithString; + prop?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -3366,6 +3410,8 @@ exports[`generation v3 file(./test/result/v3/models/ModelWithOneOf.ts): ./test/r /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithArray } from './ModelWithArray'; import { ModelWithDictionary } from './ModelWithDictionary'; import { ModelWithEnum } from './ModelWithEnum'; @@ -3375,7 +3421,7 @@ import { ModelWithString } from './ModelWithString'; * This is a model with one property with a 'one of' relationship */ export interface ModelWithOneOf { - propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; + propA?: ModelThatExtends | ModelThatExtendsExtends | ModelWithArray | ModelWithDictionary | ModelWithEnum | ModelWithString; } " `; @@ -3404,6 +3450,8 @@ exports[`generation v3 file(./test/result/v3/models/ModelWithProperties.ts): ./t /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from './ModelThatExtends'; +import { ModelThatExtendsExtends } from './ModelThatExtendsExtends'; import { ModelWithString } from './ModelWithString'; /** @@ -3416,7 +3464,7 @@ export interface ModelWithProperties { string?: string; number?: number; boolean?: boolean; - reference?: ModelWithString; + reference?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString; } " `; @@ -3734,7 +3782,7 @@ export const $ModelThatExtends = { type: 'string', }, propExtendsB: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -3757,7 +3805,7 @@ export const $ModelThatExtendsExtends = { type: 'string', }, propExtendsD: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -3772,7 +3820,7 @@ exports[`generation v3 file(./test/result/v3/schemas/$ModelWithAnyOf.ts): ./test export const $ModelWithAnyOf = { properties: { propA: { - type: 'ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithArray | ModelWithDictionary | ModelWithEnum | ModelWithString', }, }, };" @@ -3853,13 +3901,13 @@ exports[`generation v3 file(./test/result/v3/schemas/$ModelWithDuplicateImports. export const $ModelWithDuplicateImports = { properties: { propA: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, propB: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, propC: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -3874,7 +3922,7 @@ exports[`generation v3 file(./test/result/v3/schemas/$ModelWithDuplicateProperti export const $ModelWithDuplicateProperties = { properties: { prop: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -4005,7 +4053,7 @@ exports[`generation v3 file(./test/result/v3/schemas/$ModelWithOneOf.ts): ./test export const $ModelWithOneOf = { properties: { propA: { - type: 'ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithArray | ModelWithDictionary | ModelWithEnum | ModelWithString', }, }, };" @@ -4064,7 +4112,7 @@ export const $ModelWithProperties = { type: 'boolean', }, reference: { - type: 'ModelWithString', + type: 'ModelThatExtends | ModelThatExtendsExtends | ModelWithString', }, }, };" @@ -4172,6 +4220,8 @@ exports[`generation v3 file(./test/result/v3/services/ComplexService.ts): ./test /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from '../models/ModelThatExtends'; +import { ModelThatExtendsExtends } from '../models/ModelThatExtendsExtends'; import { ModelWithArray } from '../models/ModelWithArray'; import { ModelWithDictionary } from '../models/ModelWithDictionary'; import { ModelWithEnum } from '../models/ModelWithEnum'; @@ -4188,10 +4238,7 @@ export class ComplexService { * @result ModelWithString Successful response * @throws ApiError */ - public static async complexTypes({ - parameterObject, - parameterReference, - }: { + public static async complexTypes( parameterObject: { first?: { second?: { @@ -4199,8 +4246,8 @@ export class ComplexService { }, }, }, - parameterReference: ModelWithString, - }): Promise> { + parameterReference: ModelThatExtends | ModelThatExtendsExtends | ModelWithString, + ): Promise> { const result = await __request({ method: 'get', @@ -4229,25 +4276,22 @@ export class ComplexService { * @result ModelWithString Success * @throws ApiError */ - public static async complexParams({ - id, - requestBody, - }: { + public static async complexParams( id: number, requestBody?: { readonly key: string | null, name: string | null, enabled?: boolean, readonly type: ('Monkey' | 'Horse' | 'Bird'), - listOfModels?: Array | null, + listOfModels?: Array | null, listOfStrings?: Array | null, - parameters: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary, + parameters: ModelThatExtends | ModelThatExtendsExtends | ModelWithArray | ModelWithDictionary | ModelWithEnum | ModelWithString, readonly user?: { readonly id?: number, readonly name?: string | null, }, }, - }): Promise { + ): Promise { const result = await __request({ method: 'put', @@ -4269,6 +4313,8 @@ exports[`generation v3 file(./test/result/v3/services/DefaultsService.ts): ./tes /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from '../models/ModelThatExtends'; +import { ModelThatExtendsExtends } from '../models/ModelThatExtendsExtends'; import { ModelWithString } from '../models/ModelWithString'; import { ApiError, catchGenericError } from '../core/ApiError'; import { request as __request } from '../core/request'; @@ -4284,21 +4330,15 @@ export class DefaultsService { * @param parameterModel This is a simple model * @throws ApiError */ - public static async callWithDefaultParameters({ - parameterString = 'Hello World!', - parameterNumber = 123, - parameterBoolean = true, - parameterEnum = 'Success', - parameterModel = { + public static async callWithDefaultParameters( + parameterString: string | null = 'Hello World!', + parameterNumber: number | null = 123, + parameterBoolean: boolean | null = true, + parameterEnum: ('Success' | 'Warning' | 'Error') = 'Success', + parameterModel: ModelThatExtends | ModelThatExtendsExtends | ModelWithString | null = { \\"prop\\": \\"Hello World\\" }, - }: { - parameterString: string | null, - parameterNumber: number | null, - parameterBoolean: boolean | null, - parameterEnum: ('Success' | 'Warning' | 'Error'), - parameterModel: ModelWithString | null, - }): Promise { + ): Promise { const result = await __request({ method: 'get', @@ -4363,6 +4403,8 @@ exports[`generation v3 file(./test/result/v3/services/ParametersService.ts): ./t /* eslint-disable */ /* prettier-ignore */ +import { ModelThatExtends } from '../models/ModelThatExtends'; +import { ModelThatExtendsExtends } from '../models/ModelThatExtendsExtends'; import { ModelWithString } from '../models/ModelWithString'; import { ApiError, catchGenericError } from '../core/ApiError'; import { request as __request } from '../core/request'; @@ -4378,19 +4420,13 @@ export class ParametersService { * @param requestBody This is the parameter that goes into the body * @throws ApiError */ - public static async callWithParameters({ - parameterHeader, - parameterQuery, - parameterForm, - parameterCookie, - requestBody, - }: { + public static async callWithParameters( parameterHeader: string | null, parameterQuery: string | null, parameterForm: string | null, parameterCookie: string | null, - requestBody: ModelWithString | null, - }): Promise { + requestBody: ModelThatExtends | ModelThatExtendsExtends | ModelWithString | null, + ): Promise { const result = await __request({ method: 'get', @@ -4426,25 +4462,16 @@ export class ParametersService { * @param parameterPath3 This is the parameter that goes into the path * @throws ApiError */ - public static async callWithWeirdParameterNames({ - parameterHeader, - parameterQuery, - parameterForm, - parameterCookie, - requestBody, - parameterPath1, - parameterPath2, - parameterPath3, - }: { + public static async callWithWeirdParameterNames( parameterHeader: string | null, parameterQuery: string | null, parameterForm: string | null, parameterCookie: string | null, - requestBody: ModelWithString | null, + requestBody: ModelThatExtends | ModelThatExtendsExtends | ModelWithString | null, parameterPath1?: string, parameterPath2?: string, parameterPath3?: string, - }): Promise { + ): Promise { const result = await __request({ method: 'get', @@ -4474,13 +4501,10 @@ export class ParametersService { * @param parameter This is an optional parameter * @throws ApiError */ - public static async getCallWithOptionalParam({ - requestBody, - parameter, - }: { - requestBody: ModelWithString, + public static async getCallWithOptionalParam( + requestBody: ModelThatExtends | ModelThatExtendsExtends | ModelWithString, parameter?: string, - }): Promise { + ): Promise { const result = await __request({ method: 'get', @@ -4501,13 +4525,10 @@ export class ParametersService { * @param requestBody This is an optional parameter * @throws ApiError */ - public static async postCallWithOptionalParam({ - parameter, - requestBody, - }: { + public static async postCallWithOptionalParam( parameter: string, - requestBody?: ModelWithString, - }): Promise { + requestBody?: ModelThatExtends | ModelThatExtendsExtends | ModelWithString, + ): Promise { const result = await __request({ method: 'post', @@ -4545,7 +4566,7 @@ export class ResponseService { * @result ModelWithString * @throws ApiError */ - public static async callWithResponse(): Promise { + public static async callWithResponse(): Promise { const result = await __request({ method: 'get', @@ -4561,7 +4582,7 @@ export class ResponseService { * @result ModelWithString Message for default response * @throws ApiError */ - public static async callWithDuplicateResponses(): Promise { + public static async callWithDuplicateResponses(): Promise { const result = await __request({ method: 'post', @@ -4587,7 +4608,7 @@ export class ResponseService { * @result ModelThatExtendsExtends Message for 202 response * @throws ApiError */ - public static async callWithResponses(): Promise { + public static async callWithResponses(): Promise { const result = await __request({ method: 'put', @@ -4757,25 +4778,16 @@ export class TypesService { * @result any Response is a simple object * @throws ApiError */ - public static async types({ - parameterNumber = 123, - parameterString = 'default', - parameterBoolean = true, - parameterObject = null, - parameterArray, - parameterDictionary, - parameterEnum, - id, - }: { - parameterNumber: number, - parameterString: string | null, - parameterBoolean: boolean | null, - parameterObject: any, + public static async types( + parameterNumber: number = 123, + parameterString: string | null = 'default', + parameterBoolean: boolean | null = true, + parameterObject: any = null, parameterArray: Array | null, parameterDictionary: any, parameterEnum: ('Success' | 'Warning' | 'Error') | null, id?: number, - }): Promise { + ): Promise { const result = await __request({ method: 'get', @@ -4816,11 +4828,9 @@ export class UploadService { * @result boolean * @throws ApiError */ - public static async uploadFile({ - file, - }: { + public static async uploadFile( file: File, - }): Promise { + ): Promise { const result = await __request({ method: 'post', diff --git a/test/index.js b/test/index.js index 4211b93d..3e37a8db 100644 --- a/test/index.js +++ b/test/index.js @@ -1,18 +1,38 @@ +const path = require('path'); +const ts = require('typescript'); const OpenAPI = require('../dist'); -OpenAPI.generate( - './test/mock/v2/spec.json', - './test/result/v2/', - OpenAPI.HttpClient.FETCH, - false, -); +function compile(dir) { + const config = { + compilerOptions: { + target: 'esnext', + module: 'commonjs', + moduleResolution: 'node', + }, + include: ['./index.ts'], + }; + const configFile = ts.parseConfigFileTextToJson('tsconfig.json', JSON.stringify(config)); + const configFileResult = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.resolve(process.cwd(), dir), undefined, 'tsconfig.json'); + const compilerHost = ts.createCompilerHost(configFileResult.options); + const compiler = ts.createProgram(configFileResult.fileNames, configFileResult.options, compilerHost); + compiler.emit(); +} -OpenAPI.generate( - './test/mock/v3/spec.json', - './test/result/v3/', - OpenAPI.HttpClient.FETCH, - true, -); +OpenAPI.generate({ + input: './test/mock/v2/spec.json', + output: './test/result/v2/', + httpClient: OpenAPI.HttpClient.FETCH, + useOptions: false, + useUnionTypes: false, +}); -OpenAPI.compile('./test/result/v2/'); -OpenAPI.compile('./test/result/v3/'); +OpenAPI.generate({ + input: './test/mock/v3/spec.json', + output: './test/result/v3/', + httpClient: OpenAPI.HttpClient.FETCH, + useOptions: false, + useUnionTypes: false, +}); + +compile('./test/result/v2/'); +compile('./test/result/v3/'); diff --git a/test/index.spec.js b/test/index.spec.js index 4a35fe1e..02d9cd69 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -6,12 +6,12 @@ describe('generation', () => { describe('v2', () => { - OpenAPI.generate( - './test/mock/v2/spec.json', - './test/result/v2/', - OpenAPI.HttpClient.FETCH, - false, - ); + OpenAPI.generate({ + input: './test/mock/v2/spec.json', + output: './test/result/v2/', + httpClient: OpenAPI.HttpClient.FETCH, + write: false, + }); test.each(glob .sync('./test/result/v2/**/*.ts') @@ -24,12 +24,12 @@ describe('generation', () => { describe('v3', () => { - OpenAPI.generate( - './test/mock/v3/spec.json', - './test/result/v3/', - OpenAPI.HttpClient.FETCH, - true, - ); + OpenAPI.generate({ + input: './test/mock/v3/spec.json', + output: './test/result/v3/', + httpClient: OpenAPI.HttpClient.FETCH, + write: false, + }); test.each(glob .sync('./test/result/v3/**/*.ts') diff --git a/tslint.json b/tslint.json deleted file mode 100644 index dfd79f4a..00000000 --- a/tslint.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "extends": [ - "tslint:recommended", - "tslint-config-airbnb" - ], - "rules": { - "align": false, - "import-name": false, - "ordered-imports": true, - "object-literal-sort-keys": false, - "no-boolean-literal-compare": false, - "no-increment-decrement": false, - "no-unused-variable": false, - "no-namespace": false, - "no-console": false, - "no-bitwise": false, - "no-var-requires": false, - "radix": false, - "member-access": true, - "max-line-length": [false], - "array-type": [true, "array"], - "arrow-parens": [true, "ban-single-arg-parens"], - "ter-arrow-parens": [true, "as-needed"], - "no-submodule-imports": [true], - "function-name": [true, { - "function-regex": "^[a-zA-Z$][\\w\\d]*$", - "method-regex": "^[a-z$][\\w\\d]*$", - "private-method-regex": "^[a-z$][\\w\\d]*$", - "protected-method-regex": "^[a-z$][\\w\\d]*$", - "static-method-regex": "^[a-z$][\\w\\d]*$" - }], - "interface-name": [ - true, - "never-prefix" - ], - "variable-name": [ - true, - "ban-keywords", - "check-format", - "allow-pascal-case", - "allow-leading-underscore" - ], - "typedef": [ - true, - "call-signature", - "parameter", - "property-declaration", - "member-variable-declaration" - ], - "naming-convention": [true, { - "type": "enumMember", - "format": "UPPER_CASE" - }], - "ter-indent": [true, 4, { - "SwitchCase": 1 - }], - "jsx-no-lambda": false, - "jsx-alignment": false, - "jsx-wrap-multiline": false, - "jsx-no-multiline-js": false - } -} diff --git a/yarn.lock b/yarn.lock index 0c15f9d5..ff686128 100644 --- a/yarn.lock +++ b/yarn.lock @@ -85,22 +85,23 @@ semver "^5.5.0" "@babel/helper-create-class-features-plugin@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz#5b94be88c255f140fd2c10dd151e7f98f4bff397" - integrity sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz#243a5b46e2f8f0f674dc1387631eb6b28b851de0" + integrity sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg== dependencies: "@babel/helper-function-name" "^7.8.3" "@babel/helper-member-expression-to-functions" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-split-export-declaration" "^7.8.3" "@babel/helper-create-regexp-features-plugin@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" - integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz#7fa040c97fb8aebe1247a5c645330c32d083066b" + integrity sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A== dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-regex" "^7.8.3" regexpu-core "^4.6.0" @@ -159,15 +160,16 @@ "@babel/types" "^7.8.3" "@babel/helper-module-transforms@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" - integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz#6a13b5eecadc35692047073a64e42977b97654a4" + integrity sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg== dependencies: "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-simple-access" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.8.6" lodash "^4.17.13" "@babel/helper-optimise-call-expression@^7.8.3": @@ -200,17 +202,7 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-replace-supers@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" - integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-replace-supers@^7.8.6": +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== @@ -1153,7 +1145,7 @@ acorn-globals@^4.3.2: acorn "^6.0.1" acorn-walk "^6.0.1" -acorn-jsx@^5.1.0: +acorn-jsx@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== @@ -1169,9 +1161,9 @@ acorn@^6.0.1: integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== acorn@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" - integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== + version "7.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" + integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== agent-base@5: version "5.1.1" @@ -1196,11 +1188,11 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: uri-js "^4.2.2" ansi-escapes@^4.2.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d" - integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg== + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== dependencies: - type-fest "^0.8.1" + type-fest "^0.11.0" ansi-regex@^4.1.0: version "4.1.0" @@ -1438,13 +1430,13 @@ browser-resolve@^1.11.3: resolve "1.1.7" browserslist@^4.8.3, browserslist@^4.8.5: - version "4.8.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.7.tgz#ec8301ff415e6a42c949d0e66b405eb539c532d0" - integrity sha512-gFOnZNYBHrEyUML0xr5NJ6edFaaKbTFX9S9kQHlYfCP0Rit/boRIz4G+Avq6/4haEKJXdGGUnoolx+5MWW2BoA== + version "4.9.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.9.1.tgz#01ffb9ca31a1aef7678128fc6a2253316aa7287c" + integrity sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw== dependencies: - caniuse-lite "^1.0.30001027" - electron-to-chromium "^1.3.349" - node-releases "^1.1.49" + caniuse-lite "^1.0.30001030" + electron-to-chromium "^1.3.363" + node-releases "^1.1.50" bser@2.1.1: version "2.1.1" @@ -1483,10 +1475,10 @@ camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001027: - version "1.0.30001030" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001030.tgz#78076c4c6d67d3e41d6eb9399853fb27fe6e44ee" - integrity sha512-QGK0W4Ft/Ac+zTjEiRJfwDNATvS3fodDczBXrH42784kcfqcDKpEPfN08N0HQjrAp8He/Jw8QiSS9QRn7XAbUw== +caniuse-lite@^1.0.30001030: + version "1.0.30001031" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001031.tgz#76f1bdd39e19567b855302f65102d9a8aaad5930" + integrity sha512-DpAP5a1NGRLgYfaNCaXIRyGARi+3tJA2quZXNNA1Du26VyVkqvy2tznNu5ANyN1Y5aX44QDotZSVSUSi2uMGjg== capture-exit@^2.0.0: version "2.0.0" @@ -1500,7 +1492,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.1.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1811,10 +1803,10 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -electron-to-chromium@^1.3.349: - version "1.3.361" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.361.tgz#a820bf52da171c0024314745462cfe0dc944373e" - integrity sha512-OzSVjWpsRhJyr9PSAXkeloSe6e9viU2ToGt1wXlXFsGcxuI9vlsnalL+V/AM59Z2pEo3wRxIddtOGsT7Y6x/sQ== +electron-to-chromium@^1.3.363: + version "1.3.367" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.367.tgz#48abffcaa6591051b612ae70ddc657763ede2662" + integrity sha512-GCHQreWs4zhKA48FNXCjvpV4kTnKoLu2PSAfKX394g34NPvTs2pPh1+jzWitNwhmOYI8zIqt36ulRVRZUgqlfA== emoji-regex@^7.0.1: version "7.0.3" @@ -1961,12 +1953,12 @@ eslint@6.8.0, eslint@^6.2.2: v8-compile-cache "^2.0.3" espree@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d" - integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA== + version "6.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.0.tgz#349fef01a202bbab047748300deb37fa44da79d7" + integrity sha512-Xs8airJ7RQolnDIbLtRutmfvSsAe0xqMMAantCN/GMoqf81TFbeI1T7Jpd56qYu1uuh32dOG5W/X9uO+ghPXzA== dependencies: acorn "^7.1.0" - acorn-jsx "^5.1.0" + acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" esprima@^4.0.0, esprima@^4.0.1: @@ -2502,22 +2494,22 @@ inherits@2.0.3: integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inquirer@^7.0.0: - version "7.0.4" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" - integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ== + version "7.0.5" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.5.tgz#fb95b238ba19966c1a1f55db53c3f0ce5c9e4275" + integrity sha512-6Z5cP+LAO0rzNE7xWjWtT84jxKa5ScLEGLgegPXeO3dGeU8lNe5Ii7SlXH6KVtLGlDuaEhsvsFjrjWjw8j5lFg== dependencies: ansi-escapes "^4.2.1" - chalk "^2.4.2" + chalk "^3.0.0" cli-cursor "^3.1.0" cli-width "^2.0.0" external-editor "^3.0.3" figures "^3.0.0" lodash "^4.17.15" mute-stream "0.0.8" - run-async "^2.2.0" + run-async "^2.4.0" rxjs "^6.5.3" string-width "^4.1.0" - strip-ansi "^5.1.0" + strip-ansi "^6.0.0" through "^2.3.6" invariant@^2.2.2, invariant@^2.2.4: @@ -3488,7 +3480,7 @@ node-notifier@^6.0.0: shellwords "^0.1.1" which "^1.3.1" -node-releases@^1.1.49: +node-releases@^1.1.50: version "1.1.50" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.50.tgz#803c40d2c45db172d0410e4efec83aa8c6ad0592" integrity sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ== @@ -4018,7 +4010,7 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.2.0: +run-async@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8" integrity sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg== @@ -4520,9 +4512,9 @@ tr46@^1.0.1: punycode "^2.1.0" tslib@^1.8.1, tslib@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.0.tgz#f1f3528301621a53220d58373ae510ff747a66bc" - integrity sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg== + version "1.11.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" + integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== tsutils@^3.17.1: version "3.17.1" @@ -4555,6 +4547,11 @@ type-detect@4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"