diff --git a/.editorconfig b/.editorconfig index cc133d0c..d741e40b 100755 --- a/.editorconfig +++ b/.editorconfig @@ -4,6 +4,6 @@ root = true end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = false +insert_final_newline = true indent_style = space indent_size = 4 diff --git a/src/client/interfaces/Model.d.ts b/src/client/interfaces/Model.d.ts index 89beab3c..3cdc9dd0 100644 --- a/src/client/interfaces/Model.d.ts +++ b/src/client/interfaces/Model.d.ts @@ -1,12 +1,12 @@ import { Enum } from './Enum'; -import { Validation } from './Validation'; export interface Model { name: string; + export: 'reference' | 'generic' | 'enum' | 'array' | 'dictionary' | 'interface'; type: string; base: string; - link: Model | null; template: string | null; + link: Model | null; description: string | null; readOnly: boolean; required: boolean; @@ -16,5 +16,4 @@ export interface Model { enum: Enum[]; enums: Model[]; properties: Model[]; - validation: Validation | null; } diff --git a/src/client/interfaces/Validation.d.ts b/src/client/interfaces/Validation.d.ts index cbec194d..dd9fbad9 100644 --- a/src/client/interfaces/Validation.d.ts +++ b/src/client/interfaces/Validation.d.ts @@ -1,5 +1,5 @@ export interface Validation { - type: 'ref' | 'type' | 'enum' | 'array' | 'dictionary' | 'property' | 'model'; + type: 'ref' | 'type' | 'enum' | 'array' | 'dictionary' | 'properties'; childType: string | null; childBase: string | null; childValidation: Validation | null; diff --git a/src/openApi/v2/parser/getModel.ts b/src/openApi/v2/parser/getModel.ts index f01e7349..ea7be48c 100644 --- a/src/openApi/v2/parser/getModel.ts +++ b/src/openApi/v2/parser/getModel.ts @@ -12,6 +12,7 @@ import { getModelProperties } from './getModelProperties'; export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: string = ''): Model { const result: Model = { name, + export: 'interface', type: PrimaryType.OBJECT, base: PrimaryType.OBJECT, template: null, @@ -25,124 +26,80 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri enum: [], enums: [], properties: [], - validation: null, }; if (definition.$ref) { const definitionRef = getType(definition.$ref); + result.export = 'reference'; result.type = definitionRef.type; result.base = definitionRef.base; result.template = definitionRef.template; result.imports.push(...definitionRef.imports); - result.validation = { - type: 'ref', - childType: null, - childBase: null, - childValidation: null, - }; return result; } - // If the param is a enum then return the values as an inline type. if (definition.enum) { const enumerators = getEnum(definition.enum); if (enumerators.length) { + result.export = 'enum'; result.type = getEnumType(enumerators); result.base = PrimaryType.STRING; result.enum.push(...enumerators); - result.validation = { - type: 'enum', - childType: null, - childBase: null, - childValidation: null, - }; return result; } } - // If the param is a enum then return the values as an inline type. if (definition.type === 'int' && definition.description) { const enumerators = getEnumFromDescription(definition.description); if (enumerators.length) { + result.export = 'enum'; result.type = getEnumType(enumerators); result.base = PrimaryType.NUMBER; result.enum.push(...enumerators); - result.validation = { - type: 'enum', - childType: null, - childBase: null, - childValidation: null, - }; return result; } } - // If the schema is an Array type, we check for the child type, - // so we can create a typed array, otherwise this will be a "any[]". if (definition.type === 'array' && definition.items) { if (definition.items.$ref) { const arrayItems = getType(definition.items.$ref); - result.type = `Array<${arrayItems.type}>`; - result.base = 'Array'; + result.export = 'array'; + result.type = arrayItems.type; + result.base = arrayItems.base; 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 = `Array<${arrayItems.type}>`; - result.base = 'Array'; + result.export = 'array'; + result.type = arrayItems.type; + result.base = arrayItems.base; result.template = arrayItems.template; result.link = arrayItems; result.imports.push(...arrayItems.imports); - result.validation = { - type: 'array', - childType: arrayItems.type, - childBase: arrayItems.base, - childValidation: arrayItems.validation, - }; } return result; } - // If a property has additionalProperties, then it likely to be a dictionary type. - // In that case parse the related property and assume it lives inside a string - // based dictionary: { [key:string]: MyType } if (definition.type === 'object' && definition.additionalProperties && typeof definition.additionalProperties === 'object') { if (definition.additionalProperties.$ref) { const additionalProperties = getType(definition.additionalProperties.$ref); - result.type = `Dictionary<${additionalProperties.type}>`; - result.base = 'Dictionary'; - result.template = additionalProperties.type; + result.export = 'dictionary'; + result.type = additionalProperties.type; + result.base = additionalProperties.base; + result.template = additionalProperties.template; result.imports.push(...additionalProperties.imports); - result.validation = { - 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.export = 'dictionary'; + result.type = additionalProperties.type; + result.base = additionalProperties.base; + result.template = additionalProperties.template; result.link = additionalProperties; result.imports.push(...additionalProperties.imports); - result.validation = { - type: 'dictionary', - childType: additionalProperties.type, - childBase: additionalProperties.base, - childValidation: additionalProperties.validation, - }; } return result; } - // Check if this model extends other models if (definition.allOf) { definition.allOf.forEach(parent => { if (parent.$ref) { @@ -158,14 +115,9 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri }); } }); + result.export = 'interface'; result.type = PrimaryType.OBJECT; result.base = PrimaryType.OBJECT; - result.validation = { - type: 'model', - childType: null, - childBase: null, - childValidation: null, - }; } if (definition.type === 'object' && definition.properties) { @@ -174,30 +126,20 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri result.properties.push(property); result.imports.push(...property.imports); }); + result.export = 'interface'; result.type = PrimaryType.OBJECT; result.base = PrimaryType.OBJECT; - result.validation = { - type: 'model', - childType: null, - childBase: null, - childValidation: null, - }; return result; } // If the schema has a type than it can be a basic or generic type. if (definition.type) { const definitionType = getType(definition.type); + result.export = 'generic'; result.type = definitionType.type; result.base = definitionType.base; result.template = definitionType.template; result.imports.push(...definitionType.imports); - result.validation = { - type: 'type', - childType: null, - childBase: null, - childValidation: null, - }; return result; } diff --git a/src/openApi/v2/parser/getModelProperties.ts b/src/openApi/v2/parser/getModelProperties.ts index 352fc543..8abbcf14 100644 --- a/src/openApi/v2/parser/getModelProperties.ts +++ b/src/openApi/v2/parser/getModelProperties.ts @@ -16,6 +16,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): const prop = getType(property.$ref); result.push({ name: propertyName, + export: 'reference', type: prop.type, base: prop.base, template: prop.template, @@ -29,17 +30,12 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): enum: [], enums: [], properties: [], - validation: { - type: 'property', - childType: prop.type, - childBase: prop.base, - childValidation: null, - }, }); } else { const prop = getModel(openApi, property); result.push({ name: propertyName, + export: prop.export, type: prop.type, base: prop.base, template: prop.template, @@ -53,12 +49,6 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema): enum: prop.enum, enums: prop.enums, properties: prop.properties, - validation: { - type: 'property', - childType: prop.type, - childBase: prop.base, - childValidation: prop.validation, - }, }); } } diff --git a/src/openApi/v2/parser/getType.ts b/src/openApi/v2/parser/getType.ts index 6caffb25..7ab373f4 100644 --- a/src/openApi/v2/parser/getType.ts +++ b/src/openApi/v2/parser/getType.ts @@ -16,35 +16,24 @@ export function getType(value?: string, template?: string): Type { imports: [], }; - // Remove definitions prefix and cleanup string. const valueClean = stripNamespace(value || ''); - // Check of we have an Array type or generic type, for instance: "Link[Model]". if (/\[.*\]$/g.test(valueClean)) { const matches = valueClean.match(/(.*?)\[(.*)\]$/); if (matches && matches.length) { - // Both of the types can be complex types so parse each of them. const match1 = getType(matches[1]); 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 "Array". - if (match1.type === 'Array') { - result.type = `Array<${match2.type}>`; - result.base = match2.type; - match1.imports = []; - } else if (match2.type === '') { - result.type = match1.type; - result.base = match1.type; - result.template = match1.type; - match2.imports = []; - } else { + if (match2.type) { result.type = `${match1.type}<${match2.type}>`; result.base = match1.type; result.template = match2.type; + } else { + result.type = match1.type; + result.base = match1.type; + result.template = match1.type; } - // Either way we need to add the found imports result.imports.push(...match1.imports); result.imports.push(...match2.imports); } diff --git a/src/templates/typescript/exportArray.hbs b/src/templates/typescript/exportArray.hbs new file mode 100644 index 00000000..2baf5149 --- /dev/null +++ b/src/templates/typescript/exportArray.hbs @@ -0,0 +1,14 @@ +export type {{{name}}} = Array<{{>type}}>{{#if nullable}} | null{{/if}}; + +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 }); + } +} diff --git a/src/templates/typescript/exportType.hbs b/src/templates/typescript/exportDictionary.hbs similarity index 94% rename from src/templates/typescript/exportType.hbs rename to src/templates/typescript/exportDictionary.hbs index 3478bcc6..1f71e092 100644 --- a/src/templates/typescript/exportType.hbs +++ b/src/templates/typescript/exportDictionary.hbs @@ -1,5 +1,4 @@ export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}}; -{{#if validation}} export namespace {{{name}}} { @@ -13,4 +12,3 @@ export namespace {{{name}}} { return schema.validateSync(value, { strict: true }); } } -{{/if}} \ No newline at end of file diff --git a/src/templates/typescript/exportEnum.hbs b/src/templates/typescript/exportEnum.hbs index 36665ecf..67c54a32 100644 --- a/src/templates/typescript/exportEnum.hbs +++ b/src/templates/typescript/exportEnum.hbs @@ -1,9 +1,8 @@ export enum {{{name}}} { - {{#each symbols}} + {{#each enum}} {{{name}}} = {{{value}}}, {{/each}} } -{{#if validation}} export namespace {{{name}}} { @@ -17,4 +16,3 @@ export namespace {{{name}}} { return schema.validateSync(value, { strict: true }); } } -{{/if}} \ No newline at end of file diff --git a/src/templates/typescript/exportGeneric.hbs b/src/templates/typescript/exportGeneric.hbs new file mode 100644 index 00000000..1f71e092 --- /dev/null +++ b/src/templates/typescript/exportGeneric.hbs @@ -0,0 +1,14 @@ +export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}}; + +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 }); + } +} diff --git a/src/templates/typescript/exportInterface.hbs b/src/templates/typescript/exportInterface.hbs index e1c2b49a..4e50fe8e 100644 --- a/src/templates/typescript/exportInterface.hbs +++ b/src/templates/typescript/exportInterface.hbs @@ -24,7 +24,6 @@ export namespace {{{name}}} { } {{/each}} - {{#if validation}} export const schema = {{>validation}}; export function validate(value: any): Promise<{{{name}}}{{{template}}}> { @@ -34,5 +33,4 @@ export namespace {{{name}}} { export function validateSync(value: any): {{{name}}}{{{template}}} { return schema.validateSync(value, { strict: true }); } - {{/if}} -} \ No newline at end of file +} diff --git a/src/templates/typescript/exportReference.hbs b/src/templates/typescript/exportReference.hbs new file mode 100644 index 00000000..1f71e092 --- /dev/null +++ b/src/templates/typescript/exportReference.hbs @@ -0,0 +1,14 @@ +export type {{{name}}} = {{>type}}{{#if nullable}} | null{{/if}}; + +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 }); + } +} diff --git a/src/templates/typescript/index.hbs b/src/templates/typescript/index.hbs index 0a412286..df73b249 100644 --- a/src/templates/typescript/index.hbs +++ b/src/templates/typescript/index.hbs @@ -18,4 +18,4 @@ export { {{{this}}} } from './models/{{{this}}}'; {{#each services}} export { {{{this}}} } from './services/{{{this}}}'; {{/each}} -{{/if}} \ No newline at end of file +{{/if}} diff --git a/src/templates/typescript/model.hbs b/src/templates/typescript/model.hbs index 6100b5bf..378d0357 100644 --- a/src/templates/typescript/model.hbs +++ b/src/templates/typescript/model.hbs @@ -8,19 +8,25 @@ import { {{{this}}} } from '../models/{{{this}}}'; {{/each}} {{/if}} -{{#if validation}} +import Dictionary from '../core/Dictionary'; import * as yup from 'yup'; -{{/if}} {{#if description}} /** * {{{description}}} */ {{/if}} -{{#if properties}} -{{> exportInterface}} -{{else if enum}} -{{> exportEnum}} -{{else}} -{{> exportType}} -{{/if}} \ No newline at end of file + +{{~#eq export 'reference'~}} +{{>exportReference}} +{{~else eq export 'generic'~}} +{{>exportGeneric}} +{{~else eq export 'enum'~}} +{{>exportEnum}} +{{~else eq export 'array'~}} +{{>exportArray}} +{{~else eq export 'dictionary'~}} +{{>exportDictionary}} +{{~else eq export 'interface'~}} +{{>exportInterface}} +{{~/eq~}} diff --git a/src/templates/typescript/service.hbs b/src/templates/typescript/service.hbs index 27244d57..f610b13b 100644 --- a/src/templates/typescript/service.hbs +++ b/src/templates/typescript/service.hbs @@ -46,23 +46,31 @@ export class {{{name}}} { const result = await request({ method: '{{{method}}}', - path: `{{{path}}}`,{{#if parametersHeader}} + path: `{{{path}}}`, + {{~#if parametersHeader~}} headers: { {{#each parametersHeader}} '{{{prop}}}': {{{name}}}, {{/each}} - },{{/if}}{{#if parametersQuery}} + }, + {{~/if~}} + {{~#if parametersQuery~}} query: { {{#each parametersQuery}} '{{{prop}}}': {{{name}}}, {{/each}} - },{{/if}}{{#if parametersForm}} + }, + {{~/if~}} + {{~#if parametersForm~}} formData: { {{#each parametersForm}} '{{{prop}}}': {{{name}}}, {{/each}} - },{{/if}}{{#if parametersBody}} - body: {{{parametersBody.name}}},{{/if}} + }, + {{~/if~}} + {{~#if parametersBody~}} + body: {{{parametersBody.name}}}, + {{~/if~}} }); {{#if errors}} @@ -81,4 +89,4 @@ export class {{{name}}} { } {{/each}} -} \ No newline at end of file +} diff --git a/src/templates/typescript/type.hbs b/src/templates/typescript/type.hbs index fbbe83b1..922f6912 100644 --- a/src/templates/typescript/type.hbs +++ b/src/templates/typescript/type.hbs @@ -1,5 +1,13 @@ -{{#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}} \ No newline at end of file +{{~#eq export 'reference'~}} +{{>typeForReference}} +{{~else eq export 'generic'~}} +{{>typeForGeneric}} +{{~else eq export 'enum'~}} +{{>typeForEnum}} +{{~else eq export 'array'~}} +{{>typeForArray}} +{{~else eq export 'dictionary'~}} +{{>typeForDictionary}} +{{~else eq export 'interface'~}} +{{>typeForInterface}} +{{~/eq~}} diff --git a/src/templates/typescript/typeForArray.hbs b/src/templates/typescript/typeForArray.hbs new file mode 100644 index 00000000..9e88f8f9 --- /dev/null +++ b/src/templates/typescript/typeForArray.hbs @@ -0,0 +1,12 @@ +{{~#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~}} +// TODO: Per type ook een nette export maken! diff --git a/src/templates/typescript/typeForDictionary.hbs b/src/templates/typescript/typeForDictionary.hbs new file mode 100644 index 00000000..9e88f8f9 --- /dev/null +++ b/src/templates/typescript/typeForDictionary.hbs @@ -0,0 +1,12 @@ +{{~#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~}} +// TODO: Per type ook een nette export maken! diff --git a/src/templates/typescript/typeForEnum.hbs b/src/templates/typescript/typeForEnum.hbs new file mode 100644 index 00000000..9e88f8f9 --- /dev/null +++ b/src/templates/typescript/typeForEnum.hbs @@ -0,0 +1,12 @@ +{{~#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~}} +// TODO: Per type ook een nette export maken! diff --git a/src/templates/typescript/typeForGeneric.hbs b/src/templates/typescript/typeForGeneric.hbs new file mode 100644 index 00000000..9e88f8f9 --- /dev/null +++ b/src/templates/typescript/typeForGeneric.hbs @@ -0,0 +1,12 @@ +{{~#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~}} +// TODO: Per type ook een nette export maken! diff --git a/src/templates/typescript/typeForInterface.hbs b/src/templates/typescript/typeForInterface.hbs new file mode 100644 index 00000000..9e88f8f9 --- /dev/null +++ b/src/templates/typescript/typeForInterface.hbs @@ -0,0 +1,12 @@ +{{~#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~}} +// TODO: Per type ook een nette export maken! diff --git a/src/templates/typescript/typeForReference.hbs b/src/templates/typescript/typeForReference.hbs new file mode 100644 index 00000000..9e88f8f9 --- /dev/null +++ b/src/templates/typescript/typeForReference.hbs @@ -0,0 +1,12 @@ +{{~#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~}} +// TODO: Per type ook een nette export maken! diff --git a/src/templates/typescript/validation.hbs b/src/templates/typescript/validation.hbs index 64793b21..76691640 100644 --- a/src/templates/typescript/validation.hbs +++ b/src/templates/typescript/validation.hbs @@ -1 +1,13 @@ -yup.mixed() \ No newline at end of file +{{~#eq export 'reference'~}} +{{>validationForReference}} +{{~else eq export 'generic'~}} +{{>validationForGeneric}} +{{~else eq export 'enum'~}} +{{>validationForEnum}} +{{~else eq export 'array'~}} +{{>validationForArray}} +{{~else eq export 'dictionary'~}} +{{>validationForDictionary}} +{{~else eq export 'interface'~}} +{{>validationForInterface}} +{{~/eq~}} diff --git a/src/templates/typescript/validationForArray.hbs b/src/templates/typescript/validationForArray.hbs new file mode 100644 index 00000000..429f752a --- /dev/null +++ b/src/templates/typescript/validationForArray.hbs @@ -0,0 +1 @@ +yup.mixed() diff --git a/src/templates/typescript/validationForDictionary.hbs b/src/templates/typescript/validationForDictionary.hbs new file mode 100644 index 00000000..429f752a --- /dev/null +++ b/src/templates/typescript/validationForDictionary.hbs @@ -0,0 +1 @@ +yup.mixed() diff --git a/src/templates/typescript/validationForEnum.hbs b/src/templates/typescript/validationForEnum.hbs new file mode 100644 index 00000000..a1166a74 --- /dev/null +++ b/src/templates/typescript/validationForEnum.hbs @@ -0,0 +1,9 @@ +yup.mixed{{#if name}}<{{{name}}}>{{/if}}().oneOf([ + {{#each enum}} + {{#if ../name}} + {{{../name}}}.{{{name}}}, + {{else}} + {{{value}}}, + {{/if}} + {{/each}} +]) diff --git a/src/templates/typescript/validationForGeneric.hbs b/src/templates/typescript/validationForGeneric.hbs new file mode 100644 index 00000000..5021c4c8 --- /dev/null +++ b/src/templates/typescript/validationForGeneric.hbs @@ -0,0 +1,9 @@ +{{~#eq type 'boolean'~}} +yup.boolean() +{{~else eq type 'number'~}} +yup.number() +{{~else eq type 'string'~}} +yup.string() +{{~else~}} +yup.mixed<{{{type}}}>() +{{~/eq~}} diff --git a/src/templates/typescript/validationForInterface.hbs b/src/templates/typescript/validationForInterface.hbs new file mode 100644 index 00000000..79862aac --- /dev/null +++ b/src/templates/typescript/validationForInterface.hbs @@ -0,0 +1,15 @@ +{{~#if extends~}} +{{#each extends}} +{{{this}}}.schema.concat( +{{/each}} +{{~/if~}} +yup.object{{#if name}}<{{{name}}}>{{/if}}().shape({ + {{#each properties}} + {{{name}}}: yup.lazy(() => {{>validation this}}.default(undefined)){{#if required}}.required(){{/if}}{{#if nullable}}.nullable(){{/if}}, + {{/each}} +}).noUnknown() +{{~#if extends~}} +{{#each extends}} +) +{{/each}} +{{~/if~}} diff --git a/src/templates/typescript/validationForReference.hbs b/src/templates/typescript/validationForReference.hbs new file mode 100644 index 00000000..bb7edfd1 --- /dev/null +++ b/src/templates/typescript/validationForReference.hbs @@ -0,0 +1 @@ +{{{base}}}.schema diff --git a/src/utils/readHandlebarsTemplate.ts b/src/utils/readHandlebarsTemplate.ts index 44df7f4d..cd7e894d 100644 --- a/src/utils/readHandlebarsTemplate.ts +++ b/src/utils/readHandlebarsTemplate.ts @@ -7,10 +7,17 @@ import * as handlebars from 'handlebars'; */ export function readHandlebarsTemplate(filePath: string): handlebars.TemplateDelegate { if (fs.existsSync(filePath)) { - const template = fs.readFileSync(filePath, 'utf8').toString(); try { + const template = fs + .readFileSync(filePath, 'utf8') + .toString() + .trim(); return handlebars.compile(template, { strict: true, + knownHelpersOnly: true, + knownHelpers: { + eq: true, + }, }); } catch (e) { throw new Error(`Could not compile Handlebar template: "${filePath}"`); diff --git a/src/utils/readHandlebarsTemplates.ts b/src/utils/readHandlebarsTemplates.ts index f8370b81..0000300b 100644 --- a/src/utils/readHandlebarsTemplates.ts +++ b/src/utils/readHandlebarsTemplates.ts @@ -6,12 +6,27 @@ import * as path from 'path'; export interface Templates { index: handlebars.TemplateDelegate; model: handlebars.TemplateDelegate; + service: handlebars.TemplateDelegate; + exportGeneric: handlebars.TemplateDelegate; + exportReference: handlebars.TemplateDelegate; exportInterface: handlebars.TemplateDelegate; exportEnum: handlebars.TemplateDelegate; - exportType: handlebars.TemplateDelegate; - service: 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; } /** @@ -20,25 +35,38 @@ export interface Templates { * @param language The language we need to generate (Typescript or Javascript). */ 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`); + 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 { - index: readHandlebarsTemplate(pathTemplateIndex), - model: readHandlebarsTemplate(pathTemplateModel), - exportInterface: readHandlebarsTemplate(pathTemplateExportInterface), - exportEnum: readHandlebarsTemplate(pathTemplateExportEnum), - exportType: readHandlebarsTemplate(pathTemplateExportType), - service: readHandlebarsTemplate(pathTemplateService), - validation: readHandlebarsTemplate(pathTemplateValidation), - type: readHandlebarsTemplate(pathTemplateType), + 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`)), + 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`)), + exportEnum: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/exportEnum.hbs`)), + exportDictionary: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/exportDictionary.hbs`)), + exportArray: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/exportArray.hbs`)), + validation: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validation.hbs`)), + validationForGeneric: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validationForGeneric.hbs`)), + validationForReference: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validationForReference.hbs`)), + validationForEnum: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validationForEnum.hbs`)), + validationForInterface: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validationForInterface.hbs`)), + validationForDictionary: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validationForDictionary.hbs`)), + validationForArray: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/validationForArray.hbs`)), + type: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/type.hbs`)), + typeForArray: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/typeForArray.hbs`)), + typeForDictionary: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/typeForDictionary.hbs`)), + typeForEnum: readHandlebarsTemplate(path.resolve(__dirname, `../../src/templates/${language}/typeForEnum.hbs`)), + 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`)), }; } catch (e) { throw e; diff --git a/src/utils/writeClientModels.ts b/src/utils/writeClientModels.ts index e323b123..a89d3402 100644 --- a/src/utils/writeClientModels.ts +++ b/src/utils/writeClientModels.ts @@ -16,20 +16,35 @@ import { Templates } from './readHandlebarsTemplates'; export function writeClientModels(models: Map, language: Language, templates: Templates, outputPath: string): void { models.forEach(model => { const fileName = getFileName(model.name, language); - // 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}"`); - // } + 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); + } catch (e) { + throw new Error(`Could not write model: "${fileName}"`); + } }); }