- Getting good formatted results now

This commit is contained in:
Ferdi Koomen 2019-11-20 17:18:44 +01:00
parent 266a0dadba
commit 76690fbe2d
36 changed files with 629 additions and 423 deletions

View File

@ -1,47 +0,0 @@
import { getType } from './getType';
import { PrimaryType } from './constants';
import { OpenApiItems } from '../interfaces/OpenApiItems';
export interface ArrayType {
type: string;
base: string;
template?: string;
default?: any;
imports: string[];
}
export function getArrayType(items: OpenApiItems): ArrayType {
const result: ArrayType = {
type: PrimaryType.OBJECT,
base: PrimaryType.OBJECT,
default: items.default,
imports: [],
};
// If the parameter has a type than it can be a basic or generic type.
if (items.type) {
const itemsType = getType(items.type);
result.type = itemsType.type;
result.base = itemsType.base;
result.template = itemsType.template;
result.imports.push(...itemsType.imports);
// If the parameter is an Array type, we check for the child type,
// so we can create a typed array, otherwise this will be a "any[]".
if (items.type === 'array' && items.items) {
const arrayType = getArrayType(items.items);
result.type = `${arrayType.type}[]`;
result.base = arrayType.base;
result.template = arrayType.template;
result.imports.push(...arrayType.imports);
}
}
// if (items.enum) {
// result.type = getEnumType(items.enum, true);
// result.base = 'string';
// result.imports = [];
// }
return result;
}

View File

