- Working on validation

This commit is contained in:
Ferdi Koomen 2019-11-17 23:45:35 +01:00
parent 433de4437e
commit fd0d909faa
42 changed files with 282 additions and 171 deletions

View File

@ -4,6 +4,6 @@ root = true
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
insert_final_newline = false
indent_style = space
indent_size = 4

View File

@ -5,15 +5,16 @@ export interface Model {
name: string;
type: string;
base: string;
template?: string;
description?: string;
readOnly?: boolean;
required?: boolean;
nullable?: boolean;
link: Model | null;
template: string | null;
description: string | null;
readOnly: boolean;
required: boolean;
nullable: boolean;
imports: string[];
extends: string[];
enum: Enum[];
enums: Model[];
properties: Model[];
validation?: Validation;
validation: Validation | null;
}

View File

@ -4,8 +4,8 @@ import { OperationParameters } from './OperationParameters';
export interface Operation extends OperationParameters {
service: string;
name: string;
summary?: string;
description?: string;
summary: string | null;
description: string | null;
deprecated: boolean;
method: string;
path: string;

View File

@ -4,9 +4,9 @@ export interface OperationParameter {
name: string;
type: string;
base: string;
template?: string;
description?: string;
default?: any;
template: string | null;
description: string | null;
default: any;
required: boolean;
nullable: boolean;
imports: string[];

View File

@ -7,5 +7,5 @@ export interface OperationParameters {
parametersQuery: OperationParameter[];
parametersForm: OperationParameter[];
parametersHeader: OperationParameter[];
parametersBody?: OperationParameter;
parametersBody: OperationParameter | null;
}

View File

@ -3,6 +3,6 @@ export interface OperationResponse {
text: string;
type: string;
base: string;
template?: string;
template: string | null;
imports: string[];
}

View File

@ -1,6 +1,6 @@
export interface Type {
type: string;
base: string;
template?: string;
template: string | null;
imports: string[];
}

View File

@ -1,6 +1,6 @@
export interface Validation {
type: 'ref' | 'type' | 'enum' | 'array' | 'dictionary' | 'property' | 'model';
childType?: string | null;
childBase?: string | null;
childValidation?: Validation;
childType: string | null;
childBase: string | null;
childValidation: Validation | null;
}

View File

@ -1,13 +1,12 @@
import * as path from 'path';
import { parse as parseV2 } from './openApi/v2';
import { parse as parseV3 } from './openApi/v3';
import { readHandlebarsTemplates, Templates } from './utils/readHandlebarsTemplates';
import { readHandlebarsTemplates } from './utils/readHandlebarsTemplates';
import { getOpenApiSpec } from './utils/getOpenApiSpec';
import { writeClient } from './utils/writeClient';
import * as os from 'os';
import * as chalk from 'chalk';
import { getOpenApiVersion, OpenApiVersion } from './utils/getOpenApiVersion';
import { Client } from './client/interfaces/Client';
export enum Language {
TYPESCRIPT = 'typescript',

View File

@ -1,7 +1,6 @@
export enum PrimaryType {
FILE = 'File',
OBJECT = 'any',
ARRAY = 'any[]',
BOOLEAN = 'boolean',
NUMBER = 'number',
STRING = 'string',
@ -14,8 +13,6 @@ export const TYPE_MAPPINGS = new Map<string, PrimaryType>([
['binary', PrimaryType.FILE],
['any', PrimaryType.OBJECT],
['object', PrimaryType.OBJECT],
['list', PrimaryType.ARRAY],
['array', PrimaryType.ARRAY],
['boolean', PrimaryType.BOOLEAN],
['byte', PrimaryType.NUMBER],
['int', PrimaryType.NUMBER],

View File

@ -1,6 +1,6 @@
import { EOL } from 'os';
export function getComment(comment?: string): string | undefined {
export function getComment(comment?: string): string | null {
if (comment) {
return comment
.split(/(\r\n|\n|\r)+/g)
@ -9,5 +9,5 @@ export function getComment(comment?: string): string | undefined {
.join(EOL)
.replace(/(\r\n|\n|\r)+/g, '$1 * ');
}
return undefined;
return null;
}

View File

@ -3,8 +3,6 @@ import { getMappedType } from './getMappedType';
describe('getMappedType', () => {
it('should map types to the basics', () => {
expect(getMappedType('File')).toEqual('File');
expect(getMappedType('Array')).toEqual('any[]');
expect(getMappedType('List')).toEqual('any[]');
expect(getMappedType('String')).toEqual('string');
expect(getMappedType('date')).toEqual('string');
expect(getMappedType('date-time')).toEqual('string');

View File

@ -7,7 +7,6 @@ import { PrimaryType } from './constants';
import { getEnumType } from './getEnumType';
import { getEnum } from './getEnum';
import { getEnumFromDescription } from './getEnumFromDescription';
import { getTypeFromProperties } from './getTypeFromProperties';
import { getModelProperties } from './getModelProperties';
export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: string = ''): Model {
@ -15,13 +14,18 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
name,
type: PrimaryType.OBJECT,
base: PrimaryType.OBJECT,
template: null,
link: null,
description: getComment(definition.description),
readOnly: definition.readOnly,
readOnly: definition.readOnly || false,
required: false,
nullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
validation: null,
};
if (definition.$ref) {
@ -32,6 +36,9 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
result.imports.push(...definitionRef.imports);
result.validation = {
type: 'ref',
childType: null,
childBase: null,
childValidation: null,
};
return result;
}
@ -45,10 +52,12 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
result.enum.push(...enumerators);
result.validation = {
type: 'enum',
childType: null,
childBase: null,
childValidation: null,
};
return result;
}
return result;
}
// If the param is a enum then return the values as an inline type.
@ -60,10 +69,12 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
result.enum.push(...enumerators);
result.validation = {
type: 'enum',
childType: null,
childBase: null,
childValidation: null,
};
return result;
}
return result;
}
// If the schema is an Array type, we check for the child type,
@ -71,20 +82,22 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
if (definition.type === 'array' && definition.items) {
if (definition.items.$ref) {
const arrayItems = getType(definition.items.$ref);
result.type = `${arrayItems.type}[]`;
result.base = arrayItems.base;
result.type = `Array<${arrayItems.type}>`;
result.base = 'Array';
result.template = arrayItems.template;
result.imports.push(...arrayItems.imports);
result.validation = {
type: 'array',
childType: arrayItems.type,
childBase: arrayItems.base,
childValidation: null,
};
} else {
const arrayItems = getModel(openApi, definition.items);
result.type = `${arrayItems.type}[]`;
result.base = arrayItems.base;
result.type = `Array<${arrayItems.type}>`;
result.base = 'Array';
result.template = arrayItems.template;
result.link = arrayItems;
result.imports.push(...arrayItems.imports);
result.validation = {
type: 'array',
@ -110,12 +123,14 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
type: 'dictionary',
childType: additionalProperties.type,
childBase: additionalProperties.base,
childValidation: null,
};
} else {
const additionalProperties = getModel(openApi, definition.additionalProperties);
result.type = `Dictionary<${additionalProperties.type}>`;
result.base = 'Dictionary';
result.template = additionalProperties.type;
result.link = additionalProperties;
result.imports.push(...additionalProperties.imports);
result.validation = {
type: 'dictionary',
@ -143,10 +158,13 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
});
}
});
result.type = getTypeFromProperties(result.properties);
result.type = PrimaryType.OBJECT;
result.base = PrimaryType.OBJECT;
result.validation = {
type: 'model',
childType: null,
childBase: null,
childValidation: null,
};
}
@ -156,10 +174,13 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
result.properties.push(property);
result.imports.push(...property.imports);
});
result.type = getTypeFromProperties(result.properties);
result.type = PrimaryType.OBJECT;
result.base = PrimaryType.OBJECT;
result.validation = {
type: 'model',
childType: null,
childBase: null,
childValidation: null,
};
return result;
}
@ -173,6 +194,9 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
result.imports.push(...definitionType.imports);
result.validation = {
type: 'type',
childType: null,
childBase: null,
childValidation: null,
};
return result;
}

