- First draft ready

This commit is contained in:
Ferdi Koomen 2019-11-24 11:13:30 +01:00
parent 00158b4af7
commit b16db33c92
22 changed files with 3459 additions and 7567 deletions

View File

@ -4,7 +4,7 @@ import { OpenApiResponse } from './OpenApiResponse';
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#responsesObject
*/
export interface OpenApiResponses {
[httpcode: string]: OpenApiResponse;
default?: OpenApiResponse;
[httpcode: string]: OpenApiResponse;
}

View File

@ -19,7 +19,7 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty
link: null,
description: getComment(definition.description),
isProperty: isProperty,
isReadOnly: definition.readOnly || false,
isReadOnly: definition.readOnly === true,
isNullable: false,
isRequired: false,
imports: [],

View File

@ -10,8 +10,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
const property = definition.properties[propertyName];
const propertyRequired = !!(definition.required && definition.required.includes(propertyName));
const propertyReadOnly = !!property.readOnly;
const propertyRequired = definition.required && definition.required.includes(propertyName);
if (property.$ref) {
const model = getType(property.$ref);
models.push({
@ -23,8 +22,8 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
link: null,
description: getComment(property.description),
isProperty: true,
isReadOnly: propertyReadOnly,
isRequired: propertyRequired,
isReadOnly: property.readOnly === true,
isRequired: propertyRequired === true,
isNullable: false,
imports: model.imports,
extends: [],
@ -43,8 +42,8 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
link: model.link,
description: getComment(property.description),
isProperty: true,
isReadOnly: propertyReadOnly,
isRequired: propertyRequired,
isReadOnly: property.readOnly === true,
isRequired: propertyRequired === true,
isNullable: false,
imports: model.imports,
extends: model.extends,

View File

@ -23,7 +23,7 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
name: operationName,
summary: getComment(op.summary),
description: getComment(op.description),
deprecated: op.deprecated || false,
deprecated: op.deprecated === true,
method: method,
path: operationPath,
parameters: [],

View File

@ -25,7 +25,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
default: getOperationParameterDefault(parameter.default),
isProperty: false,
isReadOnly: false,
isRequired: parameter.required || false,
isRequired: parameter.required === true,
isNullable: false,
imports: [],
extends: [],

View File

@ -10,7 +10,7 @@ export interface OpenApiParameter extends OpenApiReference {
name: string;
in: 'path' | 'query' | 'header' | 'cookie';
description?: string;
required: boolean;
required?: boolean;
deprecated?: boolean;
allowEmptyValue?: boolean;
style?: string;

View File

@ -5,7 +5,7 @@ import { OpenApiResponse } from './OpenApiResponse';
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject
*/
export interface OpenApiResponses extends OpenApiReference {
[httpcode: string]: OpenApiResponse;
default: OpenApiResponse;
[httpcode: string]: OpenApiResponse;
}

View File

@ -42,3 +42,10 @@ export enum Method {
HEAD = 'head',
PATCH = 'patch',
}
export enum ContentType {
APPLICATION_JSON_PATCH = 'application/json-patch+json',
APPLICATION_JSON = 'application/json',
TEXT_JSON = 'text/json',
TEXT_PAIN = 'text/plain',
}

View File

@ -0,0 +1,22 @@
import { ContentType } from './constants';
import { Dictionary } from '../../../utils/types';
import { OpenApi } from '../interfaces/OpenApi';
import { OpenApiMediaType } from '../interfaces/OpenApiMediaType';
import { OpenApiSchema } from '../interfaces/OpenApiSchema';
export function getContent(openApi: OpenApi, content: Dictionary<OpenApiMediaType>): OpenApiSchema | null {
/* prettier-ignore */
return (
content[ContentType.APPLICATION_JSON_PATCH] &&
content[ContentType.APPLICATION_JSON_PATCH].schema
) || (
content[ContentType.APPLICATION_JSON] &&
content[ContentType.APPLICATION_JSON].schema
) || (
content[ContentType.TEXT_JSON] &&
content[ContentType.TEXT_JSON].schema
) || (
content[ContentType.TEXT_PAIN] &&
content[ContentType.TEXT_PAIN].schema
) || null;
}

View File

@ -19,8 +19,8 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty
link: null,
description: getComment(definition.description),
isProperty: isProperty,
isReadOnly: definition.readOnly || false,
isNullable: definition.nullable || false,
isReadOnly: definition.readOnly === true,
isNullable: definition.nullable === true,
isRequired: false,
imports: [],
extends: [],

View File

@ -10,9 +10,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
const property = definition.properties[propertyName];
const propertyRequired = !!(definition.required && definition.required.includes(propertyName));
const propertyReadOnly = !!property.readOnly;
const propertyNullable = !!property.nullable;
const propertyRequired = definition.required && definition.required.includes(propertyName);
if (property.$ref) {
const model = getType(property.$ref);
models.push({
@ -24,9 +22,9 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
link: null,
description: getComment(property.description),
isProperty: true,
isReadOnly: propertyReadOnly,
isRequired: propertyRequired,
isNullable: propertyNullable,
isReadOnly: property.readOnly === true,
isRequired: propertyRequired === true,
isNullable: property.nullable === true,
imports: model.imports,
extends: [],
enum: [],
@ -44,9 +42,9 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema):
link: model.link,
description: getComment(property.description),
isProperty: true,
isReadOnly: propertyReadOnly,
isRequired: propertyRequired,
isNullable: propertyNullable,
isReadOnly: property.readOnly === true,
isRequired: propertyRequired === true,
isNullable: property.nullable === true,
imports: model.imports,
extends: model.extends,
enum: model.enum,

View File

@ -6,6 +6,7 @@ import { getOperationErrors } from './getOperationErrors';
import { getOperationName } from './getOperationName';
import { getOperationParameters } from './getOperationParameters';
import { getOperationPath } from './getOperationPath';
import { getOperationRequestBody } from './getOperationRequestBody';
import { getOperationResponses } from './getOperationResponses';
import { getOperationResults } from './getOperationResults';
import { getServiceClassName } from './getServiceClassName';
@ -23,7 +24,7 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
name: operationName,
summary: getComment(op.summary),
description: getComment(op.description),
deprecated: op.deprecated || false,
deprecated: op.deprecated === true,
method: method,
path: operationPath,
parameters: [],
@ -49,6 +50,13 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
operation.parametersBody = parameters.parametersBody;
}
if (op.requestBody) {
const requestBody = getOperationRequestBody(openApi, op.requestBody);
operation.imports.push(...requestBody.imports);
operation.parameters.push(requestBody);
operation.parametersBody = requestBody;
}
// Parse the operation responses.
if (op.responses) {
const operationResponses = getOperationResponses(openApi, op.responses);

View File

@ -21,7 +21,7 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
default: undefined,
isProperty: false,
isReadOnly: false,
isRequired: parameter.required || false,
isRequired: parameter.required === true,
isNullable: false,
imports: [],
extends: [],

View File

@ -0,0 +1,60 @@
import { OpenApi } from '../interfaces/OpenApi';
import { OpenApiRequestBody } from '../interfaces/OpenApiRequestBody';
import { OperationParameter } from '../../../client/interfaces/OperationParameter';
import { PrimaryType } from './constants';
import { getComment } from './getComment';
import { getContent } from './getContent';
import { getModel } from './getModel';
import { getType } from './getType';
export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequestBody): OperationParameter {
const requestBody: OperationParameter = {
in: 'body',
prop: 'body',
export: 'interface',
name: 'requestBody',
type: PrimaryType.OBJECT,
base: PrimaryType.OBJECT,
template: null,
link: null,
description: getComment(parameter.description),
default: undefined,
isProperty: false,
isReadOnly: false,
isRequired: parameter.required === true,
isNullable: false,
imports: [],
extends: [],
enum: [],
enums: [],
properties: [],
};
if (parameter.content) {
const schema = getContent(openApi, parameter.content);
if (schema) {
if (schema && schema.$ref) {
const model = getType(schema.$ref);
requestBody.export = 'reference';
requestBody.type = model.type;
requestBody.base = model.base;
requestBody.template = model.template;
requestBody.imports.push(...model.imports);
} else {
const model = getModel(openApi, schema);
requestBody.export = model.export;
requestBody.type = model.type;
requestBody.base = model.base;
requestBody.template = model.template;
requestBody.link = model.link;
requestBody.imports.push(...model.imports);
requestBody.extends.push(...model.extends);
requestBody.enum.push(...model.enum);
requestBody.enums.push(...model.enums);
requestBody.properties.push(...model.properties);
}
}
}
return requestBody;
}

View File

@ -3,6 +3,9 @@ import { OpenApiResponse } from '../interfaces/OpenApiResponse';
import { OperationResponse } from '../../../client/interfaces/OperationResponse';
import { PrimaryType } from './constants';
import { getComment } from './getComment';
import { getContent } from './getContent';
import { getModel } from './getModel';
import { getType } from './getType';
export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse, responseCode: number): OperationResponse {
const operationResponse: OperationResponse = {
@ -25,33 +28,31 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse
properties: [],
};
// If this response has a schema, then we need to check two things:
// if this is a reference then the parameter is just the 'name' of
// this reference type. Otherwise it might be a complex schema and
// then we need to parse the schema!
// if (response.schema) {
// if (response.schema.$ref) {
// const model = getType(response.schema.$ref);
// operationResponse.export = 'reference';
// operationResponse.type = model.type;
// operationResponse.base = model.base;
// operationResponse.template = model.template;
// operationResponse.imports.push(...model.imports);
// } else {
// const model = getModel(openApi, response.schema);
// operationResponse.export = model.export;
// operationResponse.type = model.type;
// operationResponse.base = model.base;
// operationResponse.template = model.template;
// operationResponse.link = model.link;
// operationResponse.imports.push(...model.imports);
// operationResponse.extends.push(...model.extends);
// operationResponse.enum.push(...model.enum);
// operationResponse.enums.push(...model.enums);
// operationResponse.properties.push(...model.properties);
// }
// }
if (response.content) {
const schema = getContent(openApi, response.content);
if (schema) {
if (schema && schema.$ref) {
const model = getType(schema.$ref);
operationResponse.export = 'reference';
operationResponse.type = model.type;
operationResponse.base = model.base;
operationResponse.template = model.template;
operationResponse.imports.push(...model.imports);
} else {
const model = getModel(openApi, schema);
operationResponse.export = model.export;
operationResponse.type = model.type;
operationResponse.base = model.base;
operationResponse.template = model.template;
operationResponse.link = model.link;
operationResponse.imports.push(...model.imports);
operationResponse.extends.push(...model.extends);
operationResponse.enum.push(...model.enum);
operationResponse.enums.push(...model.enums);
operationResponse.properties.push(...model.properties);
}
}
}
return operationResponse;
}

View File

@ -1,7 +1,7 @@
import {PrimaryType} from './constants';
import {Type} from '../../../client/interfaces/Type';
import {getMappedType, hasMappedType} from './getMappedType';
import {stripNamespace} from './stripNamespace';
import { PrimaryType } from './constants';
import { Type } from '../../../client/interfaces/Type';
import { getMappedType, hasMappedType } from './getMappedType';
import { stripNamespace } from './stripNamespace';
/**
* Parse any string value into a type object.

View File

@ -10,7 +10,7 @@ export interface {{{name}}}{{#if extends}} extends {{#each extends}}{{{this}}}{{
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless isRequired}}?{{/unless}}: {{>type parent=../name}}{{#if isNullable}} | null{{/if}};
{{#if isReadOnly}}readonly {{/if}}{{{name}}}{{#unless isRequired}}?{{/unless}}: {{>type parent=../name}}{{#if isNullable}} | null{{/if}};
{{/each}}
}

View File

@ -6,7 +6,7 @@
* {{{description}}}
*/
{{/if}}
{{#if readOnly}}readonly {{/if}}{{{name}}}{{#unless isRequired}}?{{/unless}}: {{>type}}{{#if isNullable}} | null{{/if}}{{#unless @last}},{{/unless}}
{{#if isReadOnly}}readonly {{/if}}{{{name}}}{{#unless isRequired}}?{{/unless}}: {{>type}}{{#if isNullable}} | null{{/if}}{{#unless @last}},{{/unless}}
{{/each}}
}
{{~else~}}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,19 @@
const OpenAPI = require('../dist');
OpenAPI.generate(
'./test/mock/spec-v2.json',
'./test/result/v2/typescript/',
OpenAPI.Language.TYPESCRIPT,
OpenAPI.HttpClient.FETCH,
);
OpenAPI.generate(
'./test/mock/spec-v2.json',
'./test/result/v2/javascript/',
OpenAPI.Language.JAVASCRIPT,
OpenAPI.HttpClient.XHR,
);
OpenAPI.generate(
'./test/mock/spec-v3.json',
'./test/result/v3/typescript/',
@ -7,18 +21,12 @@ OpenAPI.generate(
OpenAPI.HttpClient.FETCH,
);
// OpenAPI.generate(
// './test/mock/spec-v2.json',
// './test/result/v2/typescript/',
// OpenAPI.Language.TYPESCRIPT,
// OpenAPI.HttpClient.FETCH,
// );
OpenAPI.generate(
'./test/mock/spec-v3.json',
'./test/result/v3/javascript/',
OpenAPI.Language.JAVASCRIPT,
OpenAPI.HttpClient.XHR,
);
// OpenAPI.generate(
// './test/mock/spec-v2.json',
// './test/result/v2/javascript/',
// OpenAPI.Language.JAVASCRIPT,
// OpenAPI.HttpClient.XHR,
// );
// OpenAPI.compile('./test/result/v2/typescript/');
OpenAPI.compile('./test/result/v2/typescript/');
OpenAPI.compile('./test/result/v3/typescript/');

View File

@ -618,18 +618,59 @@
}
}
},
"ModelWithProperties": {
"description": "This is a model with one nested property",
"type": "object",
"required": [
"required",
"requiredAndreadOnly"
],
"properties": {
"required": {
"type": "string"
},
"requiredAndreadOnly": {
"type": "string",
"readOnly": true
},
"string": {
"type": "string"
},
"number": {
"type": "number"
},
"boolean": {
"type": "boolean"
},
"reference": {
"$ref": "#/definitions/ModelWithString"
}
}
},
"ModelWithNestedProperties": {
"description": "This is a model with one nested property",
"type": "object",
"required": [
"first"
],
"properties": {
"first": {
"type": "object",
"required": [
"second"
],
"readOnly": true,
"properties": {
"second": {
"type": "object",
"required": [
"third"
],
"readOnly": true,
"properties": {
"third": {
"type": "string"
"type": "string",
"readOnly": true
}
}
}

File diff suppressed because it is too large Load Diff