mirror of
https://github.com/ferdikoomen/openapi-typescript-codegen.git
synced 2025-12-08 20:16:21 +00:00
- Working types + schema validator
This commit is contained in:
parent
2a73a14a48
commit
d6131dc780
@ -1,4 +1,5 @@
|
||||
export interface Enum {
|
||||
name: string;
|
||||
value: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
3
src/client/interfaces/Model.d.ts
vendored
3
src/client/interfaces/Model.d.ts
vendored
@ -7,8 +7,9 @@ export interface Model {
|
||||
base: string;
|
||||
template: string | null;
|
||||
description: string | null;
|
||||
validation: string | null;
|
||||
extends: string[];
|
||||
imports: string[];
|
||||
enum: Enum[];
|
||||
properties: Map<string, ModelProperty>;
|
||||
properties: ModelProperty[];
|
||||
}
|
||||
|
||||
1
src/client/interfaces/ModelProperty.d.ts
vendored
1
src/client/interfaces/ModelProperty.d.ts
vendored
@ -7,4 +7,5 @@ export interface ModelProperty {
|
||||
required: boolean;
|
||||
nullable: boolean;
|
||||
description: string | null;
|
||||
validation: string | null;
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
import { PrimaryType } from './constants';
|
||||
|
||||
export function getEnum(values?: (string | number)[]): Enum[] {
|
||||
if (Array.isArray(values)) {
|
||||
@ -11,11 +12,13 @@ export function getEnum(values?: (string | number)[]): Enum[] {
|
||||
return {
|
||||
name: `NUM_${value}`,
|
||||
value: String(value),
|
||||
type: PrimaryType.NUMBER,
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: value.replace(/([a-z])([A-Z]+)/g, '$1_$2').toUpperCase(),
|
||||
value: `'${value}'`,
|
||||
type: PrimaryType.STRING,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Enum } from '../../../client/interfaces/Enum';
|
||||
import { PrimaryType } from './constants';
|
||||
|
||||
export function getEnumFromDescription(description: string): Enum[] {
|
||||
// Check if we can find this special format string:
|
||||
@ -15,6 +16,7 @@ export function getEnumFromDescription(description: string): Enum[] {
|
||||
symbols.push({
|
||||
name: name.replace(/([a-z])([A-Z]+)/g, '$1_$2').toUpperCase(),
|
||||
value: String(value),
|
||||
type: PrimaryType.NUMBER,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -5,12 +5,17 @@ import {getType} from './getType';
|
||||
import {Model} from '../../../client/interfaces/Model';
|
||||
import {PrimaryType} from './constants';
|
||||
import {getEnumType} from './getEnumType';
|
||||
import {ModelProperty} from '../../../client/interfaces/ModelProperty';
|
||||
import {getEnum} from './getEnum';
|
||||
import {getEnumFromDescription} from './getEnumFromDescription';
|
||||
import {getTypeFromProperties} from './getTypeFromProperties';
|
||||
import {getValidationForRef} from './getValidationForRef';
|
||||
import {getValidationForEnum} from './getValidationForEnum';
|
||||
import {getValidationForArrayRef} from './getValidationForArrayRef';
|
||||
import {getValidationForType} from './getValidationForType';
|
||||
import {getValidationForArray} from './getValidationForArray';
|
||||
import {getValidationForProperties} from './getValidationForProperties';
|
||||
|
||||
export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: string = 'unknown'): Model {
|
||||
|
||||
export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: string = ''): Model {
|
||||
// TODO: Properties now contain ALL properties, so we need to filter out enums
|
||||
// before we render the file, plus we need to calculate the final TYPE of a model
|
||||
// by checking all the properties!
|
||||
@ -19,14 +24,15 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
|
||||
const result: Model = {
|
||||
name,
|
||||
type: 'any',
|
||||
base: 'any',
|
||||
type: PrimaryType.OBJECT,
|
||||
base: PrimaryType.OBJECT,
|
||||
template: null,
|
||||
description: getComment(definition.description),
|
||||
validation: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
properties: [],
|
||||
};
|
||||
|
||||
if (definition.$ref) {
|
||||
@ -35,6 +41,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
result.base = definitionRef.base;
|
||||
result.template = definitionRef.template;
|
||||
result.imports.push(...definitionRef.imports);
|
||||
result.validation = getValidationForRef(definitionRef);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -45,6 +52,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
result.type = getEnumType(enumerators);
|
||||
result.base = PrimaryType.STRING;
|
||||
result.enum.push(...enumerators);
|
||||
result.validation = getValidationForEnum(name, enumerators);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
@ -57,6 +65,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
result.type = getEnumType(enumerators);
|
||||
result.base = PrimaryType.NUMBER;
|
||||
result.enum.push(...enumerators);
|
||||
result.validation = getValidationForEnum(name, enumerators);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
@ -66,17 +75,19 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
// so we can create a typed array, otherwise this will be a "any[]".
|
||||
if (definition.type === 'array' && definition.items) {
|
||||
if (definition.items.$ref) {
|
||||
const arrayItemsRef = getType(definition.items.$ref);
|
||||
result.type = `${arrayItemsRef.type}[]`;
|
||||
result.base = arrayItemsRef.base;
|
||||
result.template = arrayItemsRef.template;
|
||||
result.imports.push(...arrayItemsRef.imports);
|
||||
const arrayItems = getType(definition.items.$ref);
|
||||
result.type = `${arrayItems.type}[]`;
|
||||
result.base = arrayItems.base;
|
||||
result.template = arrayItems.template;
|
||||
result.imports.push(...arrayItems.imports);
|
||||
result.validation = getValidationForArrayRef(arrayItems);
|
||||
} else {
|
||||
const arrayItemsModel = getModel(openApi, definition.items);
|
||||
result.type = `${arrayItemsModel.type}[]`;
|
||||
result.base = arrayItemsModel.base;
|
||||
result.template = arrayItemsModel.template;
|
||||
result.imports.push(...arrayItemsModel.imports);
|
||||
const arrayItems = getModel(openApi, definition.items);
|
||||
result.type = `${arrayItems.type}[]`;
|
||||
result.base = arrayItems.base;
|
||||
result.template = arrayItems.template;
|
||||
result.imports.push(...arrayItems.imports);
|
||||
result.validation = getValidationForArray(name, arrayItems);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -96,38 +107,43 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
const propertyRequired = !!(parent.required && parent.required.includes(propertyName));
|
||||
const propertyReadOnly = !!property.readOnly;
|
||||
if (property.$ref) {
|
||||
const propertyRef = getType(property.$ref);
|
||||
const prop = getType(property.$ref);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyRef.imports);
|
||||
result.properties.set(propertyName, {
|
||||
result.imports.push(...prop.imports);
|
||||
result.properties.push({
|
||||
name: propertyName,
|
||||
type: propertyRef.type,
|
||||
base: propertyRef.base,
|
||||
template: propertyRef.template,
|
||||
type: prop.type,
|
||||
base: prop.base,
|
||||
template: prop.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
description: property.description || null,
|
||||
validation: getValidationForRef(prop),
|
||||
});
|
||||
} else {
|
||||
const propertyModel = getModel(openApi, property);
|
||||
const prop = getModel(openApi, property);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyModel.imports);
|
||||
result.properties.set(propertyName, {
|
||||
result.imports.push(...prop.imports);
|
||||
result.properties.push({
|
||||
name: propertyName,
|
||||
type: propertyModel.type,
|
||||
base: propertyModel.base,
|
||||
template: propertyModel.template,
|
||||
type: prop.type,
|
||||
base: prop.base,
|
||||
template: prop.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
description: property.description || null,
|
||||
validation: prop.validation,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
result.type = getTypeFromProperties(result.properties);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.validation = getValidationForProperties(name, result.properties, result.extends);
|
||||
}
|
||||
|
||||
if (definition.type === 'object' && definition.properties) {
|
||||
@ -137,36 +153,65 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
const propertyRequired = !!(definition.required && definition.required.includes(propertyName));
|
||||
const propertyReadOnly = !!property.readOnly;
|
||||
if (property.$ref) {
|
||||
const propertyRef = getType(property.$ref);
|
||||
const prop = getType(property.$ref);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyRef.imports);
|
||||
result.properties.set(propertyName, {
|
||||
result.imports.push(...prop.imports);
|
||||
result.properties.push({
|
||||
name: propertyName,
|
||||
type: propertyRef.type,
|
||||
base: propertyRef.base,
|
||||
template: propertyRef.template,
|
||||
type: prop.type,
|
||||
base: prop.base,
|
||||
template: prop.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
description: property.description || null,
|
||||
validation: getValidationForRef(prop),
|
||||
});
|
||||
} else {
|
||||
const propertyModel = getModel(openApi, property);
|
||||
const prop = getModel(openApi, property);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.imports.push(...propertyModel.imports);
|
||||
result.properties.set(propertyName, {
|
||||
result.imports.push(...prop.imports);
|
||||
result.properties.push({
|
||||
name: propertyName,
|
||||
type: propertyModel.type,
|
||||
base: propertyModel.base,
|
||||
template: propertyModel.template,
|
||||
type: prop.type,
|
||||
base: prop.base,
|
||||
template: prop.template,
|
||||
readOnly: propertyReadOnly,
|
||||
required: propertyRequired,
|
||||
nullable: false,
|
||||
description: property.description || null,
|
||||
validation: prop.validation,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
result.type = getTypeFromProperties(result.properties);
|
||||
result.base = PrimaryType.OBJECT;
|
||||
result.validation = getValidationForProperties(name, result.properties, result.extends);
|
||||
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.imports.push(...additionalProperties.imports);
|
||||
result.imports.push('Dictionary');
|
||||
console.log(name, 'Dictionary', result.type);
|
||||
} else {
|
||||
const additionalProperties = getModel(openApi, definition.additionalProperties);
|
||||
result.type = `Dictionary<${additionalProperties.type}>`;
|
||||
result.base = 'Dictionary';
|
||||
result.template = additionalProperties.type;
|
||||
result.imports.push(...additionalProperties.imports);
|
||||
result.imports.push('Dictionary');
|
||||
console.log(name, 'Dictionary', result.type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -177,6 +222,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, name: stri
|
||||
result.base = definitionType.base;
|
||||
result.template = definitionType.template;
|
||||
result.imports.push(...definitionType.imports);
|
||||
result.validation = getValidationForType(definitionType);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
import { EOL } from 'os';
|
||||
import { ModelProperty } from '../../../client/interfaces/ModelProperty';
|
||||
|
||||
export function getModelType(properties: ModelProperty[]): string {
|
||||
return [
|
||||
`{`,
|
||||
...properties.map(property => {
|
||||
return ` ${property.readOnly ? 'readonly ' : ''}${property.name}${property.required ? '' : '?'}: ${property.type},`;
|
||||
}),
|
||||
`}`,
|
||||
].join(EOL);
|
||||
}
|
||||
@ -4,9 +4,9 @@ import { ModelProperty } from '../../../client/interfaces/ModelProperty';
|
||||
export function getModelValidation(name: string, properties: ModelProperty[]): string {
|
||||
return [
|
||||
`yup.object().shape({`,
|
||||
...properties.map(property => {
|
||||
return ` ${property.name}: ${property.validation},`;
|
||||
}),
|
||||
// ...properties.map(property => {
|
||||
// return ` ${property.name}: ${property.validation},`;
|
||||
// }),
|
||||
`}).noUnknown()`,
|
||||
].join(EOL);
|
||||
}
|
||||
|
||||
@ -9,10 +9,8 @@ export function getModels(openApi: OpenApi): Map<string, Model> {
|
||||
if (openApi.definitions.hasOwnProperty(definitionName)) {
|
||||
const definition = openApi.definitions[definitionName];
|
||||
const definitionType = getType(definitionName);
|
||||
if (!models.has(definitionType.base)) {
|
||||
const model = getModel(openApi, definition, definitionType.base);
|
||||
models.set(definitionType.base, model);
|
||||
}
|
||||
const model = getModel(openApi, definition, definitionType.base);
|
||||
models.set(definitionType.base, model);
|
||||
}
|
||||
}
|
||||
return models;
|
||||
|
||||
@ -10,6 +10,7 @@ import { getOperationResponses } from './getOperationResponses';
|
||||
import { getOperationResponse } from './getOperationResponse';
|
||||
import { getOperationErrors } from './getOperationErrors';
|
||||
import { Operation } from '../../../client/interfaces/Operation';
|
||||
import { PrimaryType } from './constants';
|
||||
|
||||
export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation): Operation {
|
||||
const serviceName = (op.tags && op.tags[0]) || 'Service';
|
||||
@ -35,7 +36,7 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
|
||||
parametersBody: null,
|
||||
imports: [],
|
||||
errors: [],
|
||||
result: 'void',
|
||||
result: PrimaryType.VOID,
|
||||
};
|
||||
|
||||
// Parse the operation parameters (path, query, body, etc).
|
||||
|
||||
@ -6,7 +6,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('number');
|
||||
expect(type.base).toEqual('number');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
expect(type.imports).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert string', () => {
|
||||
@ -14,7 +14,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('string');
|
||||
expect(type.base).toEqual('string');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
expect(type.imports).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert string array', () => {
|
||||
@ -22,7 +22,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('string[]');
|
||||
expect(type.base).toEqual('string');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
expect(type.imports).toEqual([]);
|
||||
});
|
||||
|
||||
it('should convert template with primary', () => {
|
||||
@ -30,7 +30,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('Link<string>');
|
||||
expect(type.base).toEqual('Link');
|
||||
expect(type.template).toEqual('string');
|
||||
expect(Array.from(type.imports.values())).toEqual(['Link']);
|
||||
expect(type.imports).toEqual(['Link']);
|
||||
});
|
||||
|
||||
it('should convert template with model', () => {
|
||||
@ -38,7 +38,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('Link<Model>');
|
||||
expect(type.base).toEqual('Link');
|
||||
expect(type.template).toEqual('Model');
|
||||
expect(Array.from(type.imports.values())).toEqual(['Link', 'Model']);
|
||||
expect(type.imports).toEqual(['Link', 'Model']);
|
||||
});
|
||||
|
||||
it('should have double imports', () => {
|
||||
@ -46,7 +46,7 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('Link<Link>');
|
||||
expect(type.base).toEqual('Link');
|
||||
expect(type.template).toEqual('Link');
|
||||
expect(Array.from(type.imports.values())).toEqual(['Link', 'Link']);
|
||||
expect(type.imports).toEqual(['Link', 'Link']);
|
||||
});
|
||||
|
||||
it('should convert generic', () => {
|
||||
@ -54,6 +54,6 @@ describe('getType', () => {
|
||||
expect(type.type).toEqual('T');
|
||||
expect(type.base).toEqual('T');
|
||||
expect(type.template).toEqual(null);
|
||||
expect(Array.from(type.imports.values())).toEqual([]);
|
||||
expect(type.imports).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
18
src/openApi/v2/parser/getTypeFromProperties.ts
Normal file
18
src/openApi/v2/parser/getTypeFromProperties.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { EOL } from 'os';
|
||||
import { ModelProperty } from '../../../client/interfaces/ModelProperty';
|
||||
|
||||
export function getTypeFromProperties(properties: ModelProperty[]): 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);
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
export function getValidation(validation: string, required: boolean = false, nullable: boolean = false): string {
|
||||
if (required) {
|
||||
validation = `${validation}.required()`;
|
||||
}
|
||||
|
||||
if (nullable) {
|
||||
validation = `${validation}.nullable()`;
|
||||
}
|
||||
|
||||
return validation;
|
||||
}
|
||||
5
src/openApi/v2/parser/getValidationForArray.ts
Normal file
5
src/openApi/v2/parser/getValidationForArray.ts
Normal file
@ -0,0 +1,5 @@
|
||||
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()'})`;
|
||||
}
|
||||
@ -1,15 +1,5 @@
|
||||
import { Type } from '../../../client/interfaces/Type';
|
||||
|
||||
export function getValidationForArrayRef(ref: Type, required: boolean = false, nullable: boolean = false): string {
|
||||
let validation = `yup.array<${ref.type}>().of(${ref.base}.schema)`;
|
||||
|
||||
if (required) {
|
||||
validation = `${validation}.required()`;
|
||||
}
|
||||
|
||||
if (nullable) {
|
||||
validation = `${validation}.nullable()`;
|
||||
}
|
||||
|
||||
return validation;
|
||||
export function getValidationForArrayRef(ref: Type): string {
|
||||
return `yup.array<${ref.type}>().of(${ref.base}.schema)`;
|
||||
}
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
import { PrimaryType } from './constants';
|
||||
import { Type } from '../../../client/interfaces/Type';
|
||||
|
||||
export function getValidationForArrayType(type: Type, required: boolean = false, nullable: boolean = false): string {
|
||||
let validation = `yup.array<any>().of(yup.mixed())`;
|
||||
|
||||
switch (type.type) {
|
||||
case PrimaryType.BOOLEAN:
|
||||
validation = `yup.array<boolean>().of(yup.boolean())`;
|
||||
break;
|
||||
case PrimaryType.NUMBER:
|
||||
validation = `yup.array<number>().of(yup.number())`;
|
||||
break;
|
||||
case PrimaryType.STRING:
|
||||
validation = `yup.array<string>().of(yup.string())`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (required) {
|
||||
validation = `${validation}.required()`;
|
||||
}
|
||||
|
||||
if (nullable) {
|
||||
validation = `${validation}.nullable()`;
|
||||
}
|
||||
|
||||
return validation;
|
||||
}
|
||||
16
src/openApi/v2/parser/getValidationForEnum.ts
Normal file
16
src/openApi/v2/parser/getValidationForEnum.ts
Normal file
@ -0,0 +1,16 @@
|
||||
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);
|
||||
}
|
||||
18
src/openApi/v2/parser/getValidationForProperties.ts
Normal file
18
src/openApi/v2/parser/getValidationForProperties.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { EOL } from 'os';
|
||||
import { ModelProperty } from '../../../client/interfaces/ModelProperty';
|
||||
|
||||
export function getValidationForProperties(name: string, properties: ModelProperty[], extendClasses: string[]): string {
|
||||
return [
|
||||
...extendClasses.map(extendClass => `${extendClass}.schema.concat(`),
|
||||
`yup.object${name ? `<${name}>` : ''}().shape({`,
|
||||
...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()`,
|
||||
...extendClasses.map(() => `)`),
|
||||
].join(EOL);
|
||||
}
|
||||
@ -1,15 +1,5 @@
|
||||
import { Type } from '../../../client/interfaces/Type';
|
||||
|
||||
export function getValidationForRef(ref: Type, required = false, nullable = false): string {
|
||||
let validation = `${ref.base}.schema`;
|
||||
|
||||
if (required) {
|
||||
validation = `${validation}.required()`;
|
||||
}
|
||||
|
||||
if (nullable) {
|
||||
validation = `${validation}.nullable()`;
|
||||
}
|
||||
|
||||
return validation;
|
||||
export function getValidationForRef(ref: Type): string {
|
||||
return `${ref.base}.schema`;
|
||||
}
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { PrimaryType } from './constants';
|
||||
import { Type } from '../../../client/interfaces/Type';
|
||||
|
||||
export function getValidationForType(type: Type, required: boolean = false, nullable: boolean = false): string {
|
||||
export function getValidationForType(type: Type): string {
|
||||
let validation = `yup.mixed<${type.type}>()`;
|
||||
|
||||
switch (type.type) {
|
||||
case PrimaryType.BOOLEAN:
|
||||
validation = `yup.boolean()`;
|
||||
@ -15,14 +14,5 @@ export function getValidationForType(type: Type, required: boolean = false, null
|
||||
validation = `yup.string()`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (required) {
|
||||
validation = `${validation}.required()`;
|
||||
}
|
||||
|
||||
if (nullable) {
|
||||
validation = `${validation}.nullable()`;
|
||||
}
|
||||
|
||||
return validation;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export function exportModel(model: Model): any {
|
||||
imports: getSortedImports(model.imports).filter(name => {
|
||||
return model.name !== name;
|
||||
}),
|
||||
properties: Array.from(model.properties.values())
|
||||
properties: model.properties
|
||||
.filter((property, index, arr) => {
|
||||
return arr.findIndex(item => item.name === property.name) === index;
|
||||
})
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { getSortedModels } from './getSortedModels';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { ModelProperty } from '../client/interfaces/ModelProperty';
|
||||
|
||||
describe('getSortedModels', () => {
|
||||
it('should return sorted list', () => {
|
||||
@ -11,10 +10,11 @@ describe('getSortedModels', () => {
|
||||
base: 'John',
|
||||
template: null,
|
||||
description: null,
|
||||
validation: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
properties: [],
|
||||
});
|
||||
models.set('Jane', {
|
||||
name: 'Jane',
|
||||
@ -22,10 +22,11 @@ describe('getSortedModels', () => {
|
||||
base: 'Jane',
|
||||
template: null,
|
||||
description: null,
|
||||
validation: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
properties: [],
|
||||
});
|
||||
models.set('Doe', {
|
||||
name: 'Doe',
|
||||
@ -33,10 +34,11 @@ describe('getSortedModels', () => {
|
||||
base: 'Doe',
|
||||
template: null,
|
||||
description: null,
|
||||
validation: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: new Map<string, ModelProperty>(),
|
||||
properties: [],
|
||||
});
|
||||
|
||||
expect(getSortedModels(new Map<string, Model>())).toEqual([]);
|
||||
|
||||
@ -6,6 +6,8 @@ import { Client } from '../client/interfaces/Client';
|
||||
import { Templates } from './readHandlebarsTemplates';
|
||||
import { Language } from '../index';
|
||||
import * as glob from 'glob';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
|
||||
jest.mock('rimraf');
|
||||
jest.mock('mkdirp');
|
||||
@ -22,8 +24,8 @@ describe('writeClient', () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: 'v1',
|
||||
models: [],
|
||||
services: [],
|
||||
models: new Map<string, Model>(),
|
||||
services: new Map<string, Service>(),
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
|
||||
@ -2,6 +2,8 @@ import { writeClientIndex } from './writeClientIndex';
|
||||
import * as fs from 'fs';
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { Language } from '../index';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
@ -12,8 +14,8 @@ describe('writeClientIndex', () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: 'v1',
|
||||
models: [],
|
||||
services: [],
|
||||
models: new Map<string, Model>(),
|
||||
services: new Map<string, Service>(),
|
||||
};
|
||||
const template = () => 'dummy';
|
||||
writeClientIndex(client, Language.TYPESCRIPT, template, '/');
|
||||
|
||||
@ -9,24 +9,19 @@ const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeF
|
||||
|
||||
describe('writeClientModels', () => {
|
||||
it('should write to filesystem', () => {
|
||||
const models: Model[] = [
|
||||
{
|
||||
isInterface: false,
|
||||
isType: false,
|
||||
isEnum: false,
|
||||
name: 'Item',
|
||||
type: 'Item',
|
||||
base: 'Item',
|
||||
template: null,
|
||||
validation: null,
|
||||
description: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
symbols: [],
|
||||
properties: [],
|
||||
enums: [],
|
||||
},
|
||||
];
|
||||
const models = new Map<string, Model>();
|
||||
models.set('Item', {
|
||||
name: 'Item',
|
||||
type: 'Item',
|
||||
base: 'Item',
|
||||
template: null,
|
||||
description: null,
|
||||
validation: null,
|
||||
extends: [],
|
||||
imports: [],
|
||||
enum: [],
|
||||
properties: [],
|
||||
});
|
||||
const template = () => 'dummy';
|
||||
writeClientModels(models, Language.TYPESCRIPT, template, '/');
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
|
||||
@ -9,13 +9,12 @@ const fsWriteFileSync = fs.writeFileSync as jest.MockedFunction<typeof fs.writeF
|
||||
|
||||
describe('writeClientServices', () => {
|
||||
it('should write to filesystem', () => {
|
||||
const services: Service[] = [
|
||||
{
|
||||
name: 'Item',
|
||||
operations: [],
|
||||
imports: [],
|
||||
},
|
||||
];
|
||||
const services = new Map<string, Service>();
|
||||
services.set('Item', {
|
||||
name: 'Item',
|
||||
operations: [],
|
||||
imports: [],
|
||||
});
|
||||
const template = () => 'dummy';
|
||||
writeClientServices(services, Language.TYPESCRIPT, template, '/');
|
||||
expect(fsWriteFileSync).toBeCalledWith('/Item.ts', 'dummy');
|
||||
|
||||
@ -112,6 +112,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user