- Cleanup of old extend system

This commit is contained in:
Ferdi Koomen 2020-11-19 11:51:40 +01:00
parent bb788088bb
commit 18bf2f783f
29 changed files with 156 additions and 291 deletions

View File

@ -11,7 +11,6 @@ export interface Model extends Schema {
description: string | null;
default?: string;
imports: string[];
extends: string[];
enum: Enum[];
enums: Model[];
properties: Model[];

View File

@ -13,7 +13,7 @@ export enum HttpClient {
NODE = 'node',
}
export interface Options {
export type Options = {
input: string | Record<string, any>;
output: string;
httpClient?: HttpClient;
@ -24,7 +24,7 @@ export interface Options {
exportModels?: boolean;
exportSchemas?: boolean;
write?: boolean;
}
};
/**
* Generate the OpenAPI client. This method will read the OpenAPI specification and based on the

View File

@ -5,20 +5,21 @@ import { extendEnum } from './extendEnum';
import { getComment } from './getComment';
import { getEnum } from './getEnum';
import { getEnumFromDescription } from './getEnumFromDescription';
import { getModelComposition } from './getModelComposition';
import { getModelProperties } from './getModelProperties';
import { getPattern } from './getPattern';
import { getType } from './getType';
export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model {
const model: Model = {
name: name,
name,
export: 'interface',
type: 'any',
base: 'any',
template: null,
link: null,
description: getComment(definition.description),
isDefinition: isDefinition,
isDefinition,
isReadOnly: definition.readOnly === true,
isNullable: definition['x-nullable'] === true,
isRequired: false,
@ -37,7 +38,6 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
minProperties: definition.minProperties,
pattern: getPattern(definition.pattern),
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -118,42 +118,30 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
}
}
if (definition.type === 'object' || definition.allOf) {
if (definition.allOf?.length) {
const composition = getModelComposition(openApi, definition.allOf, 'all-of', getModel);
model.export = composition.type;
model.imports.push(...composition.imports);
model.enums.push(...composition.enums);
model.properties.push(...composition.properties);
return model;
}
if (definition.type === 'object') {
model.export = 'interface';
model.type = 'any';
model.base = 'any';
if (definition.allOf?.length) {
definition.allOf.forEach(parent => {
if (parent.$ref) {
const parentRef = getType(parent.$ref);
model.extends.push(parentRef.base);
model.imports.push(parentRef.base);
}
if (parent.type === 'object' && parent.properties) {
const properties = getModelProperties(openApi, parent, getModel);
properties.forEach(property => {
model.properties.push(property);
model.imports.push(...property.imports);
if (property.export === 'enum') {
model.enums.push(property);
}
});
}
});
}
if (definition.properties) {
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
model.properties.push(property);
model.imports.push(...property.imports);
model.properties.push(property);
if (property.export === 'enum') {
model.enums.push(property);
}
});
}
return model;
}

View File

@ -45,7 +45,6 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema,
minProperties: property.minProperties,
pattern: getPattern(property.pattern),
imports: model.imports,
extends: [],
enum: [],
enums: [],
properties: [],
@ -79,7 +78,6 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema,
minProperties: property.minProperties,
pattern: getPattern(property.pattern),
imports: model.imports,
extends: model.extends,
enum: model.enum,
enums: model.enums,
properties: model.properties,

View File

@ -39,7 +39,6 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
uniqueItems: parameter.uniqueItems,
pattern: getPattern(parameter.pattern),
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -121,7 +120,6 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
operationParameter.template = model.template;
operationParameter.link = model.link;
operationParameter.imports.push(...model.imports);
operationParameter.extends.push(...model.extends);
operationParameter.enum.push(...model.enum);
operationParameter.enums.push(...model.enums);
operationParameter.properties.push(...model.properties);

View File

@ -22,7 +22,6 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -80,7 +79,6 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse
operationResponse.minProperties = model.minProperties;
operationResponse.pattern = getPattern(model.pattern);
operationResponse.imports.push(...model.imports);
operationResponse.extends.push(...model.extends);
operationResponse.enum.push(...model.enum);
operationResponse.enums.push(...model.enums);
operationResponse.properties.push(...model.properties);

View File

@ -34,7 +34,6 @@ export function getOperationResults(operationResponses: OperationResponse[]): Op
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],

View File

@ -5,6 +5,7 @@ import { extendEnum } from './extendEnum';
import { getComment } from './getComment';
import { getEnum } from './getEnum';
import { getEnumFromDescription } from './getEnumFromDescription';
import { getModelComposition } from './getModelComposition';
import { getModelDefault } from './getModelDefault';
import { getModelProperties } from './getModelProperties';
import { getPattern } from './getPattern';
@ -12,14 +13,14 @@ import { getType } from './getType';
export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model {
const model: Model = {
name: name,
name,
export: 'interface',
type: 'any',
base: 'any',
template: null,
link: null,
description: getComment(definition.description),
isDefinition: isDefinition,
isDefinition,
isReadOnly: definition.readOnly === true,
isNullable: definition.nullable === true,
isRequired: false,
@ -38,7 +39,6 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
minProperties: definition.minProperties,
pattern: getPattern(definition.pattern),
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -103,7 +103,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
}
}
if (definition.type === 'object' && definition.additionalProperties && typeof definition.additionalProperties === 'object') {
if (definition.type === 'object' && typeof definition.additionalProperties === 'object') {
if (definition.additionalProperties.$ref) {
const additionalProperties = getType(definition.additionalProperties.$ref);
model.export = 'dictionary';
@ -125,26 +125,31 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
return model;
}
}
// TODO:
// Add correct support for oneOf
// https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/
if (definition.oneOf?.length || definition.anyOf?.length || definition.allOf?.length) {
let types: OpenApiSchema[] = [];
if (definition.oneOf?.length) {
model.export = 'one-of';
types = definition.oneOf;
} else if (definition.anyOf?.length) {
model.export = 'any-of';
types = definition.anyOf;
} else if (definition.allOf?.length) {
model.export = 'all-of';
types = definition.allOf;
}
const compositionTypes = types.map(model => getModel(openApi, model));
model.properties = compositionTypes;
model.imports.push(...compositionTypes.reduce((acc: string[], type) => acc.concat(type.imports), []));
model.enums.push(...compositionTypes.reduce((acc: Model[], type) => acc.concat(type.enums), []));
if (definition.oneOf?.length) {
const composition = getModelComposition(openApi, definition.oneOf, 'one-of', getModel);
model.export = composition.type;
model.imports.push(...composition.imports);
model.enums.push(...composition.enums);
model.properties.push(...composition.properties);
return model;
}
if (definition.anyOf?.length) {
const composition = getModelComposition(openApi, definition.anyOf, 'any-of', getModel);
model.export = composition.type;
model.imports.push(...composition.imports);
model.enums.push(...composition.enums);
model.properties.push(...composition.properties);
return model;
}
if (definition.allOf?.length) {
const composition = getModelComposition(openApi, definition.allOf, 'all-of', getModel);
model.export = composition.type;
model.imports.push(...composition.imports);
model.enums.push(...composition.enums);
model.properties.push(...composition.properties);
return model;
}
@ -152,15 +157,18 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
model.export = 'interface';
model.type = 'any';
model.base = 'any';
model.default = getModelDefault(definition, model);
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
model.properties.push(property);
model.imports.push(...property.imports);
if (property.export === 'enum') {
model.enums.push(property);
}
});
if (definition.properties) {
model.default = getModelDefault(definition, model);
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
model.imports.push(...property.imports);
model.properties.push(property);
if (property.export === 'enum') {
model.enums.push(property);
}
});
}
return model;
}

View File

@ -45,7 +45,6 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema,
minProperties: property.minProperties,
pattern: getPattern(property.pattern),
imports: model.imports,
extends: [],
enum: [],
enums: [],
properties: [],
@ -79,7 +78,6 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema,
minProperties: property.minProperties,
pattern: getPattern(property.pattern),
imports: model.imports,
extends: model.extends,
enum: model.enum,
enums: model.enums,
properties: model.properties,

View File

@ -24,7 +24,6 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
isRequired: parameter.required === true,
isNullable: parameter.nullable === true,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -76,7 +75,6 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
operationParameter.pattern = getPattern(model.pattern);
operationParameter.default = model.default;
operationParameter.imports.push(...model.imports);
operationParameter.extends.push(...model.extends);
operationParameter.enum.push(...model.enum);
operationParameter.enums.push(...model.enums);
operationParameter.properties.push(...model.properties);

View File

@ -24,7 +24,6 @@ export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequ
isRequired: parameter.required === true,
isNullable: parameter.nullable === true,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -66,7 +65,6 @@ export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequ
requestBody.minProperties = model.minProperties;
requestBody.pattern = getPattern(model.pattern);
requestBody.imports.push(...model.imports);
requestBody.extends.push(...model.extends);
requestBody.enum.push(...model.enum);
requestBody.enums.push(...model.enums);
requestBody.properties.push(...model.properties);

View File

@ -23,7 +23,6 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -79,7 +78,6 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse
operationResponse.minProperties = model.minProperties;
operationResponse.pattern = getPattern(model.pattern);
operationResponse.imports.push(...model.imports);
operationResponse.extends.push(...model.extends);
operationResponse.enum.push(...model.enum);
operationResponse.enums.push(...model.enums);
operationResponse.properties.push(...model.properties);

View File

@ -34,7 +34,6 @@ export function getOperationResults(operationResponses: OperationResponse[]): Op
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],

View File

@ -1,6 +1,6 @@
{{>header}}
export interface ApiRequestOptions {
export type ApiRequestOptions = {
readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
readonly path: string;
readonly cookies?: Record<string, any>;

View File

@ -1,6 +1,6 @@
{{>header}}
export interface ApiResult {
export type ApiResult = {
readonly url: string;
readonly ok: boolean;
readonly status: number;

View File

@ -3,7 +3,7 @@
type Resolver<T> = () => Promise<T>;
type Headers = Record<string, string>;
interface Config {
type Config = {
BASE: string;
VERSION: string;
WITH_CREDENTIALS: boolean;

View File

@ -1,10 +1,3 @@
{{>header}}
{{#if extends}}
{{#each extends}}
import { ${{{this}}} } from './${{{this}}}';
{{/each}}
{{/if}}
export const ${{{name}}} = {{>schema}};

View File

@ -3,7 +3,7 @@
* {{{description}}}
*/
{{/if}}
export interface {{{name}}}{{>extends}} {
export type {{{name}}} = {
{{#each properties}}
{{#if description}}
/**

View File

@ -1 +0,0 @@
{{#if extends}} extends {{#each extends}}{{{this}}}{{#unless @last}}, {{/unless}}{{/each}}{{/if}}

View File

@ -1,16 +1,16 @@
{{#if parameters}}
{{#if @root.useOptions}}
{{#if @root.useOptions~}}
{
{{#each parameters}}
{{{name}}}{{#if default}} = {{{default}}}{{/if}},
{{/each}}
}: {
{{#each parameters}}
/** {{{description}}} */
/** {{{description}}} **/
{{{name}}}{{>isRequired}}: {{>type}},
{{/each}}
}
{{else}}
{{~else}}
{{#each parameters}}
{{{name}}}{{>isRequired}}: {{>type}}{{#if default}} = {{{default}}}{{/if}},

View File

@ -1,10 +1,5 @@
{
properties: {
{{#if extends}}
{{#each extends}}
...${{{this}}}.properties,
{{/each}}
{{/if}}
{{#if properties}}
{{#each properties}}
{{{name}}}: {{>schema}},

View File

@ -16,7 +16,6 @@ describe('getModelNames', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -34,7 +33,6 @@ describe('getModelNames', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -52,7 +50,6 @@ describe('getModelNames', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],

View File

@ -42,7 +42,6 @@ import partialBase from '../templates/partials/base.hbs';
import partialExportEnum from '../templates/partials/exportEnum.hbs';
import partialExportInterface from '../templates/partials/exportInterface.hbs';
import partialExportType from '../templates/partials/exportType.hbs';
import partialExtends from '../templates/partials/extends.hbs';
import partialHeader from '../templates/partials/header.hbs';
import partialIsNullable from '../templates/partials/isNullable.hbs';
import partialIsReadOnly from '../templates/partials/isReadOnly.hbs';
@ -111,7 +110,6 @@ export function registerHandlebarTemplates(): Templates {
Handlebars.registerPartial('exportEnum', Handlebars.template(partialExportEnum));
Handlebars.registerPartial('exportInterface', Handlebars.template(partialExportInterface));
Handlebars.registerPartial('exportType', Handlebars.template(partialExportType));
Handlebars.registerPartial('extends', Handlebars.template(partialExtends));
Handlebars.registerPartial('header', Handlebars.template(partialHeader));
Handlebars.registerPartial('isNullable', Handlebars.template(partialIsNullable));
Handlebars.registerPartial('isReadOnly', Handlebars.template(partialIsReadOnly));

View File

@ -16,7 +16,6 @@ describe('sortModelsByName', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -34,7 +33,6 @@ describe('sortModelsByName', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
@ -52,7 +50,6 @@ describe('sortModelsByName', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],

View File

@ -22,7 +22,6 @@ describe('writeClientModels', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],

View File

@ -22,7 +22,6 @@ describe('writeClientSchemas', () => {
isRequired: false,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,8 @@ async function generateV2() {
input: './test/spec/v2.json',
output: './test/generated/v2/',
httpClient: OpenAPI.HttpClient.FETCH,
useOptions: true,
useUnionTypes: true,
useOptions: false,
useUnionTypes: false,
exportCore: true,
exportSchemas: true,
exportModels: true,
@ -21,8 +21,8 @@ async function generateV3() {
input: './test/spec/v3.json',
output: './test/generated/v3/',
httpClient: OpenAPI.HttpClient.FETCH,
useOptions: true,
useUnionTypes: true,
useOptions: false,
useUnionTypes: false,
exportCore: true,
exportSchemas: true,
exportModels: true,

4
types/index.d.ts vendored
View File

@ -4,7 +4,7 @@ export declare enum HttpClient {
NODE = 'node',
}
export interface Options {
export type Options = {
input: string | Record<string, any>;
output: string;
httpClient?: HttpClient;
@ -15,6 +15,6 @@ export interface Options {
exportModels?: boolean;
exportSchemas?: boolean;
write?: boolean;
}
};
export declare function generate(options: Options): Promise<void>;