mirror of
https://github.com/ferdikoomen/openapi-typescript-codegen.git
synced 2025-12-08 20:16:21 +00:00
- Rework
This commit is contained in:
parent
6292c840ad
commit
2a73a14a48
4
src/client/interfaces/Client.d.ts
vendored
4
src/client/interfaces/Client.d.ts
vendored
@ -4,6 +4,6 @@ import { Service } from './Service';
|
||||
export interface Client {
|
||||
version: string;
|
||||
server: string;
|
||||
models: Model[];
|
||||
services: Service[];
|
||||
models: Map<string, Model>;
|
||||
services: Map<string, Service>;
|
||||
}
|
||||
|
||||
8
src/client/interfaces/Enum.d.ts
vendored
8
src/client/interfaces/Enum.d.ts
vendored
@ -1,8 +0,0 @@
|
||||
import { EnumSymbol } from './EnumSymbol';
|
||||
|
||||
export interface Enum {
|
||||
name: string;
|
||||
type: string;
|
||||
symbols: EnumSymbol[];
|
||||
validation: string | null;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
export interface EnumSymbol {
|
||||
export interface Enum {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
10
src/client/interfaces/Model.d.ts
vendored
10
src/client/interfaces/Model.d.ts
vendored
@ -1,20 +1,14 @@
|
||||
import { ModelProperty } from './ModelProperty';
|
||||
import { Enum } from './Enum';
|
||||
import { EnumSymbol } from './EnumSymbol';
|
||||
|
||||
export interface Model {
|
||||
isInterface: boolean;
|
||||
isType: boolean;
|
||||
isEnum: boolean;
|
||||
name: string;
|
||||
type: string;
|
||||
base: string;
|
||||
template: string | null;
|
||||
validation: string | null;
|
||||
description: string | null;
|
||||
extends: string[];
|
||||
imports: string[];
|
||||
enums: Enum[];
|
||||
symbols: EnumSymbol[];
|
||||
properties: ModelProperty[];
|
||||
enum: Enum[];
|
||||
properties: Map<string, ModelProperty>;
|
||||
}
|
||||
|
||||
5
src/client/interfaces/ModelProperty.d.ts
vendored
5
src/client/interfaces/ModelProperty.d.ts
vendored
@ -1,9 +1,10 @@
|
||||
export interface ModelProperty {
|
||||
name: string;
|
||||
type: string;
|
||||
base: string;
|
||||
template: string | null;
|
||||
readOnly: boolean;
|
||||
required: boolean;
|
||||
nullable: boolean;
|
||||
readOnly: boolean;
|
||||
description: string | null;
|
||||
validation: string | null;
|
||||
}
|
||||
|
||||
@ -1,12 +1,23 @@
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
|
||||
export function getModelEnum(): Enum {
|
||||
const prop: Enum = {
|
||||
name: '',
|
||||
type: '',
|
||||
values: [],
|
||||
validation: null,
|
||||
};
|
||||
|
||||
return prop;
|
||||
export function getEnum(values?: (string | number)[]): Enum[] {
|
||||
if (Array.isArray(values)) {
|
||||
return values
|
||||
.filter((value, index, arr) => {
|
||||
return arr.indexOf(value) === index;
|
||||
})
|
||||
.map(value => {
|
||||
if (typeof value === 'number') {
|
||||
return {
|
||||
name: `NUM_${value}`,
|
||||
value: String(value),
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: value.replace(/([a-z])([A-Z]+)/g, '$1_$2').toUpperCase(),
|
||||
value: `'${value}'`,
|
||||
};
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { EnumSymbol } from '../../../client/interfaces/EnumSymbol';
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
|
||||
export function getEnumSymbolsFromDescription(description: string): EnumSymbol[] {
|
||||
export function getEnumFromDescription(description: string): Enum[] {
|
||||
// Check if we can find this special format string:
|
||||
// None=0,Something=1,AnotherThing=2
|
||||
if (/^(\w+=[0-9]+,?)+$/g.test(description)) {
|
||||
const matches = description.match(/(\w+=[0-9]+,?)/g);
|
||||
if (matches) {
|
||||
// Grab the values from the description
|
||||
const symbols: EnumSymbol[] = [];
|
||||
const symbols: Enum[] = [];
|
||||
matches.forEach(match => {
|
||||
const name = match.split('=')[0];
|
||||
const value = parseInt(match.split('=')[1].replace(/[^0-9]/g, ''));
|
||||
@ -1,23 +0,0 @@
|
||||
import { EnumSymbol } from '../../../client/interfaces/EnumSymbol';
|
||||
|
||||
export function getEnumSymbols(values?: (string | number)[]): EnumSymbol[] {
|
||||
if (Array.isArray(values)) {
|
||||
return values
|
||||
.filter((value, index, arr) => {
|
||||
return arr.indexOf(value) === index;
|
||||
})
|
||||
.map(value => {
|
||||
if (typeof value === 'number') {
|
||||
return {
|
||||
name: `NUM_${value}`,
|
||||
value: String(value),
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: value.replace(/([a-z])([A-Z]+)/g, '$1_$2').toUpperCase(),
|
||||
value: `'${value}'`,
|
||||
};
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
import { EnumSymbol } from '../../../client/interfaces/EnumSymbol';
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
import { getEnumValues } from './getEnumValues';
|
||||
|
||||
export function getEnumType(symbols: EnumSymbol[], addParentheses: boolean = false): string {
|
||||
export function getEnumType(enumerators: Enum[], addParentheses: boolean = false): string {
|
||||
// Fetch values from the symbols, just to be sure we filter out
|
||||
// any double values and finally we sort them to make them easier
|
||||
// to read when we use them in our generated code.
|
||||
const values = getEnumValues(symbols);
|
||||
const values = getEnumValues(enumerators);
|
||||
|
||||
// Add grouping parentheses if needed. This can be handy if enum values
|
||||
// are used in Arrays, so that you will get the following definition:
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { EnumSymbol } from '../../../client/interfaces/EnumSymbol';
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
|
||||
export function getEnumValues(symbols: EnumSymbol[]): string[] {
|
||||
export function getEnumValues(enumerators: Enum[]): string[] {
|
||||
// Fetch values from the symbols, just to be sure we filter out
|
||||
// any double values and finally we sort them to make them easier
|
||||
// to read when we use them in our generated code.
|
||||
return symbols
|
||||
.map(symbol => symbol.value)
|
||||
.filter((symbol, index, arr) => {
|
||||
return arr.indexOf(symbol) === index;
|
||||
return enumerators
|
||||
.map(enumerator => enumerator.value)
|
||||
.filter((enumerator, index, arr) => {
|
||||
return arr.indexOf(enumerator) === index;
|
||||
})
|
||||
.sort();
|
||||
}
|
||||
|
||||
@ -1,58 +1,50 @@
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { OpenApiSchema } from '../interfaces/OpenApiSchema';
|
||||
import { getComment } from './getComment';
|
||||
import { getType } from './getType';
|
||||
import { Model } from '../../../client/interfaces/Model';
|
||||
import { getValidationForRef } from './getValidationForRef';
|
||||
import { getValidationForType } from './getValidationForType';
|
||||
import { getValidationForArrayRef } from './getValidationForArrayRef';
|
||||
import { getModelType } from './getModelType';
|
||||
import { getModelValidation } from './getModelValidation';
|
||||
import { getValidation } from './getValidation';
|
||||
import { PrimaryType } from './constants';
|
||||
import { getEnumType } from './getEnumType';
|
||||
import { getEnumSymbols } from './getEnumSymbols';
|
||||
import { getEnumValues } from './getEnumValues';
|
||||
import { getEnumSymbolsFromDescription } from './getEnumSymbolsFromDescription';
|
||||
import {OpenApi} from '../interfaces/OpenApi';
|
||||
import {OpenApiSchema} from '../interfaces/OpenApiSchema';
|
||||
import {getComment} from './getComment';
|
||||
import {getType} from './getType';
|
||||
import {Model} from '../../../client/interfaces/Model';
|
||||
import {PrimaryType} from './constants';
|
||||
import {getEnumType} from './getEnumType';
|
||||
import {ModelProperty} from '../../../client/interfaces/ModelProperty';
|
||||
import {getEnum} from './getEnum';
|
||||
import {getEnumFromDescription} from './getEnumFromDescription';
|
||||
|
||||
export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: string = 'unknown'): Model {
|
||||
|
||||
// TODO: Properties now contain ALL properties, so we need to filter out enums
|
||||
// before we render the file, plus we need to calculate the final TYPE of a model
|
||||
// by checking all the properties!
|
||||
// After this we also need to calculate the validation
|
||||
// this should all be done in a cleanup / prepare phase, not in this parsing phase
|
||||
|
||||
export function getModel(openApi: OpenApi, definition: OpenApiSchema, definitionName: string = 'unknown'): Model {
|
||||
const result: Model = {
|
||||
isInterface: false,
|
||||
isType: false,
|
||||
isEnum: false,
|
||||
name: definitionName,
|
||||
name,
|
||||
type: 'any',
|
||||
base: 'any',
|
||||
template: null,
|
||||
validation: null,
|
||||
description: getComment(definition.description),
|
||||
extends: [],
|
||||
imports: [],
|
||||
enums: [],
|
||||
symbols: [],
|
||||
properties: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
};
|
||||
|
||||
if (definition.$ref) {
|
||||
const definitionRef = getType(definition.$ref);
|
||||
result.isType = true;
|
||||
result.type = definitionRef.type;
|
||||
result.base = definitionRef.base;
|
||||
result.template = definitionRef.template;
|
||||
result.validation = getValidationForRef(definitionRef);
|
||||
result.imports.push(...definitionRef.imports);
|
||||
return result;
|
||||
}
|
||||
|
||||
// If the param is a enum then return the values as an inline type.
|
||||
if (definition.enum) {
|
||||
const enumSymbols = getEnumSymbols(definition.enum);
|
||||
if (enumSymbols.length) {
|
||||
result.isEnum = true;
|
||||
result.symbols = enumSymbols;
|
||||
result.type = getEnumType(enumSymbols);
|
||||
const enumerators = getEnum(definition.enum);
|
||||
if (enumerators.length) {
|
||||
result.type = getEnumType(enumerators);
|
||||
result.base = PrimaryType.STRING;
|
||||
result.validation = `yup.mixed<${definitionName}>().oneOf([${getEnumValues(enumSymbols).join(', ')}])`;
|
||||
result.enum.push(...enumerators);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
@ -60,13 +52,11 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, definition
|
||||
|
||||
// If the param is a enum then return the values as an inline type.
|
||||
if (definition.type === 'int' && definition.description) {
|
||||
const enumSymbols = getEnumSymbolsFromDescription(definition.description);
|
||||
if (enumSymbols.length) {
|
||||
result.isEnum = true;
|
||||
result.symbols = enumSymbols;
|
||||
result.type = getEnumType(enumSymbols);
|
||||
const enumerators = getEnumFromDescription(definition.description);
|
||||
if (enumerators.length) {
|
||||
result.type = getEnumType(enumerators);
|
||||
result.base = PrimaryType.NUMBER;
|
||||
result.validation = `yup.mixed<${definitionName}>().oneOf([${getEnumValues(enumSymbols).join(', ')}])`;
|
||||
result.enum.push(...enumerators);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
@ -77,20 +67,15 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, definition
|
||||
if (definition.type === 'array' && definition.items) {
|
||||
if (definition.items.$ref) {
|
||||
const arrayItemsRef = getType(definition.items.$ref);
|
||||
result.imports.push(...arrayItemsRef.imports);
|
||||
result.isType = true;
|
||||
result.type = `${arrayItemsRef.type}[]`;
|
||||
result.base = arrayItemsRef.base;
|
||||
result.template = arrayItemsRef.template;
|
||||
result.validation = getValidationForArrayRef(arrayItemsRef);
|
||||
result.imports.push(...arrayItemsRef.imports);
|
||||
} else {
|
||||
const arrayItemsModel = getModel(openApi, definition.items);
|
||||
result.isType = true;
|
||||
result.type = `${arrayItemsModel.type}[]`;
|
||||
result.base = arrayItemsModel.base;
|
||||
result.template = arrayItemsModel.template;
|
||||
// result.validation = getValidationForArray(array.validation || 'any');
|
||||
result.imports.push(...arrayItemsModel.imports);
|
||||
}
|
||||
return result;
|
||||
@ -112,41 +97,37 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, definition
|
||||
const propertyReadOnly = !!property.readOnly;
|
||||
if (property.$ref) {
|
||||
const propertyRef = getType(property.$ref);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyRef.imports);
|
||||
result.properties.push({
|
||||
result.properties.set(propertyName, {
|
||||
name: propertyName,
|
||||
type: propertyRef.type,
|
||||
base: propertyRef.base,
|
||||
template: propertyRef.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
readOnly: propertyReadOnly,
|
||||
description: property.description || null,
|
||||
validation: getValidationForRef(propertyRef, propertyRequired),
|
||||
});
|
||||
} else {
|
||||
const propertyModel = getModel(openApi, property);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyModel.imports);
|
||||
result.properties.push({
|
||||
result.properties.set(propertyName, {
|
||||
name: propertyName,
|
||||
type: propertyModel.type,
|
||||
base: propertyModel.base,
|
||||
template: propertyModel.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
readOnly: propertyReadOnly,
|
||||
description: property.description || null,
|
||||
validation: propertyModel.validation ? getValidation(propertyModel.validation, propertyRequired) : null,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Validation needs to also check extended schema!
|
||||
// Check ModelThatExtends.ts
|
||||
result.isInterface = true;
|
||||
result.type = getModelType(result.properties);
|
||||
result.validation = getModelValidation(definitionName, result.properties);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.template = null;
|
||||
}
|
||||
|
||||
if (definition.type === 'object' && definition.properties) {
|
||||
@ -157,48 +138,44 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, definition
|
||||
const propertyReadOnly = !!property.readOnly;
|
||||
if (property.$ref) {
|
||||
const propertyRef = getType(property.$ref);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyRef.imports);
|
||||
result.properties.push({
|
||||
result.properties.set(propertyName, {
|
||||
name: propertyName,
|
||||
type: propertyRef.type,
|
||||
base: propertyRef.base,
|
||||
template: propertyRef.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
readOnly: propertyReadOnly,
|
||||
description: property.description || null,
|
||||
validation: getValidationForRef(propertyRef, propertyRequired),
|
||||
});
|
||||
} else {
|
||||
const propertyModel = getModel(openApi, property);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyModel.imports);
|
||||
result.properties.push({
|
||||
result.properties.set(propertyName, {
|
||||
name: propertyName,
|
||||
type: propertyModel.type,
|
||||
base: propertyModel.base,
|
||||
template: propertyModel.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
readOnly: propertyReadOnly,
|
||||
description: property.description || null,
|
||||
validation: propertyModel.validation ? getValidation(propertyModel.validation, propertyRequired) : null,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.isInterface = true;
|
||||
result.type = getModelType(result.properties);
|
||||
result.validation = getModelValidation(definitionName, result.properties);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.template = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
// If the schema has a type than it can be a basic or generic type.
|
||||
if (definition.type !== 'object' && definition.type) {
|
||||
const definitionType = getType(definition.type);
|
||||
result.isType = true;
|
||||
result.type = definitionType.type;
|
||||
result.base = definitionType.base;
|
||||
result.template = definitionType.template;
|
||||
result.validation = getValidationForType(definitionType);
|
||||
result.imports.push(...definitionType.imports);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
import { Model } from '../../../client/interfaces/Model';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { getModel } from './getModel';
|
||||
import { getType } from './getType';
|
||||
|
||||
export function getModels(openApi: OpenApi): Model[] {
|
||||
const models: Model[] = [];
|
||||
export function getModels(openApi: OpenApi): Map<string, Model> {
|
||||
const models = new Map<string, Model>();
|
||||
for (const definitionName in openApi.definitions) {
|
||||
if (openApi.definitions.hasOwnProperty(definitionName)) {
|
||||
const definition = openApi.definitions[definitionName];
|
||||
const definitionModel = getModel(openApi, definition, definitionName);
|
||||
models.push(definitionModel);
|
||||
const definitionType = getType(definitionName);
|
||||
if (!models.has(definitionType.base)) {
|
||||
const model = getModel(openApi, definition, definitionType.base);
|
||||
models.set(definitionType.base, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
return models;
|
||||
|
||||
@ -5,7 +5,7 @@ import { Method } from './constants';
|
||||
/**
|
||||
* Get the OpenAPI services
|
||||
*/
|
||||
export function getServices(openApi: OpenApi): Service[] {
|
||||
export function getServices(openApi: OpenApi): Map<string, Service> {
|
||||
const services = new Map<string, Service>();
|
||||
for (const url in openApi.paths) {
|
||||
if (openApi.paths.hasOwnProperty(url)) {
|
||||
@ -44,5 +44,5 @@ export function getServices(openApi: OpenApi): Service[] {
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(services.values());
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('number');
|
||||
expect(type.base).toEqual('number');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(type.imports).toEqual([]);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert string', () => {
|
||||
@ -14,7 +14,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('string');
|
||||
expect(type.base).toEqual('string');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(type.imports).toEqual([]);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert string array', () => {
|
||||
@ -22,7 +22,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('string[]');
|
||||
expect(type.base).toEqual('string');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(type.imports).toEqual([]);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert template with primary', () => {
|
||||
@ -30,7 +30,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('Link<string>');
|
||||
expect(type.base).toEqual('Link');
|
||||
expect(type.template).toEqual('string');
|
||||
expect(type.imports).toEqual(['Link']);
|
||||
expect(Array.from(type.imports.values())).toEqual(['Link']);
|
||||
});
|
||||
|
||||
it('should convert template with model', () => {
|
||||
@ -38,7 +38,15 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('Link<Model>');
|
||||
expect(type.base).toEqual('Link');
|
||||
expect(type.template).toEqual('Model');
|
||||
expect(type.imports).toEqual(['Link', 'Model']);
|
||||
expect(Array.from(type.imports.values())).toEqual(['Link', 'Model']);
|
||||
});
|
||||
|
||||
it('should have double imports', () => {
|
||||
const type = getType('#/definitions/Link[Link]', null);
|
||||
expect(type.type).toEqual('Link<Link>');
|
||||
expect(type.base).toEqual('Link');
|
||||
expect(type.template).toEqual('Link');
|
||||
expect(Array.from(type.imports.values())).toEqual(['Link', 'Link']);
|
||||
});
|
||||
|
||||
it('should convert generic', () => {
|
||||
@ -46,6 +54,6 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('T');
|
||||
expect(type.base).toEqual('T');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(type.imports).toEqual([]);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ import { OpenApi } from '../interfaces/OpenApi';
|
||||
* Parse and return the OpenAPI models.
|
||||
* @param openApi
|
||||
*/
|
||||
export function getModels(openApi: OpenApi): Model[] {
|
||||
const models: Model[] = [];
|
||||
export function getModels(openApi: OpenApi): Map<string, Model> {
|
||||
const models = new Map<string, Model>();
|
||||
return models;
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import { OpenApi } from '../interfaces/OpenApi';
|
||||
* Parse and return the OpenAPI services.
|
||||
* @param openApi
|
||||
*/
|
||||
export function getServices(openApi: OpenApi): Service[] {
|
||||
const services: Service[] = [];
|
||||
export function getServices(openApi: OpenApi): Map<string, Service> {
|
||||
const services = new Map<string, Service>();
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -10,12 +10,12 @@ export { OpenAPI } from './core/OpenAPI';
|
||||
{{#if models}}
|
||||
|
||||
{{#each models}}
|
||||
export { {{{name}}} } from './models/{{{name}}}';
|
||||
export { {{{this}}} } from './models/{{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if services}}
|
||||
|
||||
{{#each services}}
|
||||
export { {{{name}}} } from './services/{{{name}}}';
|
||||
export { {{{this}}} } from './services/{{{this}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
describe('cleanupModels', () => {
|
||||
it('should cleanup models', () => {
|
||||
// TODO
|
||||
});
|
||||
});
|
||||
@ -1,5 +0,0 @@
|
||||
describe('cleanupServices', () => {
|
||||
it('should cleanup services', () => {
|
||||
// TODO
|
||||
});
|
||||
});
|
||||
@ -1,12 +1,13 @@
|
||||
import { getSortedImports } from './getSortedImports';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
|
||||
export function cleanupModels(models: Model[]): Model[] {
|
||||
models.forEach(model => {
|
||||
model.imports = getSortedImports(model.imports).filter(name => {
|
||||
export function exportModel(model: Model): any {
|
||||
return {
|
||||
...model,
|
||||
imports: getSortedImports(model.imports).filter(name => {
|
||||
return model.name !== name;
|
||||
});
|
||||
model.properties = model.properties
|
||||
}),
|
||||
properties: Array.from(model.properties.values())
|
||||
.filter((property, index, arr) => {
|
||||
return arr.findIndex(item => item.name === property.name) === index;
|
||||
})
|
||||
@ -14,7 +15,6 @@ export function cleanupModels(models: Model[]): Model[] {
|
||||
const nameA = a.name.toLowerCase();
|
||||
const nameB = b.name.toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
});
|
||||
return models;
|
||||
}),
|
||||
};
|
||||
}
|
||||
@ -1,15 +1,14 @@
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
import { getSortedImports } from './getSortedImports';
|
||||
|
||||
export function cleanupServices(services: Service[]): Service[] {
|
||||
services.forEach(service => {
|
||||
const names = new Map<string, number>();
|
||||
|
||||
service.imports = getSortedImports(service.imports).filter(name => {
|
||||
export function exportService(service: Service): any {
|
||||
const names = new Map<string, number>();
|
||||
return {
|
||||
...service,
|
||||
imports: getSortedImports(service.imports).filter(name => {
|
||||
return service.name !== name;
|
||||
});
|
||||
|
||||
service.operations = service.operations
|
||||
}),
|
||||
operations: service.operations
|
||||
.map(operation => {
|
||||
const name = operation.name;
|
||||
const index = names.get(name) || 0;
|
||||
@ -23,7 +22,6 @@ export function cleanupServices(services: Service[]): Service[] {
|
||||
const nameA = a.name.toLowerCase();
|
||||
const nameB = b.name.toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
});
|
||||
return services;
|
||||
}),
|
||||
};
|
||||
}
|
||||
@ -1,60 +1,45 @@
|
||||
import { getSortedModels } from './getSortedModels';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { ModelProperty } from '../client/interfaces/ModelProperty';
|
||||
|
||||
describe('getSortedModels', () => {
|
||||
it('should return sorted list', () => {
|
||||
const models: Model[] = [
|
||||
{
|
||||
isInterface: false,
|
||||
isType: false,
|
||||
isEnum: false,
|
||||
name: 'John',
|
||||
type: 'John',
|
||||
base: 'John',
|
||||
template: null,
|
||||
validation: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
symbols: [],
|
||||
properties: [],
|
||||
enums: [],
|
||||
},
|
||||
{
|
||||
isInterface: false,
|
||||
isType: false,
|
||||
isEnum: false,
|
||||
name: 'Jane',
|
||||
type: 'Jane',
|
||||
base: 'Jane',
|
||||
template: null,
|
||||
validation: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
symbols: [],
|
||||
properties: [],
|
||||
enums: [],
|
||||
},
|
||||
{
|
||||
isInterface: false,
|
||||
isType: false,
|
||||
isEnum: false,
|
||||
name: 'Doe',
|
||||
type: 'Doe',
|
||||
base: 'Doe',
|
||||
template: null,
|
||||
validation: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
symbols: [],
|
||||
properties: [],
|
||||
enums: [],
|
||||
},
|
||||
];
|
||||
const models = new Map<string, Model>();
|
||||
models.set('John', {
|
||||
name: 'John',
|
||||
type: 'John',
|
||||
base: 'John',
|
||||
template: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
});
|
||||
models.set('Jane', {
|
||||
name: 'Jane',
|
||||
type: 'Jane',
|
||||
base: 'Jane',
|
||||
template: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
});
|
||||
models.set('Doe', {
|
||||
name: 'Doe',
|
||||
type: 'Doe',
|
||||
base: 'Doe',
|
||||
template: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
});
|
||||
|
||||
expect(getSortedModels([])).toEqual([]);
|
||||
expect(getSortedModels(models)).toEqual(models.reverse());
|
||||
expect(getSortedModels(new Map<string, Model>())).toEqual([]);
|
||||
expect(getSortedModels(models)).toEqual(['Doe', 'Jane', 'John']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
|
||||
export function getSortedModels(models: Model[]): Model[] {
|
||||
return models.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase();
|
||||
const nameB = b.name.toLowerCase();
|
||||
return nameA.localeCompare(nameB, 'en');
|
||||
});
|
||||
export function getSortedModels(models: Map<string, Model>): string[] {
|
||||
return Array.from(models.values())
|
||||
.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase();
|
||||
const nameB = b.name.toLowerCase();
|
||||
return nameA.localeCompare(nameB, 'en');
|
||||
})
|
||||
.map(model => model.name);
|
||||
}
|
||||
|
||||
@ -3,25 +3,24 @@ import { Service } from '../client/interfaces/Service';
|
||||
|
||||
describe('getSortedServices', () => {
|
||||
it('should return sorted list', () => {
|
||||
const services: Service[] = [
|
||||
{
|
||||
name: 'John',
|
||||
operations: [],
|
||||
imports: [],
|
||||
},
|
||||
{
|
||||
name: 'Jane',
|
||||
operations: [],
|
||||
imports: [],
|
||||
},
|
||||
{
|
||||
name: 'Doe',
|
||||
operations: [],
|
||||
imports: [],
|
||||
},
|
||||
];
|
||||
const services = new Map<string, Service>();
|
||||
services.set('John', {
|
||||
name: 'John',
|
||||
operations: [],
|
||||
imports: [],
|
||||
});
|
||||
services.set('Jane', {
|
||||
name: 'Jane',
|
||||
operations: [],
|
||||
imports: [],
|
||||
});
|
||||
services.set('Doe', {
|
||||
name: 'Doe',
|
||||
operations: [],
|
||||
imports: [],
|
||||
});
|
||||
|
||||
expect(getSortedServices([])).toEqual([]);
|
||||
expect(getSortedServices(services)).toEqual(services.reverse());
|
||||
expect(getSortedServices(new Map<string, Service>())).toEqual([]);
|
||||
expect(getSortedServices(services)).toEqual(['Doe', 'Jane', 'John']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
|
||||
export function getSortedServices(services: Service[]): Service[] {
|
||||
return services.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase();
|
||||
const nameB = b.name.toLowerCase();
|
||||
return nameA.localeCompare(nameB, 'en');
|
||||
});
|
||||
export function getSortedServices(services: Map<string, Service>): string[] {
|
||||
return Array.from(services.values())
|
||||
.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase();
|
||||
const nameB = b.name.toLowerCase();
|
||||
return nameA.localeCompare(nameB, 'en');
|
||||
})
|
||||
.map(service => service.name);
|
||||
}
|
||||
|
||||
@ -6,14 +6,10 @@ import * as mkdirp from 'mkdirp';
|
||||
import * as rimraf from 'rimraf';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { writeClientIndex } from './writeClientIndex';
|
||||
import { getSortedModels } from './getSortedModels';
|
||||
import { getSortedServices } from './getSortedServices';
|
||||
import { Language } from '../index';
|
||||
import * as fs from 'fs';
|
||||
import { getFileName } from './getFileName';
|
||||
import * as glob from 'glob';
|
||||
import { cleanupServices } from './cleanupServices';
|
||||
import { cleanupModels } from './cleanupModels';
|
||||
|
||||
/**
|
||||
* Write our OpenAPI client, using the given templates at the given output path
|
||||
@ -58,8 +54,8 @@ export function writeClient(client: Client, language: Language, templates: Templ
|
||||
// Write the client files
|
||||
try {
|
||||
writeClientIndex(client, language, templates.index, outputPath);
|
||||
writeClientModels(getSortedModels(cleanupModels(client.models)), language, templates.model, outputPathModels);
|
||||
writeClientServices(getSortedServices(cleanupServices(client.services)), language, templates.service, outputPathServices);
|
||||
writeClientModels(client.models, language, templates.model, outputPathModels);
|
||||
writeClientServices(client.services, language, templates.service, outputPathServices);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { Model } from '../client/interfaces/Model';
|
||||
import * as path from 'path';
|
||||
import { Language } from '../index';
|
||||
import { getFileName } from './getFileName';
|
||||
import { exportModel } from './exportModel';
|
||||
|
||||
/**
|
||||
* Generate Models using the Handlebar template and write to disk.
|
||||
@ -12,11 +13,13 @@ import { getFileName } from './getFileName';
|
||||
* @param template: The template that is used to write the file.
|
||||
* @param outputPath:
|
||||
*/
|
||||
export function writeClientModels(models: Model[], language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
|
||||
export function writeClientModels(models: Map<string, Model>, language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
|
||||
models.forEach(model => {
|
||||
const fileName = getFileName(model.name, language);
|
||||
try {
|
||||
fs.writeFileSync(path.resolve(outputPath, fileName), template(model));
|
||||
const templateData = exportModel(model);
|
||||
const templateResult = template(templateData);
|
||||
fs.writeFileSync(path.resolve(outputPath, fileName), templateResult);
|
||||
} catch (e) {
|
||||
throw new Error(`Could not write model: "${fileName}"`);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import * as path from 'path';
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
import { Language } from '../index';
|
||||
import { getFileName } from './getFileName';
|
||||
import { exportService } from './exportService';
|
||||
|
||||
/**
|
||||
* Generate Services using the Handlebar template and write to disk.
|
||||
@ -12,11 +13,13 @@ import { getFileName } from './getFileName';
|
||||
* @param template: The template that is used to write the file.
|
||||
* @param outputPath:
|
||||
*/
|
||||
export function writeClientServices(services: Service[], language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
|
||||
export function writeClientServices(services: Map<string, Service>, language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
|
||||
services.forEach(service => {
|
||||
const fileName = getFileName(service.name, language);
|
||||
try {
|
||||
fs.writeFileSync(path.resolve(outputPath, fileName), template(service));
|
||||
const templateData = exportService(service);
|
||||
const templateResult = template(templateData);
|
||||
fs.writeFileSync(path.resolve(outputPath, fileName), templateResult);
|
||||
} catch (e) {
|
||||
throw new Error(`Could not write service: "${fileName}"`);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user