diff --git a/src/client/interfaces/Client.d.ts b/src/client/interfaces/Client.d.ts index 59d0c768..f761f87c 100644 --- a/src/client/interfaces/Client.d.ts +++ b/src/client/interfaces/Client.d.ts @@ -4,6 +4,6 @@ import { Service } from './Service'; export interface Client { version: string; server: string; - models: Model[]; - services: Service[]; + models: Map; + services: Map; } diff --git a/src/client/interfaces/Enum.d.ts b/src/client/interfaces/Enum.d.ts deleted file mode 100644 index 18475c3f..00000000 --- a/src/client/interfaces/Enum.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { EnumSymbol } from './EnumSymbol'; - -export interface Enum { - name: string; - type: string; - symbols: EnumSymbol[]; - validation: string | null; -} diff --git a/src/client/interfaces/EnumSymbol.ts b/src/client/interfaces/Enum.ts similarity index 56% rename from src/client/interfaces/EnumSymbol.ts rename to src/client/interfaces/Enum.ts index 921833e1..147c240a 100644 --- a/src/client/interfaces/EnumSymbol.ts +++ b/src/client/interfaces/Enum.ts @@ -1,4 +1,4 @@ -export interface EnumSymbol { +export interface Enum { name: string; value: string; } diff --git a/src/client/interfaces/Model.d.ts b/src/client/interfaces/Model.d.ts index 13ceb79b..d82657a5 100644 --- a/src/client/interfaces/Model.d.ts +++ b/src/client/interfaces/Model.d.ts @@ -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; } diff --git a/src/client/interfaces/ModelProperty.d.ts b/src/client/interfaces/ModelProperty.d.ts index e883d9a9..a1abdac0 100644 --- a/src/client/interfaces/ModelProperty.d.ts +++ b/src/client/interfaces/ModelProperty.d.ts @@ -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; } diff --git a/src/openApi/v2/parser/getEnum.ts b/src/openApi/v2/parser/getEnum.ts index 7f0bda98..bc0d24cf 100644 --- a/src/openApi/v2/parser/getEnum.ts +++ b/src/openApi/v2/parser/getEnum.ts @@ -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 []; } diff --git a/src/openApi/v2/parser/getEnumSymbolsFromDescription.ts b/src/openApi/v2/parser/getEnumFromDescription.ts similarity index 83% rename from src/openApi/v2/parser/getEnumSymbolsFromDescription.ts rename to src/openApi/v2/parser/getEnumFromDescription.ts index cc3e2b2a..309b5b60 100644 --- a/src/openApi/v2/parser/getEnumSymbolsFromDescription.ts +++ b/src/openApi/v2/parser/getEnumFromDescription.ts @@ -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, '')); diff --git a/src/openApi/v2/parser/getEnumSymbols.ts b/src/openApi/v2/parser/getEnumSymbols.ts deleted file mode 100644 index 866ba84b..00000000 --- a/src/openApi/v2/parser/getEnumSymbols.ts +++ /dev/null @@ -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 []; -} diff --git a/src/openApi/v2/parser/getEnumType.ts b/src/openApi/v2/parser/getEnumType.ts index 2c7c5d90..d0415c6a 100644 --- a/src/openApi/v2/parser/getEnumType.ts +++ b/src/openApi/v2/parser/getEnumType.ts @@ -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: diff --git a/src/openApi/v2/parser/getEnumValues.ts b/src/openApi/v2/parser/getEnumValues.ts index 6be78e01..348208fe 100644 --- a/src/openApi/v2/parser/getEnumValues.ts +++ b/src/openApi/v2/parser/getEnumValues.ts @@ -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(); } diff --git a/src/openApi/v2/parser/getModel.ts b/src/openApi/v2/parser/getModel.ts index 1c53f0c2..9f8494f7 100644 --- a/src/openApi/v2/parser/getModel.ts +++ b/src/openApi/v2/parser/getModel.ts @@ -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(), }; 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; } diff --git a/src/openApi/v2/parser/getModels.ts b/src/openApi/v2/parser/getModels.ts index 7d24d914..f6c7eb02 100644 --- a/src/openApi/v2/parser/getModels.ts +++ b/src/openApi/v2/parser/getModels.ts @@ -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 { + const models = new Map(); 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; diff --git a/src/openApi/v2/parser/getServices.ts b/src/openApi/v2/parser/getServices.ts index 30cb3e53..4de12b2c 100644 --- a/src/openApi/v2/parser/getServices.ts +++ b/src/openApi/v2/parser/getServices.ts @@ -5,7 +5,7 @@ import { Method } from './constants'; /** * Get the OpenAPI services */ -export function getServices(openApi: OpenApi): Service[] { +export function getServices(openApi: OpenApi): Map { const services = new Map(); 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; } diff --git a/src/openApi/v2/parser/getType.spec.ts b/src/openApi/v2/parser/getType.spec.ts index fc9767fa..993f2219 100644 --- a/src/openApi/v2/parser/getType.spec.ts +++ b/src/openApi/v2/parser/getType.spec.ts @@ -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'); 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'); 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'); + 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([]); }); }); diff --git a/src/openApi/v3/parser/getModels.ts b/src/openApi/v3/parser/getModels.ts index 28e85b8a..40db01f6 100644 --- a/src/openApi/v3/parser/getModels.ts +++ b/src/openApi/v3/parser/getModels.ts @@ -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 { + const models = new Map(); return models; } diff --git a/src/openApi/v3/parser/getServices.ts b/src/openApi/v3/parser/getServices.ts index 385e1ece..d4c59848 100644 --- a/src/openApi/v3/parser/getServices.ts +++ b/src/openApi/v3/parser/getServices.ts @@ -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 { + const services = new Map(); return services; } diff --git a/src/templates/typescript/index.hbs b/src/templates/typescript/index.hbs index bdee182a..df73b249 100644 --- a/src/templates/typescript/index.hbs +++ b/src/templates/typescript/index.hbs @@ -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}} diff --git a/src/utils/cleanupModels.spec.ts b/src/utils/cleanupModels.spec.ts deleted file mode 100644 index a4f48645..00000000 --- a/src/utils/cleanupModels.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -describe('cleanupModels', () => { - it('should cleanup models', () => { - // TODO - }); -}); diff --git a/src/utils/cleanupServices.spec.ts b/src/utils/cleanupServices.spec.ts deleted file mode 100644 index 496cb029..00000000 --- a/src/utils/cleanupServices.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -describe('cleanupServices', () => { - it('should cleanup services', () => { - // TODO - }); -}); diff --git a/src/utils/cleanupModels.ts b/src/utils/exportModel.ts similarity index 65% rename from src/utils/cleanupModels.ts rename to src/utils/exportModel.ts index f1c39d0a..fda05ec7 100644 --- a/src/utils/cleanupModels.ts +++ b/src/utils/exportModel.ts @@ -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; + }), + }; } diff --git a/src/utils/cleanupServices.ts b/src/utils/exportService.ts similarity index 66% rename from src/utils/cleanupServices.ts rename to src/utils/exportService.ts index e54a5aad..1889203f 100644 --- a/src/utils/cleanupServices.ts +++ b/src/utils/exportService.ts @@ -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(); - - service.imports = getSortedImports(service.imports).filter(name => { +export function exportService(service: Service): any { + const names = new Map(); + 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; + }), + }; } diff --git a/src/utils/getSortedModels.spec.ts b/src/utils/getSortedModels.spec.ts index 63f594fb..a2737897 100644 --- a/src/utils/getSortedModels.spec.ts +++ b/src/utils/getSortedModels.spec.ts @@ -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(); + models.set('John', { + name: 'John', + type: 'John', + base: 'John', + template: null, + description: null, + extends: [], + imports: [], + enum: [], + properties: new Map(), + }); + models.set('Jane', { + name: 'Jane', + type: 'Jane', + base: 'Jane', + template: null, + description: null, + extends: [], + imports: [], + enum: [], + properties: new Map(), + }); + models.set('Doe', { + name: 'Doe', + type: 'Doe', + base: 'Doe', + template: null, + description: null, + extends: [], + imports: [], + enum: [], + properties: new Map(), + }); - expect(getSortedModels([])).toEqual([]); - expect(getSortedModels(models)).toEqual(models.reverse()); + expect(getSortedModels(new Map())).toEqual([]); + expect(getSortedModels(models)).toEqual(['Doe', 'Jane', 'John']); }); }); diff --git a/src/utils/getSortedModels.ts b/src/utils/getSortedModels.ts index 3fc44c1f..f9f6b25d 100644 --- a/src/utils/getSortedModels.ts +++ b/src/utils/getSortedModels.ts @@ -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[] { + 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); } diff --git a/src/utils/getSortedServices.spec.ts b/src/utils/getSortedServices.spec.ts index 522b0a95..cdb6d19a 100644 --- a/src/utils/getSortedServices.spec.ts +++ b/src/utils/getSortedServices.spec.ts @@ -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(); + 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())).toEqual([]); + expect(getSortedServices(services)).toEqual(['Doe', 'Jane', 'John']); }); }); diff --git a/src/utils/getSortedServices.ts b/src/utils/getSortedServices.ts index 49fc6cb4..35cc7c88 100644 --- a/src/utils/getSortedServices.ts +++ b/src/utils/getSortedServices.ts @@ -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[] { + 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); } diff --git a/src/utils/writeClient.ts b/src/utils/writeClient.ts index 11313f9b..222e6d96 100644 --- a/src/utils/writeClient.ts +++ b/src/utils/writeClient.ts @@ -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; } diff --git a/src/utils/writeClientModels.ts b/src/utils/writeClientModels.ts index e0d9b5c0..ad6f186c 100644 --- a/src/utils/writeClientModels.ts +++ b/src/utils/writeClientModels.ts @@ -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, 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}"`); } diff --git a/src/utils/writeClientServices.ts b/src/utils/writeClientServices.ts index 8b366f24..2fa7a883 100644 --- a/src/utils/writeClientServices.ts +++ b/src/utils/writeClientServices.ts @@ -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, 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}"`); }