@ -100,35 +100,36 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
return result;
}
if (definition.allOf) {
definition.allOf.forEach(parent => {
if (parent.$ref) {
const parentRef = getType(parent.$ref);
result.extends.push(parentRef.type);
result.imports.push(parentRef.base);
}
if (parent.type === 'object' && parent.properties) {
const properties = getModelProperties(openApi, parent);
properties.forEach(property => {
result.properties.push(property);
result.imports.push(...property.imports);
});
}
});
if (definition.type === 'object') {
result.export = 'interface';
result.type = PrimaryType.OBJECT;
result.base = PrimaryType.OBJECT;
}
if (definition.type === 'object' && definition.properties) {
const properties = getModelProperties(openApi, definition);
properties.forEach(property => {
result.properties.push(property);
result.imports.push(...property.imports);
});
result.export = 'interface';
result.type = PrimaryType.OBJECT;
result.base = PrimaryType.OBJECT;
if (definition.allOf) {
definition.allOf.forEach(parent => {
if (parent.$ref) {
const parentRef = getType(parent.$ref);
result.extends.push(parentRef.type);
result.imports.push(parentRef.base);
}
if (parent.type === 'object' && parent.properties) {
const properties = getModelProperties(openApi, parent);
properties.forEach(property => {
result.properties.push(property);
result.imports.push(...property.imports);
});
}
});
}
if (definition.properties) {
const properties = getModelProperties(openApi, definition);
properties.forEach(property => {
result.properties.push(property);
result.imports.push(...property.imports);
});
}
return result;
}

View File

@ -1,36 +0,0 @@
import { OpenApiSchema } from '../interfaces/OpenApiSchema';
import { OpenApi } from '../interfaces/OpenApi';
import { PrimaryType } from './constants';
export interface SchemaReference {
type: string;
base: string;
template: string | null;
imports: string[];
}
export function getSchemaReference(openApi: OpenApi, schema: OpenApiSchema): SchemaReference {
const result: SchemaReference = {
type: PrimaryType.OBJECT,
base: PrimaryType.OBJECT,
template: null,
imports: [],
};
if (schema.$ref) {
// const itemSchemaType: Type = getType(schema.$ref);
// result.type = itemSchemaType.type;
// result.base = itemSchemaType.base;
// result.template = itemSchemaType.template;
// result.imports.push(...itemSchemaType.imports);
} else {
// const item: OpenApiSchema = getRef<OpenApiSchema>(openApi, schema);
// const itemSchema: Schema = getSchema(openApi, item, 'unknown');
// result.type = itemSchema.type;
// result.base = itemSchema.base;
// result.template = itemSchema.template;
// result.imports.push(...itemSchema.imports);
}
return result;
}

View File

@ -1,18 +0,0 @@
import { EOL } from 'os';
import { Model } from '../../../client/interfaces/Model';
export function getTypeFromProperties(properties: Model[]): string {
return [
`{`,
...properties.map(property => {
let type = '';
type = `${type}${property.readOnly ? 'readonly ' : ''}`;
type = `${type}${property.name}`;
type = `${type}${property.required ? '' : '?'}`;
type = `${type}: ${property.type}`;
type = `${type}${property.nullable ? ' | null' : ''}`;
return `${type},`;
}),
`}`,
].join(EOL);
}

View File

@ -1,5 +0,0 @@
import { Model } from '../../../client/interfaces/Model';
export function getValidationForArray(name: string, model: Model): string {
return `yup.array<${name ? name : 'any'}>().of(${model.validation ? model.validation : 'yup.mixed()'})`;
}

View File

@ -1,5 +0,0 @@
import { Type } from '../../../client/interfaces/Type';
export function getValidationForArrayRef(ref: Type): string {
return `yup.array<${ref.type}>().of(${ref.base}.schema)`;
}

View File

@ -1,16 +0,0 @@
import { Model } from '../../../client/interfaces/Model';
import { EOL } from 'os';
export function getValidationForDictionary(name: string, model: Model): string {
/* prettier-ignore */
return [
`yup.lazy<Dictionary<${model.type}>>(value =>`,
`yup.object<Dictionary<${model.type}>>().shape(`,
`Object.entries(value).reduce((obj, item) => ({`,
`...obj,`,
`[item[0]]: ${model.validation ? model.validation : 'yup.mixed()'},`,
`}), {})`,
`)`,
`)`
].join(EOL);
}

View File

@ -1,16 +0,0 @@
import { Type } from '../../../client/interfaces/Type';
import { EOL } from 'os';
export function getValidationForDictionaryRef(type: Type): string {
/* prettier-ignore */
return [
`yup.lazy<Dictionary<${type.type}>>(value =>`,
`yup.object<Dictionary<${type.type}>>().shape(`,
`Object.entries(value).reduce((obj, item) => ({`,
`...obj,`,
`[item[0]]: ${type.base}.schema,`,
`}), {})`,
`)`,
`)`
].join(EOL);
}

View File

@ -1,16 +0,0 @@
import { Enum } from '../../../client/interfaces/Enum';
import { EOL } from 'os';
export function getValidationForEnum(name: string, enumerators: Enum[]): string {
return [
`yup.mixed${name ? `<${name}>` : ''}().oneOf([`,
...enumerators.map(enumerator => {
if (name) {
return `${name}.${enumerator.name},`;
} else {
return `${enumerator.value},`;
}
}),
`])`,
].join(EOL);
}

View File

@ -1,18 +0,0 @@
import { EOL } from 'os';
import { Model } from '../../../client/interfaces/Model';
export function getValidationForProperties(name: string, model: Model): string {
return [
...model.extends.map(extend => `${extend}.schema.concat(`),
`yup.object${name ? `<${name}>` : ''}().shape({`,
...model.properties.map(property => {
let validation = '';
validation = `${validation}${property.name}: yup.lazy(() => ${property.validation}.default(undefined))`;
validation = `${validation}${property.required ? '.required()' : ''}`;
validation = `${validation}${property.nullable ? '.nullable()' : ''}`;
return `${validation},`;
}),
`}).noUnknown()`,
...model.extends.map(() => `)`),
].join(EOL);
}

View File

@ -1,5 +0,0 @@
import { Type } from '../../../client/interfaces/Type';
export function getValidationForRef(ref: Type): string {
return `${ref.base}.schema`;
}

View File

@ -1,18 +0,0 @@
import { PrimaryType } from './constants';
import { Type } from '../../../client/interfaces/Type';
export function getValidationForType(type: Type): string {
let validation = `yup.mixed<${type.type}>()`;
switch (type.type) {
case PrimaryType.BOOLEAN:
validation = `yup.boolean()`;
break;
case PrimaryType.NUMBER:
validation = `yup.number()`;
break;
case PrimaryType.STRING:
validation = `yup.string()`;
break;
}
return validation;
}

View File

@ -7,13 +7,16 @@ export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}};
export namespace {{{name}}} {
export const schema = {{>validation}};
{{#indent}}
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 });
}
{{/indent}}
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 });
}
}