View File

@ -10,8 +10,8 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
const property = definition.properties[propertyName];
const propertyRequired = definition.required && definition.required.includes(propertyName);
const propertyReadOnly = property.readOnly;
const propertyRequired = !!(definition.required && definition.required.includes(propertyName));
const propertyReadOnly = !!property.readOnly;
if (property.$ref) {
const prop = getType(property.$ref);
result.push({
@ -19,9 +19,11 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
type: prop.type,
base: prop.base,
template: prop.template,
link: null,
description: getComment(property.description),
readOnly: propertyReadOnly,
required: propertyRequired,
nullable: false,
imports: prop.imports,
extends: [],
enum: [],
@ -31,6 +33,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
type: 'property',
childType: prop.type,
childBase: prop.base,
childValidation: null,
},
});
} else {
@ -40,9 +43,11 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
type: prop.type,
base: prop.base,
template: prop.template,
link: prop.link,
description: getComment(property.description),
readOnly: propertyReadOnly,
required: propertyRequired,
nullable: false,
imports: prop.imports,
extends: prop.extends,
enum: prop.enum,

View File

@ -33,6 +33,7 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
parametersQuery: [],
parametersForm: [],
parametersHeader: [],
parametersBody: null,
imports: [],
errors: [],
result: PrimaryType.VOID,

View File

@ -12,6 +12,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
name: getOperationParameterName(parameter.name),
type: 'any',
base: 'any',
template: null,
description: getComment(parameter.description),
default: parameter.default,
required: parameter.required || false,

View File

@ -17,6 +17,7 @@ export function getOperationParameters(openApi: OpenApi, parameters: OpenApiPara
parametersQuery: [],
parametersForm: [],
parametersHeader: [],
parametersBody: null,
};
// Iterate over the parameters

View File

@ -13,6 +13,7 @@ export function getOperationResponse(responses: OperationResponse[]): OperationR
text: '',
type: PrimaryType.OBJECT,
base: PrimaryType.OBJECT,
template: null,
imports: [],
};
}

View File

@ -5,7 +5,7 @@ describe('getType', () => {
const type = getType('int');
expect(type.type).toEqual('number');
expect(type.base).toEqual('number');
expect(type.template).toEqual(undefined);
expect(type.template).toEqual(null);
expect(type.imports).toEqual([]);
});
@ -13,15 +13,15 @@ describe('getType', () => {
const type = getType('String');
expect(type.type).toEqual('string');
expect(type.base).toEqual('string');
expect(type.template).toEqual(undefined);
expect(type.template).toEqual(null);
expect(type.imports).toEqual([]);
});
it('should convert string array', () => {
const type = getType('Array[String]');
expect(type.type).toEqual('string[]');
expect(type.type).toEqual('Array<string>');
expect(type.base).toEqual('string');
expect(type.template).toEqual(undefined);
expect(type.template).toEqual(null);
expect(type.imports).toEqual([]);
});
@ -53,7 +53,7 @@ describe('getType', () => {
const type = getType('#/definitions/Link', 'Link');
expect(type.type).toEqual('T');
expect(type.base).toEqual('T');
expect(type.template).toEqual(undefined);
expect(type.template).toEqual(null);
expect(type.imports).toEqual([]);
});
});

View File

@ -12,6 +12,7 @@ export function getType(value?: string, template?: string): Type {
const result: Type = {
type: PrimaryType.OBJECT,
base: PrimaryType.OBJECT,
template: null,
imports: [],
};
@ -27,13 +28,12 @@ export function getType(value?: string, template?: string): Type {
const match2 = getType(matches[2]);
// If the first match is a generic array then construct a correct array type,
// for example the type "Array[Model]" becomes "Model[]".
if (match1.type === PrimaryType.ARRAY) {
result.type = `${match2.type}[]`;
result.base = `${match2.type}`;
// for example the type "Array[Model]" becomes "Array<Model>".
if (match1.type === 'Array') {
result.type = `Array<${match2.type}>`;
result.base = match2.type;
match1.imports = [];
} else if (match2.type === '') {
// Primary types like number[] or string[]
result.type = match1.type;
result.base = match1.type;
result.template = match1.type;

View File

@ -6,7 +6,6 @@ describe('isPrimaryType', () => {
expect(isPrimaryType('boolean')).toBeTruthy();
expect(isPrimaryType('string')).toBeTruthy();
expect(isPrimaryType('any')).toBeTruthy();
expect(isPrimaryType('any[]')).toBeTruthy();
expect(isPrimaryType('void')).toBeTruthy();
expect(isPrimaryType('null')).toBeTruthy();
expect(isPrimaryType('Array')).toBeFalsy();

View File

@ -7,7 +7,6 @@ import { PrimaryType } from './constants';
export function isPrimaryType(type: string): type is PrimaryType {
switch (type.toLowerCase()) {
case PrimaryType.FILE:
case PrimaryType.ARRAY:
case PrimaryType.OBJECT:
case PrimaryType.BOOLEAN:
case PrimaryType.NUMBER:

View File

@ -0,0 +1,20 @@
export enum {{{name}}} {
{{#each symbols}}
{{{name}}} = {{{value}}},
{{/each}}
}
{{#if validation}}
export namespace {{{name}}} {
export const schema = {{>validation}};
export function validate(value: any): Promise<{{{name}}}> {
return schema.validate(value, { strict: true });
}
export function validateSync(value: any): {{{name}}} {
return schema.validateSync(value, { strict: true });
}
}
{{/if}}

View File

@ -0,0 +1,38 @@
export interface {{{name}}}{{{template}}}{{#if extends}} extends{{#each extends}} {{{this}}}{{/each}}{{/if}} {
{{#each properties}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless required}}?{{/unless}}: {{>type}}{{#if nullable}} | null{{/if}};
{{/each}}
}
export namespace {{{name}}} {
{{#each enums}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
export enum {{{name}}} {
{{#each values}}
{{{name}}} = {{{value}}},
{{/each}}
}
{{/each}}
{{#if validation}}
export const schema = {{>validation}};
export function validate(value: any): Promise<{{{name}}}{{{template}}}> {
return schema.validate(value, { strict: true });
}
export function validateSync(value: any): {{{name}}}{{{template}}} {
return schema.validateSync(value, { strict: true });
}
{{/if}}
}

View File

@ -0,0 +1,16 @@
export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}};
{{#if validation}}
export namespace {{{name}}} {
export const schema = {{>validation}};
export function validate(value: any): Promise<{{{name}}}{{#if nullable}} | null{{/if}}> {
return schema.validate(value, { strict: true });
}
export function validateSync(value: any): {{{name}}}{{#if nullable}} | null{{/if}} {
return schema.validateSync(value, { strict: true });
}
}
{{/if}}

View File

@ -18,4 +18,4 @@ export { {{{this}}} } from './models/{{{this}}}';
{{#each services}}
export { {{{this}}} } from './services/{{{this}}}';
{{/each}}
{{/if}}
{{/if}}

View File

@ -17,83 +17,10 @@ import * as yup from 'yup';
* {{{description}}}
*/
{{/if}}
{{#if isInterface}}
export interface {{{name}}}{{{template}}}{{#if extends}} extends{{#each extends}} {{{this}}}{{/each}}{{/if}} {
{{#each properties}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless required}}?{{/unless}}: {{{type}}}{{#if nullable}} | null{{/if}};
{{/each}}
}
export namespace {{{name}}} {
{{#each enums}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
export enum {{{name}}} {
{{#each values}}
{{{name}}} = {{{value}}},
{{/each}}
}
{{/each}}
{{#if validation}}
export const schema = {{{validation}}};
export function validate(value: any): Promise<{{{name}}}{{{template}}}> {
return schema.validate(value, { strict: true });
}
export function validateSync(value: any): {{{name}}}{{{template}}} {
return schema.validateSync(value, { strict: true });
}
{{/if}}
}
{{/if}}
{{#if isType}}
export type {{{name}}} = {{{type}}}{{#if nullable}} | null{{/if}};
{{#if validation}}
export namespace {{{name}}} {
export const schema = {{{validation}}};
export function validate(value: any): Promise<{{{name}}}{{#if nullable}} | null{{/if}}> {
return schema.validate(value, { strict: true });
}
export function validateSync(value: any): {{{name}}}{{#if nullable}} | null{{/if}} {
return schema.validateSync(value, { strict: true });
}
}
{{/if}}
{{/if}}
{{#if isEnum}}
export enum {{{name}}} {
{{#each symbols}}
{{{name}}} = {{{value}}},
{{/each}}
}
{{#if validation}}
export namespace {{{name}}} {
export const schema = {{{validation}}};
export function validate(value: any): Promise<{{{name}}}> {
return schema.validate(value, { strict: true });
}
export function validateSync(value: any): {{{name}}} {
return schema.validateSync(value, { strict: true });
}
}
{{/if}}
{{/if}}
{{#if properties}}
{{> exportInterface}}
{{else if enum}}
{{> exportEnum}}
{{else}}
{{> exportType}}
{{/if}}

View File

@ -81,4 +81,4 @@ export class {{{name}}} {
}
{{/each}}
}
}

View File

@ -0,0 +1,5 @@
{{#if properties}}{
{{#each properties}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless required}}?{{/unless}}: {{>type}}{{#if nullable}} | null{{/if}},
{{/each}}
}{{else if link}}{{{base}}}<{{>type link}}>{{else}}{{{type}}}{{/if}}

View File

@ -0,0 +1 @@
yup.mixed()

View File

@ -1,6 +1,6 @@
import { Model } from '../client/interfaces/Model';
export function exportModel(model: Model): any {
export function exportModel(model: Model): Model {
return {
...model,
imports: model.imports
@ -16,8 +16,17 @@ export function exportModel(model: Model): any {
return nameA.localeCompare(nameB);
}),
properties: model.properties
// .map(property => exportModel(property))
// .filter((property, index, arr) => {
// return arr.findIndex(item => item.name === property.name) === index;
// })
.sort((a, b) => {
const nameA = a.name.toLowerCase();
const nameB = b.name.toLowerCase();
return nameA.localeCompare(nameB);
}),
enums: model.enums
.map(property => exportModel(property))
.filter(property => property.enum.length)
.filter((property, index, arr) => {
return arr.findIndex(item => item.name === property.name) === index;
})
@ -26,14 +35,9 @@ export function exportModel(model: Model): any {
const nameB = b.name.toLowerCase();
return nameA.localeCompare(nameB);
}),
enums: model.properties
.map(property => exportModel(property))
.filter(property => !property.enum.length)
.filter((property, index, arr) => {
return arr.findIndex(item => item.name === property.name) === index;
})
.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;
})
.sort((a, b) => {
const nameA = a.name.toLowerCase();

View File

@ -1,6 +1,6 @@
import { Service } from '../client/interfaces/Service';
export function exportService(service: Service): any {
export function exportService(service: Service): Service {
const names = new Map<string, number>();
return {
...service,

View File

@ -8,37 +8,52 @@ describe('getModelNames', () => {
name: 'John',
type: 'John',
base: 'John',
template: null,
link: null,
description: null,
readOnly: false,
required: false,
nullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
validation: null,
});
models.set('Jane', {
name: 'Jane',
type: 'Jane',
base: 'Jane',
template: null,
link: null,
description: null,
readOnly: false,
required: false,
nullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
validation: null,
});
models.set('Doe', {
name: 'Doe',
type: 'Doe',
base: 'Doe',
template: null,
link: null,
description: null,
readOnly: false,
required: false,
nullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
validation: null,
});
expect(getModelNames(new Map<string, Model>())).toEqual([]);

View File

@ -6,7 +6,12 @@ import * as path from 'path';
export interface Templates {
index: handlebars.TemplateDelegate;
model: handlebars.TemplateDelegate;
exportInterface: handlebars.TemplateDelegate;
exportEnum: handlebars.TemplateDelegate;
exportType: handlebars.TemplateDelegate;
service: handlebars.TemplateDelegate;
validation: handlebars.TemplateDelegate;
type: handlebars.TemplateDelegate;
}
/**
@ -17,13 +22,23 @@ export interface Templates {
export function readHandlebarsTemplates(language: Language): Templates {
const pathTemplateIndex = path.resolve(__dirname, `../../src/templates/${language}/index.hbs`);
const pathTemplateModel = path.resolve(__dirname, `../../src/templates/${language}/model.hbs`);
const pathTemplateExportInterface = path.resolve(__dirname, `../../src/templates/${language}/exportInterface.hbs`);
const pathTemplateExportEnum = path.resolve(__dirname, `../../src/templates/${language}/exportEnum.hbs`);
const pathTemplateExportType = path.resolve(__dirname, `../../src/templates/${language}/exportType.hbs`);
const pathTemplateService = path.resolve(__dirname, `../../src/templates/${language}/service.hbs`);
const pathTemplateValidation = path.resolve(__dirname, `../../src/templates/${language}/validation.hbs`);
const pathTemplateType = path.resolve(__dirname, `../../src/templates/${language}/type.hbs`);
try {
return {
index: readHandlebarsTemplate(pathTemplateIndex),
model: readHandlebarsTemplate(pathTemplateModel),
exportInterface: readHandlebarsTemplate(pathTemplateExportInterface),
exportEnum: readHandlebarsTemplate(pathTemplateExportEnum),
exportType: readHandlebarsTemplate(pathTemplateExportType),
service: readHandlebarsTemplate(pathTemplateService),
validation: readHandlebarsTemplate(pathTemplateValidation),
type: readHandlebarsTemplate(pathTemplateType),
};
} catch (e) {
throw e;

View File

@ -31,6 +31,7 @@ describe('writeClient', () => {
const templates: Templates = {
index: () => 'dummy',
model: () => 'dummy',
interface: () => 'dummy',
service: () => 'dummy',
};

View File

@ -53,9 +53,9 @@ export function writeClient(client: Client, language: Language, templates: Templ
// Write the client files
try {
writeClientIndex(client, language, templates.index, outputPath);
writeClientModels(client.models, language, templates.model, outputPathModels);
writeClientServices(client.services, language, templates.service, outputPathServices);
writeClientIndex(client, language, templates, outputPath);
writeClientModels(client.models, language, templates, outputPathModels);
writeClientServices(client.services, language, templates, outputPathServices);
} catch (e) {
throw e;
}

View File

@ -4,6 +4,7 @@ import { Client } from '../client/interfaces/Client';
import { Language } from '../index';
import { Model } from '../client/interfaces/Model';
import { Service } from '../client/interfaces/Service';
import { Templates } from './readHandlebarsTemplates';
jest.mock('fs');
@ -17,8 +18,17 @@ describe('writeClientIndex', () => {
models: new Map<string, Model>(),
services: new Map<string, Service>(),
};
const template = () => 'dummy';
writeClientIndex(client, Language.TYPESCRIPT, template, '/');
const templates: Templates = {
index: () => 'dummy',
model: () => 'dummy',
exportInterface: () => 'dummy',
exportEnum: () => 'dummy',
exportType: () => 'dummy',
service: () => 'dummy',
validation: () => 'dummy',
type: () => 'dummy',
};
writeClientIndex(client, Language.TYPESCRIPT, templates, '/');
expect(fsWriteFileSync).toBeCalledWith('/index.ts', 'dummy');
});
});

View File

@ -1,11 +1,11 @@
import { Client } from '../client/interfaces/Client';
import * as handlebars from 'handlebars';
import * as fs from 'fs';
import * as path from 'path';
import { getModelNames } from './getModelNames';
import { getServiceNames } from './getServiceNames';
import { Language } from '../index';
import { getFileName } from './getFileName';
import { Templates } from './readHandlebarsTemplates';
/**
* Generate the OpenAPI client index file using the Handlebar template and write it to disk.
@ -13,15 +13,15 @@ import { getFileName } from './getFileName';
* library. But yuo can also import individual models and services directly.
* @param client: Client object, containing, models, schemas and services.
* @param language: The output language (Typescript or javascript).
* @param template: The template that is used to write the file.
* @param templates: The loaded handlebar templates.
* @param outputPath:
*/
export function writeClientIndex(client: Client, language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
export function writeClientIndex(client: Client, language: Language, templates: Templates, outputPath: string): void {
const fileName = getFileName('index', language);
try {
fs.writeFileSync(
path.resolve(outputPath, fileName),
template({
templates.index({
server: client.server,
version: client.version,
models: getModelNames(client.models),

View File

@ -2,6 +2,7 @@ import { writeClientModels } from './writeClientModels';
import * as fs from 'fs';
import { Model } from '../client/interfaces/Model';
import { Language } from '../index';
import { Templates } from './readHandlebarsTemplates';
jest.mock('fs');
@ -14,16 +15,30 @@ describe('writeClientModels', () => {
name: 'Item',
type: 'Item',
base: 'Item',
template: null,
link: null,
description: null,
readOnly: false,
required: false,
nullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
validation: null,
});
const template = () => 'dummy';
writeClientModels(models, Language.TYPESCRIPT, template, '/');
const templates: Templates = {
index: () => 'dummy',
model: () => 'dummy',
exportInterface: () => 'dummy',
exportEnum: () => 'dummy',
exportType: () => 'dummy',
service: () => 'dummy',
validation: () => 'dummy',
type: () => 'dummy',
};
writeClientModels(models, Language.TYPESCRIPT, templates, '/');
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
});
});

View File

@ -1,27 +1,35 @@
import * as fs from 'fs';
import * as handlebars from 'handlebars';
import { Model } from '../client/interfaces/Model';
import * as path from 'path';
import { Language } from '../index';
import { getFileName } from './getFileName';
import { exportModel } from './exportModel';
import { Templates } from './readHandlebarsTemplates';
/**
* Generate Models using the Handlebar template and write to disk.
* @param models: Array of Models to write.
* @param language: The output language (Typescript or javascript).
* @param template: The template that is used to write the file.
* @param templates: The loaded handlebar templates.
* @param outputPath:
*/
export function writeClientModels(models: Map<string, Model>, language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
export function writeClientModels(models: Map<string, Model>, language: Language, templates: Templates, outputPath: string): void {
models.forEach(model => {
const fileName = getFileName(model.name, language);
try {
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}"`);
}
// try {
const templateData = exportModel(model);
const templateResult = templates.model(templateData, {
partials: {
exportInterface: templates.exportInterface,
exportEnum: templates.exportEnum,
exportType: templates.exportType,
validation: templates.validation,
type: templates.type,
},
});
fs.writeFileSync(path.resolve(outputPath, fileName), templateResult);
// } catch (e) {
// throw new Error(`Could not write model: "${fileName}"`);
// }
});
}

View File

@ -2,6 +2,7 @@ import { writeClientServices } from './writeClientServices';
import * as fs from 'fs';
import { Service } from '../client/interfaces/Service';
import { Language } from '../index';
import { Templates } from './readHandlebarsTemplates';
jest.mock('fs');
@ -15,8 +16,17 @@ describe('writeClientServices', () => {
operations: [],
imports: [],
});
const template = () => 'dummy';
writeClientServices(services, Language.TYPESCRIPT, template, '/');
const templates: Templates = {
index: () => 'dummy',
model: () => 'dummy',
exportInterface: () => 'dummy',
exportEnum: () => 'dummy',
exportType: () => 'dummy',
service: () => 'dummy',
validation: () => 'dummy',
type: () => 'dummy',
};
writeClientServices(services, Language.TYPESCRIPT, templates, '/');
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
});
});

View File

@ -1,24 +1,24 @@
import * as fs from 'fs';
import * as handlebars from 'handlebars';
import * as path from 'path';
import { Service } from '../client/interfaces/Service';
import { Language } from '../index';
import { getFileName } from './getFileName';
import { exportService } from './exportService';
import { Templates } from './readHandlebarsTemplates';
/**
* Generate Services using the Handlebar template and write to disk.
* @param services: Array of Services to write.
* @param language: The output language (Typescript or javascript).
* @param template: The template that is used to write the file.
* @param templates: The loaded handlebar templates.
* @param outputPath:
*/
export function writeClientServices(services: Map<string, Service>, language: Language, template: handlebars.TemplateDelegate, outputPath: string): void {
export function writeClientServices(services: Map<string, Service>, language: Language, templates: Templates, outputPath: string): void {
services.forEach(service => {
const fileName = getFileName(service.name, language);
try {
const templateData = exportService(service);
const templateResult = template(templateData);
const templateResult = templates.model(templateData);
fs.writeFileSync(path.resolve(outputPath, fileName), templateResult);
} catch (e) {
throw new Error(`Could not write service: "${fileName}"`);