View File

@ -7,13 +7,16 @@ export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}};
export namespace {{{name}}} {
export const schema = {{>validation}};
{{#indent}}
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 });
}
{{/indent}}
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 });
}
}

View File

@ -11,13 +11,16 @@ export enum {{{name}}} {
export namespace {{{name}}} {
export const schema = {{>validation}};
{{#indent}}
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 });
}
{{/indent}}
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 });
}
}

View File

@ -7,13 +7,16 @@ export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}};
export namespace {{{name}}} {
export const schema = {{>validation}};
{{#indent}}
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 });
}
{{/indent}}
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 });
}
}

View File

@ -3,39 +3,50 @@
* {{{description}}}
*/
{{/if}}
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 interface {{{name}}}{{{template}}}{{#if extends}} extends {{#each extends}}{{{this}}}{{#unless @last}}, {{/unless}}{{/each}}{{/if}} {
{{#indent}}
{{#each properties}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless required}}?{{/unless}}: {{>type}}{{#if nullable}} | null{{/if}};
{{/each}}
{{/indent}}
}
export namespace {{{name}}} {
{{#each enums}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
export enum {{{name}}} {
{{#each values}}
{{{name}}} = {{{value}}},
{{/each}}
}
{{#indent}}
{{#each enums}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
export enum {{{name}}} {
{{#each values}}
{{{name}}} = {{{value}}},
{{/each}}
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 });
}
}
{{/each}}
export const schema: yup.ObjectSchema<{{{name}}}{{{template}}}> = (
{{#indent}}
{{>validation}}
{{/indent}}
/**/);
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 });
}
{{/indent}}
}

View File

@ -2,13 +2,16 @@ export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}};
export namespace {{{name}}} {
export const schema = {{>validation}};
{{#indent}}
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 });
}
{{/indent}}
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 });
}
}

View File

@ -2,8 +2,8 @@
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
{{#if imports}}
{{#if imports}}
{{#each imports}}
import { {{{this}}} } from '../models/{{{this}}}';
{{/each}}

View File

@ -1,12 +1,12 @@
{
{{#each properties}}
{{#each properties}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless required}}?{{/unless}}: {{>type}}{{#if nullable}} | null{{/if}},
{{/each}}
{{/each}}
}
{{#indent}}
{{#each properties}}
{{#if description}}
/**
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless required}}?{{/unless}}: {{>type}}{{#if nullable}} | null{{/if}},
{{/each}}
{{/indent}}
/**/}

View File

@ -1,19 +1,31 @@
{{~#if link~}}
yup.lazy<Dictionary<{{>type link}}>>(value =>
yup.object<Dictionary<{{>type link}}>>().shape(
Object.entries(value).reduce((obj, item) => ({
...obj,
[item[0]]: {{>validation link}},
}), {})
)
)
{{#indent}}
yup.object<Dictionary<{{>type link}}>>().shape(
{{#indent}}
Object.entries(value).reduce((obj, item) => ({
{{#indent}}
...obj,
[item[0]]: {{>validation link}},
{{/indent}}
/**/}), {})
{{/indent}}
/**/)
{{/indent}}
/**/)
{{~else~}}
yup.lazy<Dictionary<{{{type}}}>>(value =>
yup.object<Dictionary<{{{type}}}>>().shape(
Object.entries(value).reduce((obj, item) => ({
...obj,
[item[0]]: {{{base}}}.schema,
}), {})
)
)
{{#indent}}
yup.object<Dictionary<{{{type}}}>>().shape(
{{#indent}}
Object.entries(value).reduce((obj, item) => ({
{{#indent}}
...obj,
[item[0]]: {{{base}}}.schema,
{{/indent}}
/**/}), {})
{{/indent}}
/**/)
{{/indent}}
/**/)
{{~/if~}}

View File

@ -1,15 +1,17 @@
{{~#if extends~}}
{{#if extends}}
{{#each extends}}
{{{this}}}.schema.concat(
{{/each}}
{{~/if~}}
{{/if}}
yup.object{{#if name}}<{{{name}}}>{{/if}}().shape({
{{#each properties}}
{{{name}}}: yup.lazy(() => {{>validation}}.default(undefined)){{#if required}}.required(){{/if}}{{#if nullable}}.nullable(){{/if}},
{{/each}}
}).noUnknown()
{{~#if extends~}}
{{#indent}}
{{#each properties}}
{{{name}}}: yup.lazy(() => {{>validation}}.default(undefined)){{#if required}}.required(){{/if}}{{#if nullable}}.nullable(){{/if}},
{{/each}}
{{/indent}}
/**/}).noUnknown()
{{#if extends}}
{{#each extends}}
)
{{/each}}
{{~/if~}}
{{/if}}

View File

@ -15,18 +15,12 @@ export function exportModel(model: Model): Model {
const nameB = b.toLowerCase();
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);
}),
properties: model.properties.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, index, arr) => {
return arr.findIndex(item => item.name === property.name) === index;
})

View File

@ -0,0 +1,10 @@
// Replace " /**/}" with "}"
// Replace " /**/)" with ")"
// Replace " /**/]" with "]"
export function fixIndentation(s: string): string {
return s
.replace(/\s{4}\/\*\*\/\}/g, '}')
.replace(/\s{4}\/\*\*\/\)/g, ')')
.replace(/\s{4}\/\*\*\/\]/g, ']');
}

View File

@ -5,6 +5,7 @@ describe('getModelNames', () => {
it('should return sorted list', () => {
const models = new Map<string, Model>();
models.set('John', {
export: 'interface',
name: 'John',
type: 'John',
base: 'John',
@ -19,9 +20,9 @@ describe('getModelNames', () => {
enum: [],
enums: [],
properties: [],
validation: null,
});
models.set('Jane', {
export: 'interface',
name: 'Jane',
type: 'Jane',
base: 'Jane',
@ -36,9 +37,9 @@ describe('getModelNames', () => {
enum: [],
enums: [],
properties: [],
validation: null,
});
models.set('Doe', {
export: 'interface',
name: 'Doe',
type: 'Doe',
base: 'Doe',
@ -53,7 +54,6 @@ describe('getModelNames', () => {
enum: [],
enums: [],
properties: [],
validation: null,
});
expect(getModelNames(new Map<string, Model>())).toEqual([]);

View File

@ -1,21 +1,24 @@
import * as fs from 'fs';
import * as handlebars from 'handlebars';
import * as Handlebars from 'handlebars';
/**
* Read and compile the Handlebars template.
* @param filePath
*/
export function readHandlebarsTemplate(filePath: string): handlebars.TemplateDelegate {
export function readHandlebarsTemplate(filePath: string): Handlebars.TemplateDelegate {
if (fs.existsSync(filePath)) {
try {
const template = fs
.readFileSync(filePath, 'utf8')
.toString()
.trim();
return handlebars.compile(template, {
return Handlebars.compile(template, {
strict: true,
noEscape: true,
preventIndent: true,
knownHelpersOnly: true,
knownHelpers: {
indent: true,
eq: true,
},
});

View File

@ -1,32 +1,13 @@
import * as handlebars from 'handlebars';
import * as Handlebars from 'handlebars';
import { readHandlebarsTemplate } from './readHandlebarsTemplate';
import { Language } from '../index';
import * as path from 'path';
import { registerHandlebarHelpers } from './registerHandlebarHelpers';
export interface Templates {
index: handlebars.TemplateDelegate;
model: handlebars.TemplateDelegate;
service: handlebars.TemplateDelegate;
exportGeneric: handlebars.TemplateDelegate;
exportReference: handlebars.TemplateDelegate;
exportInterface: handlebars.TemplateDelegate;
exportEnum: handlebars.TemplateDelegate;
exportDictionary: handlebars.TemplateDelegate;
exportArray: handlebars.TemplateDelegate;
validation: handlebars.TemplateDelegate;
validationForGeneric: handlebars.TemplateDelegate;
validationForReference: handlebars.TemplateDelegate;
validationForEnum: handlebars.TemplateDelegate;
validationForInterface: handlebars.TemplateDelegate;
validationForDictionary: handlebars.TemplateDelegate;
validationForArray: handlebars.TemplateDelegate;
type: handlebars.TemplateDelegate;
typeForArray: handlebars.TemplateDelegate;
typeForDictionary: handlebars.TemplateDelegate;
typeForEnum: handlebars.TemplateDelegate;
typeForInterface: handlebars.TemplateDelegate;
typeForReference: handlebars.TemplateDelegate;
typeForGeneric: handlebars.TemplateDelegate;
index: Handlebars.TemplateDelegate;
model: Handlebars.TemplateDelegate;
service: Handlebars.TemplateDelegate;
}
/**
@ -35,18 +16,14 @@ export interface Templates {
* @param language The language we need to generate (Typescript or Javascript).
*/
export function readHandlebarsTemplates(language: Language): Templates {
handlebars.registerHelper('eq', function(a: string, b: string, options: handlebars.HelperOptions): string {
// eslint-disable
// prettier-ignore
// @ts-ignore
return a === b ? options.fn(this) : options.inverse(this);
});
try {
return {
registerHandlebarHelpers();
const templates: Templates = {
index: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/index.hbs`)),
model: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/model.hbs`)),
service: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/service.hbs`)),
};
Handlebars.registerPartial({
exportGeneric: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/exportGeneric.hbs`)),
exportReference: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/exportReference.hbs`)),
exportInterface: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/exportInterface.hbs`)),
@ -67,7 +44,8 @@ export function readHandlebarsTemplates(language: Language): Templates {
typeForInterface: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/typeForInterface.hbs`)),
typeForReference: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/typeForReference.hbs`)),
typeForGeneric: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/typeForGeneric.hbs`)),
};
});
return templates;
} catch (e) {
throw e;
}

View File

@ -0,0 +1,21 @@
import * as Handlebars from 'handlebars';
import { EOL } from 'os';
export function registerHandlebarHelpers(): void {
Handlebars.registerHelper('indent', function(options: Handlebars.HelperOptions): string {
// eslint-disable
// prettier-ignore
// @ts-ignore
return options.fn(this)
.split(EOL)
.map(line => ` ${line}`)
.join(EOL)
});
Handlebars.registerHelper('eq', function(a: string, b: string, options: Handlebars.HelperOptions): string {
// eslint-disable
// prettier-ignore
// @ts-ignore
return a === b ? options.fn(this) : options.inverse(this);
});
}

View File

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

View File

@ -21,12 +21,7 @@ describe('writeClientIndex', () => {
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

@ -12,6 +12,7 @@ describe('writeClientModels', () => {
it('should write to filesystem', () => {
const models = new Map<string, Model>();
models.set('Item', {
export: 'interface',
name: 'Item',
type: 'Item',
base: 'Item',
@ -26,17 +27,11 @@ describe('writeClientModels', () => {
enum: [],
enums: [],
properties: [],
validation: null,
});
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

@ -5,6 +5,7 @@ import { Language } from '../index';
import { getFileName } from './getFileName';
import { exportModel } from './exportModel';
import { Templates } from './readHandlebarsTemplates';
import { fixIndentation } from './fixIndentation';
/**
* Generate Models using the Handlebar template and write to disk.
@ -18,31 +19,8 @@ export function writeClientModels(models: Map<string, Model>, language: Language
const fileName = getFileName(model.name, language);
try {
const templateData = exportModel(model);
const templateResult = templates.model(templateData, {
partials: {
exportGeneric: templates.exportGeneric,
exportReference: templates.exportReference,
exportInterface: templates.exportInterface,
exportEnum: templates.exportEnum,
exportDictionary: templates.exportDictionary,
exportArray: templates.exportArray,
validation: templates.validation,
validationForGeneric: templates.validationForGeneric,
validationForReference: templates.validationForReference,
validationForEnum: templates.validationForEnum,
validationForInterface: templates.validationForInterface,
validationForDictionary: templates.validationForDictionary,
validationForArray: templates.validationForArray,
type: templates.type,
typeForArray: templates.typeForArray,
typeForDictionary: templates.typeForDictionary,
typeForEnum: templates.typeForEnum,
typeForInterface: templates.typeForInterface,
typeForReference: templates.typeForReference,
typeForGeneric: templates.typeForGeneric,
},
});
fs.writeFileSync(path.resolve(outputPath, fileName), templateResult);
const templateResult = templates.model(templateData);
fs.writeFileSync(path.resolve(outputPath, fileName), fixIndentation(templateResult));
} catch (e) {
throw new Error(`Could not write model: "${fileName}"`);
}

View File

@ -19,12 +19,7 @@ describe('writeClientServices', () => {
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

@ -5,6 +5,7 @@ import { Language } from '../index';
import { getFileName } from './getFileName';
import { exportService } from './exportService';
import { Templates } from './readHandlebarsTemplates';
import { fixIndentation } from './fixIndentation';
/**
* Generate Services using the Handlebar template and write to disk.
@ -19,7 +20,7 @@ export function writeClientServices(services: Map<string, Service>, language: La
try {
const templateData = exportService(service);
const templateResult = templates.model(templateData);
fs.writeFileSync(path.resolve(outputPath, fileName), templateResult);
fs.writeFileSync(path.resolve(outputPath, fileName), fixIndentation(templateResult));
} catch (e) {
throw new Error(`Could not write service: "${fileName}"`);
}

View File

@ -80,6 +80,16 @@
"$ref": "#/definitions/ModelWithString"
}
},
"ArrayWithArray": {
"description": "This is a simple array containing an array",
"type": "array",
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"ArrayWithProperties": {
"description": "This is a simple array with properties",
"type": "array",
@ -119,6 +129,16 @@
}
}
},
"DictionaryWithDictionary": {
"description": "This is a string dictionary",
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"DictionaryWithProperties": {
"description": "This is a complex dictionary",
"type": "object",
@ -197,7 +217,7 @@
}
}
},
"ModelWithModelArray": {
"ModelWithArray": {
"description": "This is a model with one property containing an array",
"type": "object",
"properties": {
@ -209,6 +229,18 @@
}
}
},
"ModelWithDictionary": {
"description": "This is a model with one property containing a dictionary",
"type": "object",
"properties": {
"prop": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"ModelLink": {
"description": "This is a model that can have a template??",
"type": "object",
@ -309,6 +341,9 @@
"description": "This is a model that extends another model",
"type": "object",
"allOf": [
{
"$ref": "#/definitions/ModelWithString"
},
{
"$ref": "#/definitions/ModelThatExtends"
},

361
test/mock/v2/spec.json2 Normal file
View File

@ -0,0 +1,361 @@
{
"swagger": "2.0",
"info": {
"version": "v9.0",
"title": "swagger"
},
"host": "localhost:8080",
"basePath": "/api",
"schemes": [
"http"
],
"paths": {
},
"definitions": {
"SimpleInteger": {
"description": "This is a simple number",
"type": "integer"
},
"SimpleBoolean": {
"description": "This is a simple boolean",
"type": "boolean"
},
"SimpleString": {
"description": "This is a simple string",
"type": "string"
},
"SimpleFile": {
"description": "This is a simple file",
"type": "File"
},
"SimpleReference": {
"description": "This is a simple reference",
"$ref": "#/definitions/ModelWithString"
},
"EnumWithStrings": {
"description": "This is a simple enum with strings",
"enum": [
"Success",
"Warning",
"Error"
]
},
"EnumWithNumbers": {
"description": "This is a simple enum with numbers",
"enum": [
1,
2,
3
]
},
"EnumFromDescription": {
"description": "Success=1,Warning=2,Error=3",
"type": "int"
},
"ArrayWithNumbers": {
"description": "This is a simple array with numbers",
"type": "array",
"items": {
"type": "integer"
}
},
"ArrayWithBooleans": {
"description": "This is a simple array with booleans",
"type": "array",
"items": {
"type": "boolean"
}
},
"ArrayWithStrings": {
"description": "This is a simple array with strings",
"type": "array",
"items": {
"type": "string"
}
},
"ArrayWithReferences": {
"description": "This is a simple array with references",
"type": "array",
"items": {
"$ref": "#/definitions/ModelWithString"
}
},
"ArrayWithArray": {
"description": "This is a simple array containing an array",
"type": "array",
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"ArrayWithProperties": {
"description": "This is a simple array with properties",
"type": "array",
"items": {
"type": "object",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "string"
}
}
}
},
"DictionaryWithString": {
"description": "This is a string dictionary",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"DictionaryWithReference": {
"description": "This is a string reference",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ModelWithString"
}
},
"DictionaryWithArray": {
"description": "This is a complex dictionary",
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"DictionaryWithDictionary": {
"description": "This is a string dictionary",
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"DictionaryWithProperties": {
"description": "This is a complex dictionary",
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "string"
}
}
}
},
"ModelWithInteger": {
"description": "This is a model with one number property",
"type": "object",
"properties": {
"prop": {
"description": "This is a simple number property",
"type": "integer"
}
}
},
"ModelWithBoolean": {
"description": "This is a model with one boolean property",
"type": "object",
"properties": {
"prop": {
"description": "This is a simple boolean property",
"type": "boolean"
}
}
},
"ModelWithString": {
"description": "This is a model with one string property",
"type": "object",
"properties": {
"prop": {
"description": "This is a simple string property",
"type": "string"
}
}
},
"ModelWithEnum": {
"description": "This is a model with one enum",
"type": "object",
"properties": {
"prop": {
"description": "This is a simple enum with strings",
"enum": [
"Success",
"Warning",
"Error"
]
}
}
},
"ModelWithEnumFromDescription": {
"description": "This is a model with one enum",
"type": "object",
"properties": {
"prop": {
"type": "integer",
"description": "Success=1,Warning=2,Error=3"
}
}
},
"ModelWithReference": {
"description": "This is a model with one property containing a reference",
"type": "object",
"properties": {
"prop": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"ModelWithArray": {
"description": "This is a model with one property containing an array",
"type": "object",
"properties": {
"prop": {
"type": "array",
"items": {
"$ref": "#/definitions/ModelWithString"
}
}
}
},
"ModelWithDictionary": {
"description": "This is a model with one property containing a dictionary",
"type": "object",
"properties": {
"prop": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"ModelLink": {
"description": "This is a model that can have a template??",
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
},
"ModelWithLink": {
"description": "This is a model that can have a template??",
"type": "object",
"properties": {
"prop": {
"$ref": "#/definitions/ModelLink[ModelWithString]"
}
}
},
"ModelWithCircularReference": {
"description": "This is a model with one property containing a circular reference",
"type": "object",
"properties": {
"prop": {
"$ref": "#/definitions/ModelWithCircularReference"
}
}
},
"ModelWithNestedProperties": {
"description": "This is a model with one nested property",
"type": "object",
"properties": {
"first": {
"type": "object",
"properties": {
"second": {
"type": "object",
"properties": {
"third": {
"type": "string"
}
}
}
}
}
}
},
"ModelWithDuplicateProperties": {
"description": "This is a model with duplicated properties",
"type": "object",
"properties": {
"prop": {
"$ref": "#/definitions/ModelWithString"
},
"prop": {
"$ref": "#/definitions/ModelWithString"
},
"prop": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"ModelWithDuplicateImports": {
"description": "This is a model with duplicated imports",
"type": "object",
"properties": {
"propA": {
"$ref": "#/definitions/ModelWithString"
},
"propB": {
"$ref": "#/definitions/ModelWithString"
},
"propC": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"ModelThatExtends": {
"description": "This is a model that extends another model",
"type": "object",
"allOf": [
{
"$ref": "#/definitions/ModelWithString"
},
{
"type": "object",
"properties": {
"propExtendsA": {
"type": "string"
},
"propExtendsB": {
"$ref": "#/definitions/ModelWithString"
}
}
}
]
},
"ModelThatExtendsExtends": {
"description": "This is a model that extends another model",
"type": "object",
"allOf": [
{
"$ref": "#/definitions/ModelThatExtends"
},
{
"type": "object",
"properties": {
"propExtendsC": {
"type": "string"
},
"propExtendsD": {
"$ref": "#/definitions/ModelWithString"
}
}
}
]
}
}
}