mirror of
https://github.com/ferdikoomen/openapi-typescript-codegen.git
synced 2025-12-08 20:16:21 +00:00
- Added core template files
- Working on v2 parsing
This commit is contained in:
parent
c4bc1e1787
commit
30e26621a5
@ -74,6 +74,7 @@
|
||||
"eslint": "6.6.0",
|
||||
"eslint-config-prettier": "6.5.0",
|
||||
"eslint-plugin-prettier": "3.1.1",
|
||||
"glob": "7.1.6",
|
||||
"handlebars": "4.5.1",
|
||||
"jest": "24.9.0",
|
||||
"jest-cli": "24.9.0",
|
||||
|
||||
7
src/client/interfaces/ArrayType.d.ts
vendored
Normal file
7
src/client/interfaces/ArrayType.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
export interface ArrayType {
|
||||
type: string;
|
||||
base: string;
|
||||
template: string | null;
|
||||
default?: any;
|
||||
imports: string[];
|
||||
}
|
||||
2
src/client/interfaces/Client.d.ts
vendored
2
src/client/interfaces/Client.d.ts
vendored
@ -1,11 +1,9 @@
|
||||
import { Model } from './Model';
|
||||
import { Service } from './Service';
|
||||
import { Schema } from './Schema';
|
||||
|
||||
export interface Client {
|
||||
version: string;
|
||||
server: string;
|
||||
models: Map<string, Model>;
|
||||
schemas: Map<string, Schema>;
|
||||
services: Map<string, Service>;
|
||||
}
|
||||
|
||||
2
src/client/interfaces/Model.d.ts
vendored
2
src/client/interfaces/Model.d.ts
vendored
@ -5,7 +5,7 @@ export interface Model {
|
||||
name: string;
|
||||
base: string;
|
||||
type: string;
|
||||
template?: string;
|
||||
template: string | null;
|
||||
description?: string;
|
||||
extends: string[];
|
||||
imports: string[];
|
||||
|
||||
2
src/client/interfaces/ModelProperty.d.ts
vendored
2
src/client/interfaces/ModelProperty.d.ts
vendored
@ -2,7 +2,7 @@ export interface ModelProperty {
|
||||
name: string;
|
||||
type: string;
|
||||
base: string;
|
||||
template?: string;
|
||||
template: string | null;
|
||||
description?: string;
|
||||
default?: any;
|
||||
required: boolean;
|
||||
|
||||
21
src/client/interfaces/Operation.d.ts
vendored
Normal file
21
src/client/interfaces/Operation.d.ts
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
import { OperationError } from './OperationError';
|
||||
import { Parameter } from './Parameter';
|
||||
|
||||
export interface Operation {
|
||||
service: string;
|
||||
name: string;
|
||||
summary?: string;
|
||||
description?: string;
|
||||
deprecated?: boolean;
|
||||
method: string;
|
||||
path: string;
|
||||
parameters: Parameter[];
|
||||
parametersPath: Parameter[];
|
||||
parametersQuery: Parameter[];
|
||||
parametersForm: Parameter[];
|
||||
parametersHeader: Parameter[];
|
||||
parametersBody: Parameter | null;
|
||||
errors: OperationError[];
|
||||
result: string;
|
||||
imports: string[];
|
||||
}
|
||||
4
src/client/interfaces/OperationError.d.ts
vendored
Normal file
4
src/client/interfaces/OperationError.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export interface OperationError {
|
||||
code: number;
|
||||
text: string;
|
||||
}
|
||||
11
src/client/interfaces/OperationParameters.d.ts
vendored
Normal file
11
src/client/interfaces/OperationParameters.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { Parameter } from './Parameter';
|
||||
|
||||
export interface OperationParameters {
|
||||
imports: string[];
|
||||
parameters: Parameter[];
|
||||
parametersPath: Parameter[];
|
||||
parametersQuery: Parameter[];
|
||||
parametersForm: Parameter[];
|
||||
parametersHeader: Parameter[];
|
||||
parametersBody: Parameter | null;
|
||||
}
|
||||
4
src/client/interfaces/OperationResponse.d.ts
vendored
Normal file
4
src/client/interfaces/OperationResponse.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export interface OperationResponse {
|
||||
code: number;
|
||||
text: string;
|
||||
}
|
||||
4
src/client/interfaces/OperationResult.d.ts
vendored
Normal file
4
src/client/interfaces/OperationResult.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export interface OperationResult {
|
||||
type: string;
|
||||
imports: string[];
|
||||
}
|
||||
13
src/client/interfaces/Parameter.d.ts
vendored
Normal file
13
src/client/interfaces/Parameter.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
export interface Parameter {
|
||||
prop: string;
|
||||
in: 'path' | 'query' | 'header' | 'formData' | 'body';
|
||||
name: string;
|
||||
type: string;
|
||||
base: string;
|
||||
template: string | null;
|
||||
description?: string;
|
||||
default?: any;
|
||||
required: boolean;
|
||||
nullable: boolean;
|
||||
imports: string[];
|
||||
}
|
||||
6
src/client/interfaces/Schema.d.ts
vendored
6
src/client/interfaces/Schema.d.ts
vendored
@ -1,5 +1,7 @@
|
||||
export interface Schema {
|
||||
name: string;
|
||||
type: string;
|
||||
base: string;
|
||||
imports: [];
|
||||
template: string | null;
|
||||
default?: any;
|
||||
imports: string[];
|
||||
}
|
||||
|
||||
4
src/client/interfaces/Service.d.ts
vendored
4
src/client/interfaces/Service.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
import { ServiceOperation } from './ServiceOperation';
|
||||
import { Operation } from './Operation';
|
||||
|
||||
export interface Service {
|
||||
name: string;
|
||||
operations: ServiceOperation[];
|
||||
operations: Operation[];
|
||||
imports: string[];
|
||||
}
|
||||
|
||||
23
src/client/interfaces/ServiceOperation.d.ts
vendored
23
src/client/interfaces/ServiceOperation.d.ts
vendored
@ -1,23 +0,0 @@
|
||||
import { ServiceOperationError } from './ServiceOperationError';
|
||||
import { ServiceOperationParameter } from './ServiceOperationParameter';
|
||||
import { Model } from './Model';
|
||||
import { ServiceOperationResponse } from './ServiceOperationResponse';
|
||||
|
||||
export interface ServiceOperation {
|
||||
name: string;
|
||||
summary?: string;
|
||||
description?: string;
|
||||
deprecated?: boolean;
|
||||
method: string;
|
||||
path: string;
|
||||
parameters: ServiceOperationParameter[];
|
||||
parametersPath: ServiceOperationParameter[];
|
||||
parametersQuery: ServiceOperationParameter[];
|
||||
parametersForm: ServiceOperationParameter[];
|
||||
parametersHeader: ServiceOperationParameter[];
|
||||
parametersBody: ServiceOperationParameter | null;
|
||||
models: Model[];
|
||||
errors: ServiceOperationError[];
|
||||
response: ServiceOperationResponse | null;
|
||||
result: string;
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
export interface ServiceOperationError {
|
||||
code: number;
|
||||
text: string;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
export interface ServiceOperationParameter {
|
||||
name: string;
|
||||
type: string;
|
||||
base: string;
|
||||
template: string;
|
||||
description: string;
|
||||
default?: any;
|
||||
required: boolean;
|
||||
nullable: boolean;
|
||||
// extends: string[];
|
||||
// imports: string[];
|
||||
// properties: ModelProperty[];
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
export interface ServiceOperationResponse {
|
||||
code: number;
|
||||
text: string;
|
||||
property: any;
|
||||
}
|
||||
12
src/index.ts
12
src/index.ts
@ -31,12 +31,12 @@ export function generate(input: string, output: string, language: Language = Lan
|
||||
const inputPath = path.resolve(process.cwd(), input);
|
||||
const outputPath = path.resolve(process.cwd(), output);
|
||||
|
||||
console.log(chalk.bold.green('Generate:'));
|
||||
console.log(chalk.grey(' Input:'), input);
|
||||
console.log(chalk.grey(' Output:'), output);
|
||||
console.log(chalk.grey(' Language:'), language);
|
||||
console.log(chalk.grey(' HTTP client:'), httpClient);
|
||||
console.log(os.EOL);
|
||||
// console.log(chalk.bold.green('Generate:'));
|
||||
// console.log(chalk.grey(' Input:'), input);
|
||||
// console.log(chalk.grey(' Output:'), output);
|
||||
// console.log(chalk.grey(' Language:'), language);
|
||||
// console.log(chalk.grey(' HTTP client:'), httpClient);
|
||||
// console.log(os.EOL);
|
||||
|
||||
try {
|
||||
// Load the specification, read the OpenAPI version and load the
|
||||
|
||||
@ -3,7 +3,6 @@ import { Client } from '../../client/interfaces/Client';
|
||||
import { getServer } from './parser/getServer';
|
||||
import { getServices } from './parser/getServices';
|
||||
import { getModels } from './parser/getModels';
|
||||
import { getSchemas } from './parser/getSchemas';
|
||||
|
||||
/**
|
||||
* Parse the OpenAPI specification to a Client model that contains
|
||||
@ -15,7 +14,6 @@ export function parse(openApi: OpenApi): Client {
|
||||
version: openApi.info.version,
|
||||
server: getServer(openApi),
|
||||
models: getModels(openApi),
|
||||
schemas: getSchemas(openApi),
|
||||
services: getServices(openApi),
|
||||
};
|
||||
}
|
||||
|
||||
2
src/openApi/v2/interfaces/OpenApiHeader.d.ts
vendored
2
src/openApi/v2/interfaces/OpenApiHeader.d.ts
vendored
@ -21,6 +21,6 @@ export interface OpenApiHeader {
|
||||
maxItems?: number;
|
||||
minItems?: number;
|
||||
uniqueItems?: boolean;
|
||||
enum?: (string | number)[];
|
||||
enum?: string[];
|
||||
multipleOf?: number;
|
||||
}
|
||||
|
||||
2
src/openApi/v2/interfaces/OpenApiItems.d.ts
vendored
2
src/openApi/v2/interfaces/OpenApiItems.d.ts
vendored
@ -17,6 +17,6 @@ export interface OpenApiItems {
|
||||
maxItems?: number;
|
||||
minItems?: number;
|
||||
uniqueItems?: number;
|
||||
enum?: (string | number)[];
|
||||
enum?: string[];
|
||||
multipleOf?: number;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { OpenApiItems } from './OpenApiItems';
|
||||
import { OpenApiSchema } from './OpenApiSchema';
|
||||
import { OpenApiReference } from './OpenApiReference';
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject
|
||||
@ -9,8 +10,8 @@ export interface OpenApiParameter {
|
||||
in: 'path' | 'query' | 'header' | 'formData' | 'body';
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
schema?: OpenApiSchema;
|
||||
type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'file';
|
||||
schema?: OpenApiSchema & OpenApiReference;
|
||||
type?: string;
|
||||
format?: 'int32' | 'int64' | 'float' | 'double' | 'string' | 'boolean' | 'byte' | 'binary' | 'date' | 'date-time' | 'password';
|
||||
allowEmptyValue?: boolean;
|
||||
items?: OpenApiItems;
|
||||
@ -26,6 +27,6 @@ export interface OpenApiParameter {
|
||||
maxItems?: number;
|
||||
minItems?: number;
|
||||
uniqueItems?: boolean;
|
||||
enum?: (string | number)[];
|
||||
enum?: string[];
|
||||
multipleOf?: number;
|
||||
}
|
||||
|
||||
@ -2,13 +2,14 @@ import { Dictionary } from '../../../utils/types';
|
||||
import { OpenApiExample } from './OpenApiExample';
|
||||
import { OpenApiHeader } from './OpenApiHeader';
|
||||
import { OpenApiSchema } from './OpenApiSchema';
|
||||
import { OpenApiReference } from './OpenApiReference';
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#responseObject
|
||||
*/
|
||||
export interface OpenApiResponse {
|
||||
description: string;
|
||||
schema?: OpenApiSchema;
|
||||
schema?: OpenApiSchema & OpenApiReference;
|
||||
headers?: Dictionary<OpenApiHeader>;
|
||||
examples?: OpenApiExample;
|
||||
}
|
||||
|
||||
@ -7,5 +7,5 @@ import { OpenApiResponse } from './OpenApiResponse';
|
||||
export interface OpenApiResponses {
|
||||
[httpcode: string]: OpenApiResponse & OpenApiReference;
|
||||
|
||||
default: OpenApiResponse & OpenApiReference;
|
||||
default?: OpenApiResponse & OpenApiReference;
|
||||
}
|
||||
|
||||
2
src/openApi/v2/interfaces/OpenApiSchema.d.ts
vendored
2
src/openApi/v2/interfaces/OpenApiSchema.d.ts
vendored
@ -25,7 +25,7 @@ export interface OpenApiSchema {
|
||||
maxProperties?: number;
|
||||
minProperties?: number;
|
||||
required?: string[];
|
||||
enum?: (string | number)[];
|
||||
enum?: string[];
|
||||
type?: string;
|
||||
items?: OpenApiSchema & OpenApiReference;
|
||||
allOf?: (OpenApiSchema & OpenApiReference)[];
|
||||
|
||||
45
src/openApi/v2/parser/getArrayType.ts
Normal file
45
src/openApi/v2/parser/getArrayType.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { getType } from './getType';
|
||||
import { Type } from '../../../client/interfaces/Type';
|
||||
import { OpenApiItems } from '../interfaces/OpenApiItems';
|
||||
import { getEnumType } from './getEnumType';
|
||||
import { ArrayType } from '../../../client/interfaces/ArrayType';
|
||||
|
||||
export function getArrayType(items: OpenApiItems): ArrayType {
|
||||
let itemsType = 'any';
|
||||
let itemsBase = 'any';
|
||||
let itemsTemplate: string | null = null;
|
||||
const itemsImports: string[] = [];
|
||||
|
||||
// If the parameter has a type than it can be a basic or generic type.
|
||||
if (items.type) {
|
||||
const itemsData: Type = getType(items.type);
|
||||
itemsType = itemsData.type;
|
||||
itemsBase = itemsData.base;
|
||||
itemsTemplate = itemsData.template;
|
||||
itemsImports.push(...itemsData.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) {
|
||||
console.log('templated array', items.items);
|
||||
// Parse the child types and create a correct Array type, for example "string[]" or "ActivityData[]"
|
||||
// const child: ParsedProperty = parseProperty(parameter.items, template);
|
||||
// parameterType = `${child.type}[]`;
|
||||
// parameterBase = child.base;
|
||||
// parameterTemplate = child.template;
|
||||
// parameterImports.push(...child.imports);
|
||||
}
|
||||
}
|
||||
|
||||
if (items.enum) {
|
||||
itemsType = getEnumType(items.enum, true);
|
||||
}
|
||||
|
||||
return {
|
||||
type: itemsType,
|
||||
base: itemsBase,
|
||||
template: itemsTemplate,
|
||||
default: items.default,
|
||||
imports: itemsImports,
|
||||
};
|
||||
}
|
||||
6
src/openApi/v2/parser/getComment.ts
Normal file
6
src/openApi/v2/parser/getComment.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export function getComment(comment: string | undefined): string | undefined {
|
||||
if (comment) {
|
||||
return comment.replace(/(\r\n|\n|\r)+/g, '$1 * ');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
20
src/openApi/v2/parser/getEnumType.ts
Normal file
20
src/openApi/v2/parser/getEnumType.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export function getEnumType(values?: string[], addParentheses = false): string {
|
||||
if (Array.isArray(values)) {
|
||||
// Filter out empty and double enum values.
|
||||
// Plus make sure we put quotes around strings!
|
||||
const entries: string[] = values
|
||||
.filter(name => name)
|
||||
.filter((name, index, arr) => arr.indexOf(name) === index)
|
||||
.map(value => `'${String(value)}'`);
|
||||
|
||||
// Add grouping parentheses if needed. This can be handy if enum values
|
||||
// are used in Arrays, so that you will get the following definition:
|
||||
// const myArray: ('EnumValue1' | 'EnumValue2' | 'EnumValue3')[];
|
||||
if (entries.length > 1 && addParentheses) {
|
||||
return `(${entries.join(' | ')})`;
|
||||
}
|
||||
|
||||
return entries.join(' | ');
|
||||
}
|
||||
return 'string';
|
||||
}
|
||||
32
src/openApi/v2/parser/getEnumTypeFromDescription.ts
Normal file
32
src/openApi/v2/parser/getEnumTypeFromDescription.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export function getEnumTypeFromDescription(description: string, addParentheses = false): string | null {
|
||||
// Check if we can find this special format string:
|
||||
// None=0,Something=1,AnotherThing=2
|
||||
const matches: RegExpMatchArray | null = description.match(/((\w+)=([0-9]+)(?:,|$))/g);
|
||||
if (matches) {
|
||||
// Grab the values from the description
|
||||
const values: number[] = [];
|
||||
for (let i = 0, n = matches.length; i < n; i++) {
|
||||
const value = parseInt(matches[i].split('=')[1].replace(/[^0-9]/g, ''));
|
||||
if (Number.isInteger(value)) {
|
||||
values.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter and sort the values
|
||||
const entries: string[] = values
|
||||
.sort()
|
||||
.filter((name, index, arr) => arr.indexOf(name) === index)
|
||||
.map(value => String(value));
|
||||
|
||||
// Add grouping parentheses if needed. This can be handy if enum values
|
||||
// are used in Arrays, so that you will get the following definition:
|
||||
// const myArray: ('EnumValue1' | 'EnumValue2' | 'EnumValue3')[];
|
||||
if (entries.length > 1 && addParentheses) {
|
||||
return `(${entries.join(' | ')})`;
|
||||
}
|
||||
|
||||
return entries.join(' | ');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -30,7 +30,7 @@ const MAPPINGS = new Map<string, string>([
|
||||
* @param type
|
||||
*/
|
||||
export function getMappedType(type: string): string {
|
||||
const mapped = MAPPINGS.get(type.toLowerCase());
|
||||
const mapped: string | undefined = MAPPINGS.get(type.toLowerCase());
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { ModelProperties } from '../../../client/interfaces/ModelProperties';
|
||||
|
||||
export function parseModelProperties(): ModelProperties {
|
||||
export function parseModelProperties(): any {
|
||||
return {
|
||||
imports: [],
|
||||
properties: [],
|
||||
|
||||
@ -1,49 +1,47 @@
|
||||
import { Model } from '../../../client/interfaces/Model';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { getType } from './getType';
|
||||
|
||||
/**
|
||||
* Parse and return the OpenAPI models.
|
||||
* @param openApi
|
||||
* Get the OpenAPI models.
|
||||
*/
|
||||
export function getModels(openApi: OpenApi): Map<string, Model> {
|
||||
const models = new Map<string, Model>();
|
||||
const models: Map<string, Model> = new Map<string, Model>();
|
||||
|
||||
// Iterate over the definitions
|
||||
const definitions = openApi.definitions;
|
||||
const { definitions } = openApi;
|
||||
for (const definitionName in definitions) {
|
||||
if (definitions.hasOwnProperty(definitionName)) {
|
||||
const definition = definitions[definitionName];
|
||||
const required = definition.required || [];
|
||||
const modelClass = getType(definitionName);
|
||||
|
||||
// const definition: OpenApiSchema = openApi.definitions[definitionName];
|
||||
// const required: string[] = definition.required || [];
|
||||
// const modelClass: Type = getType(definitionName);
|
||||
// Check if we haven't already parsed the model
|
||||
if (!models.has(modelClass.base)) {
|
||||
// // Create a new model object
|
||||
// const model: Model = {
|
||||
// name: modelClass.base,
|
||||
// base: modelClass.base,
|
||||
// type: modelClass.type,
|
||||
// template: getModelTemplate(modelClass),
|
||||
// description: null,
|
||||
// extends: [],
|
||||
// imports: [],
|
||||
// properties: [],
|
||||
// enums: [],
|
||||
// };
|
||||
//
|
||||
// const properties = definition.properties;
|
||||
// for (const propertyName in properties) {
|
||||
// if (properties.hasOwnProperty(propertyName)) {
|
||||
// const property = properties[propertyName];
|
||||
// const propertyRequired = required.includes(propertyName);
|
||||
// getModelProperty(propertyName, property);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// models.set(modelClass.base, model);
|
||||
}
|
||||
// if (!models.has(modelClass.base)) {
|
||||
// // Create a new model object
|
||||
// const model: Model = {
|
||||
// name: modelClass.base,
|
||||
// base: modelClass.base,
|
||||
// type: modelClass.type,
|
||||
// template: getModelTemplate(modelClass),
|
||||
// description: null,
|
||||
// extends: [],
|
||||
// imports: [],
|
||||
// properties: [],
|
||||
// enums: [],
|
||||
// };
|
||||
//
|
||||
// const properties = definition.properties;
|
||||
// for (const propertyName in properties) {
|
||||
// if (properties.hasOwnProperty(propertyName)) {
|
||||
// const property = properties[propertyName];
|
||||
// const propertyRequired = required.includes(propertyName);
|
||||
// getModelProperty(propertyName, property);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// models.set(modelClass.base, model);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
64
src/openApi/v2/parser/getOperation.ts
Normal file
64
src/openApi/v2/parser/getOperation.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { Service } from '../../../client/interfaces/Service';
|
||||
import { getServiceClassName } from './getServiceClassName';
|
||||
import { Operation } from '../../../client/interfaces/Operation';
|
||||
import { OpenApiOperation } from '../interfaces/OpenApiOperation';
|
||||
import { getOperationName } from './getOperationName';
|
||||
import { getOperationPath } from './getOperationPath';
|
||||
import { getOperationParameters } from './getOperationParameters';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { getComment } from './getComment';
|
||||
import { getOperationResponses } from './getOperationResponses';
|
||||
import { OperationParameters } from '../../../client/interfaces/OperationParameters';
|
||||
import { OperationResponse } from '../../../client/interfaces/OperationResponse';
|
||||
|
||||
export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation): Operation {
|
||||
const serviceName = (op.tags && op.tags[0]) || 'Service';
|
||||
const serviceClassName = getServiceClassName(serviceName);
|
||||
const operationNameFallback = `${method}${serviceClassName}`;
|
||||
const operationName = getOperationName(op.operationId || operationNameFallback);
|
||||
const operationPath = getOperationPath(url);
|
||||
|
||||
// Create a new operation object for this method.
|
||||
const operation: Operation = {
|
||||
service: serviceClassName,
|
||||
name: operationName,
|
||||
summary: getComment(op.summary),
|
||||
description: getComment(op.description),
|
||||
deprecated: op.deprecated,
|
||||
method: method,
|
||||
path: operationPath,
|
||||
parameters: [],
|
||||
parametersPath: [],
|
||||
parametersQuery: [],
|
||||
parametersForm: [],
|
||||
parametersHeader: [],
|
||||
parametersBody: null,
|
||||
imports: [],
|
||||
errors: [],
|
||||
result: 'void',
|
||||
};
|
||||
|
||||
// Parse the operation parameters (path, query, body, etc).
|
||||
if (op.parameters) {
|
||||
const parameters: OperationParameters = getOperationParameters(openApi, op.parameters);
|
||||
operation.imports.push(...parameters.imports);
|
||||
operation.parameters.push(...parameters.parameters);
|
||||
operation.parametersPath.push(...parameters.parametersPath);
|
||||
operation.parametersQuery.push(...parameters.parametersQuery);
|
||||
operation.parametersForm.push(...parameters.parametersForm);
|
||||
operation.parametersHeader.push(...parameters.parametersHeader);
|
||||
operation.parametersBody = parameters.parametersBody;
|
||||
}
|
||||
|
||||
// Parse the operation responses.
|
||||
if (op.responses) {
|
||||
const responses: OperationResponse[] = getOperationResponses(openApi, op.responses);
|
||||
// const result: OperationResponse = getOperationResult(responses);
|
||||
// const errors = getOperationErrors(responses);
|
||||
// operation.imports.push(...result.imports);
|
||||
// operation.errors = errors;
|
||||
// operation.result = result.type;
|
||||
}
|
||||
|
||||
return operation;
|
||||
}
|
||||
11
src/openApi/v2/parser/getOperationErrors.ts
Normal file
11
src/openApi/v2/parser/getOperationErrors.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { OperationResponse } from '../../../client/interfaces/OperationResponse';
|
||||
import { OperationError } from '../../../client/interfaces/OperationError';
|
||||
|
||||
export function getOperationErrors(responses: OperationResponse[]): OperationError[] {
|
||||
return responses
|
||||
.filter((response: OperationResponse): boolean => response.code >= 300 && response.text !== undefined && response.text !== '')
|
||||
.map(response => ({
|
||||
code: response.code,
|
||||
text: response.text,
|
||||
}));
|
||||
}
|
||||
10
src/openApi/v2/parser/getOperationName.spec.ts
Normal file
10
src/openApi/v2/parser/getOperationName.spec.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { getOperationName } from './getOperationName';
|
||||
|
||||
describe('getOperationName', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getOperationName('')).toEqual('');
|
||||
expect(getOperationName('FooBar')).toEqual('fooBar');
|
||||
expect(getOperationName('Foo Bar')).toEqual('fooBar');
|
||||
expect(getOperationName('foo bar')).toEqual('fooBar');
|
||||
});
|
||||
});
|
||||
11
src/openApi/v2/parser/getOperationName.ts
Normal file
11
src/openApi/v2/parser/getOperationName.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import camelCase from 'camelcase';
|
||||
|
||||
/**
|
||||
* Convert the input value to a correct operation (method) classname.
|
||||
* This converts the input string to camelCase, so the method name follows
|
||||
* the most popular Javascript and Typescript writing style.
|
||||
*/
|
||||
export function getOperationName(value: string): string {
|
||||
const clean = value.replace(/[^\w\s\-]+/g, '_').trim();
|
||||
return camelCase(clean);
|
||||
}
|
||||
74
src/openApi/v2/parser/getOperationParameters.ts
Normal file
74
src/openApi/v2/parser/getOperationParameters.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { OpenApiParameter } from '../interfaces/OpenApiParameter';
|
||||
import { OperationParameters } from '../../../client/interfaces/OperationParameters';
|
||||
import { OpenApiReference } from '../interfaces/OpenApiReference';
|
||||
import { Parameter } from '../../../client/interfaces/Parameter';
|
||||
import { getParameter } from './getParameter';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { getRef } from './getRef';
|
||||
|
||||
function sortByRequired(a: Parameter, b: Parameter): number {
|
||||
return a.required && !b.required ? -1 : !a.required && b.required ? 1 : 0;
|
||||
}
|
||||
|
||||
export function getOperationParameters(openApi: OpenApi, parametersOrReferences: (OpenApiParameter & OpenApiReference)[]): OperationParameters {
|
||||
const imports: string[] = [];
|
||||
const parameters: Parameter[] = [];
|
||||
const parametersPath: Parameter[] = [];
|
||||
const parametersQuery: Parameter[] = [];
|
||||
const parametersForm: Parameter[] = [];
|
||||
const parametersHeader: Parameter[] = [];
|
||||
let parametersBody: Parameter | null = null;
|
||||
|
||||
// Iterate over the parameters
|
||||
for (let i = 0, n = parametersOrReferences.length; i < n; i++) {
|
||||
const parameterOrReference: OpenApiParameter & OpenApiReference = parametersOrReferences[i];
|
||||
const parameter: OpenApiParameter = getRef<OpenApiParameter>(openApi, parameterOrReference);
|
||||
const param: Parameter = getParameter(openApi, parameter);
|
||||
|
||||
// We ignore the "api-version" param, since we do not want to add this
|
||||
// as the first / default parameter for each of the service calls.
|
||||
if (param.prop !== 'api-version') {
|
||||
switch (parameter.in) {
|
||||
case 'path':
|
||||
parametersPath.push(param);
|
||||
parameters.push(param);
|
||||
imports.push(...param.imports);
|
||||
break;
|
||||
|
||||
case 'query':
|
||||
parametersQuery.push(param);
|
||||
parameters.push(param);
|
||||
imports.push(...param.imports);
|
||||
break;
|
||||
|
||||
case 'header':
|
||||
parametersHeader.push(param);
|
||||
parameters.push(param);
|
||||
imports.push(...param.imports);
|
||||
break;
|
||||
|
||||
case 'formData':
|
||||
parametersForm.push(param);
|
||||
parameters.push(param);
|
||||
imports.push(...param.imports);
|
||||
break;
|
||||
|
||||
case 'body':
|
||||
parametersBody = param;
|
||||
parameters.push(param);
|
||||
imports.push(...param.imports);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
imports,
|
||||
parameters: parameters.sort(sortByRequired),
|
||||
parametersPath: parametersPath.sort(sortByRequired),
|
||||
parametersQuery: parametersQuery.sort(sortByRequired),
|
||||
parametersForm: parametersForm.sort(sortByRequired),
|
||||
parametersHeader: parametersHeader.sort(sortByRequired),
|
||||
parametersBody: parametersBody,
|
||||
};
|
||||
}
|
||||
10
src/openApi/v2/parser/getOperationPath.spec.ts
Normal file
10
src/openApi/v2/parser/getOperationPath.spec.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { getOperationPath } from './getOperationPath';
|
||||
|
||||
describe('getOperationPath', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getOperationPath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}/${type}');
|
||||
expect(getOperationPath('/api/v{api-version}/list/{id}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}');
|
||||
expect(getOperationPath('/api/v1/list/{id}')).toEqual('/api/v1/list/${id}');
|
||||
expect(getOperationPath('/api/v1/list')).toEqual('/api/v1/list');
|
||||
});
|
||||
});
|
||||
@ -4,6 +4,6 @@
|
||||
* OpenAPI version without the need to hardcode this in the URL.
|
||||
* @param path
|
||||
*/
|
||||
export function getServicePath(path: string): string {
|
||||
export function getOperationPath(path: string): string {
|
||||
return path.replace(/{api-version}/g, '{OpenAPI.VERSION}').replace(/\{(.*?)\}/g, '${$1}');
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
export function getServiceOperationResponsesCode(value: string | 'default'): number | null {
|
||||
export function getOperationResponseCode(value: string | 'default'): number | null {
|
||||
// You can specify a "default" response, this is treated as HTTP code 200
|
||||
if (value === 'default') {
|
||||
return 200;
|
||||
@ -6,7 +6,7 @@ export function getServiceOperationResponsesCode(value: string | 'default'): num
|
||||
|
||||
// Check if we can parse the code and return of successful.
|
||||
if (/[0-9]+/g.test(value)) {
|
||||
const code = parseInt(value);
|
||||
const code: number = parseInt(value);
|
||||
if (Number.isInteger(code)) {
|
||||
return code;
|
||||
}
|
||||
39
src/openApi/v2/parser/getOperationResponses.ts
Normal file
39
src/openApi/v2/parser/getOperationResponses.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { OpenApiResponses } from '../interfaces/OpenApiResponses';
|
||||
import { getOperationResponseCode } from './getOperationResponseCode';
|
||||
import { OperationResponse } from '../../../client/interfaces/OperationResponse';
|
||||
import { OpenApiResponse } from '../interfaces/OpenApiResponse';
|
||||
import { OpenApiReference } from '../interfaces/OpenApiReference';
|
||||
import { getRef } from './getRef';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
|
||||
export function getOperationResponses(openApi: OpenApi, responses: OpenApiResponses): OperationResponse[] {
|
||||
const result: OperationResponse[] = [];
|
||||
|
||||
// Iterate over each response code and get the
|
||||
// status code and response message (if any).
|
||||
for (const code in responses) {
|
||||
if (responses.hasOwnProperty(code)) {
|
||||
const responseOrReference: OpenApiResponse & OpenApiReference = responses[code];
|
||||
const response: OpenApiResponse = getRef<OpenApiResponse>(openApi, responseOrReference);
|
||||
const responseCode: number | null = getOperationResponseCode(code);
|
||||
const responseText: string = response.description || '';
|
||||
|
||||
// TODO:
|
||||
if (response.schema) {
|
||||
console.log('response.schema', response.schema);
|
||||
}
|
||||
|
||||
if (responseCode) {
|
||||
result.push({
|
||||
code: responseCode,
|
||||
text: responseText,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the responses to 2XX success codes come before 4XX and 5XX error codes.
|
||||
return result.sort((a, b): number => {
|
||||
return a.code < b.code ? -1 : a.code > b.code ? 1 : 0;
|
||||
});
|
||||
}
|
||||
19
src/openApi/v2/parser/getOperationResult.ts
Normal file
19
src/openApi/v2/parser/getOperationResult.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { OperationResponse } from '../../../client/interfaces/OperationResponse';
|
||||
|
||||
export function getOperationResult(responses: OperationResponse[]): OperationResponse {
|
||||
const resultCode = 200;
|
||||
const resultTes: string[] = [];
|
||||
|
||||
// Fetch the first valid (2XX range) response code and return that type.
|
||||
const result: OperationResponse | undefined = responses.find(response => response.code && response.code >= 200 && response.code < 300 && response.property);
|
||||
|
||||
if (result && result.property) {
|
||||
resultType = result.property.type;
|
||||
resultImports = [...result.property.imports];
|
||||
}
|
||||
|
||||
return {
|
||||
type: resultType,
|
||||
imports: resultImports,
|
||||
};
|
||||
}
|
||||
72
src/openApi/v2/parser/getParameter.ts
Normal file
72
src/openApi/v2/parser/getParameter.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { OpenApiParameter } from '../interfaces/OpenApiParameter';
|
||||
import { getType } from './getType';
|
||||
import { Parameter } from '../../../client/interfaces/Parameter';
|
||||
import { Type } from '../../../client/interfaces/Type';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { getParameterName } from './getParameterName';
|
||||
import { getArrayType } from './getArrayType';
|
||||
import { ArrayType } from '../../../client/interfaces/ArrayType';
|
||||
import { getEnumType } from './getEnumType';
|
||||
import { getEnumTypeFromDescription } from './getEnumTypeFromDescription';
|
||||
import { getComment } from './getComment';
|
||||
|
||||
export function getParameter(openApi: OpenApi, parameter: OpenApiParameter): Parameter {
|
||||
let parameterType = 'any';
|
||||
let parameterBase = 'any';
|
||||
let parameterTemplate: string | null = null;
|
||||
const parameterImports: string[] = [];
|
||||
|
||||
// If the parameter has a type than it can be a basic or generic type.
|
||||
if (parameter.type) {
|
||||
const parameterData: Type = getType(parameter.type);
|
||||
parameterType = parameterData.type;
|
||||
parameterBase = parameterData.base;
|
||||
parameterTemplate = parameterData.template;
|
||||
parameterImports.push(...parameterData.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 (parameter.type === 'array' && parameter.items) {
|
||||
const arrayType: ArrayType = getArrayType(parameter.items);
|
||||
parameterType = `${arrayType.type}[]`;
|
||||
parameterBase = arrayType.base;
|
||||
parameterTemplate = arrayType.template;
|
||||
parameterImports.push(...arrayType.imports);
|
||||
}
|
||||
}
|
||||
|
||||
// If this parameter has a schema, then we should treat it as an embedded parameter.
|
||||
// We can just parse the schema name ($ref) and use that as the parameter type.
|
||||
if (parameter.schema) {
|
||||
// TODO: console.log('parameter.schema', parameter.schema);
|
||||
}
|
||||
|
||||
// If the param is a enum then return the values as an inline type.
|
||||
if (parameter.enum) {
|
||||
parameterType = getEnumType(parameter.enum);
|
||||
parameterBase = 'string';
|
||||
}
|
||||
|
||||
// Check if this could be a special enum where values are documented in the description.
|
||||
if (parameter.description && parameter.type === 'int') {
|
||||
const enumType: string | null = getEnumTypeFromDescription(parameter.description);
|
||||
if (enumType) {
|
||||
parameterType = enumType;
|
||||
parameterBase = 'number';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
in: parameter.in,
|
||||
prop: parameter.name,
|
||||
name: getParameterName(parameter.name),
|
||||
type: parameterType,
|
||||
base: parameterBase,
|
||||
template: parameterTemplate,
|
||||
description: getComment(parameter.description),
|
||||
default: parameter.default,
|
||||
required: parameter.required || false,
|
||||
nullable: false,
|
||||
imports: parameterImports,
|
||||
};
|
||||
}
|
||||
10
src/openApi/v2/parser/getParameterName.ts
Normal file
10
src/openApi/v2/parser/getParameterName.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import camelCase from 'camelcase';
|
||||
|
||||
/**
|
||||
* Replaces any invalid characters from a parameter name.
|
||||
* For example: 'filter.someProperty' becomes 'filterSomeProperty'.
|
||||
*/
|
||||
export function getParameterName(value: string): string {
|
||||
const clean = value.replace(/[^\w\s\-]+/g, '_').trim();
|
||||
return camelCase(clean);
|
||||
}
|
||||
27
src/openApi/v2/parser/getRef.ts
Normal file
27
src/openApi/v2/parser/getRef.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { OpenApiReference } from '../interfaces/OpenApiReference';
|
||||
|
||||
export function getRef<T>(openApi: OpenApi, item: T & OpenApiReference): T {
|
||||
if (item.$ref) {
|
||||
// Fetch the paths to the definitions, this converts:
|
||||
// "#/definitions/Form" to ["definitions", "Form"]
|
||||
const paths = item.$ref
|
||||
.replace(/^#/g, '')
|
||||
.split('/')
|
||||
.filter(item => item);
|
||||
|
||||
// Try to find the reference by walking down the path,
|
||||
// if we cannot find it, then we throw an error.
|
||||
let result: any = openApi;
|
||||
for (let i = 0, n = paths.length; i < n; i++) {
|
||||
const path: string = paths[i];
|
||||
if (result.hasOwnProperty(path)) {
|
||||
result = result[path];
|
||||
} else {
|
||||
throw new Error(`Could not find reference: "${item.$ref}"`);
|
||||
}
|
||||
}
|
||||
return result as T;
|
||||
}
|
||||
return item as T;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
import { Schema } from '../../../client/interfaces/Schema';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
|
||||
/**
|
||||
* Parse and return the OpenAPI schemas.
|
||||
* @param openApi
|
||||
*/
|
||||
export function getSchemas(openApi: OpenApi): Map<string, Schema> {
|
||||
const schemas = new Map<string, Schema>();
|
||||
return schemas;
|
||||
}
|
||||
@ -4,9 +4,15 @@ describe('getServer', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(
|
||||
getServer({
|
||||
swagger: '2.0',
|
||||
info: {
|
||||
title: 'dummy',
|
||||
version: '1.0',
|
||||
},
|
||||
host: 'localhost:8080',
|
||||
basePath: '/api',
|
||||
schemes: ['http', 'https'],
|
||||
paths: {},
|
||||
})
|
||||
).toEqual('http://localhost:8080/api');
|
||||
});
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
|
||||
type Props = Pick<OpenApi, 'schemes' | 'host' | 'basePath'>;
|
||||
|
||||
export function getServer(openApi: Props): string {
|
||||
/**
|
||||
* Get the base server url.
|
||||
* @param openApi
|
||||
*/
|
||||
export function getServer(openApi: OpenApi): string {
|
||||
const scheme = (openApi.schemes && openApi.schemes[0]) || 'http';
|
||||
const host = openApi.host;
|
||||
const basePath = openApi.basePath || '';
|
||||
|
||||
@ -3,10 +3,10 @@ import camelCase from 'camelcase';
|
||||
/**
|
||||
* Convert the input value to a correct service classname. This converts
|
||||
* the input string to PascalCase and appends the "Service" prefix if needed.
|
||||
* @param value
|
||||
*/
|
||||
export function getServiceClassName(value: string): string {
|
||||
const name = camelCase(value, { pascalCase: true });
|
||||
const clean = value.replace(/[^\w\s\-]+/g, '_').trim();
|
||||
const name: string = camelCase(clean, { pascalCase: true });
|
||||
if (name && !name.endsWith('Service')) {
|
||||
return `${name}Service`;
|
||||
}
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { ServiceOperationResponse } from '../../../client/interfaces/ServiceOperationResponse';
|
||||
import { ServiceOperationError } from '../../../client/interfaces/ServiceOperationError';
|
||||
|
||||
/**
|
||||
* Get list of service errors.
|
||||
* @param responses List of parsed service responses.
|
||||
* @returns List of service errors containing the error code and message.
|
||||
*/
|
||||
export function getServiceOperationErrors(responses: ServiceOperationResponse[]): ServiceOperationError[] {
|
||||
return responses
|
||||
.filter((response: ServiceOperationResponse): boolean => response.code >= 300 && response.text !== undefined && response.text !== '')
|
||||
.map(response => ({
|
||||
code: response.code,
|
||||
text: response.text,
|
||||
}));
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { getServiceOperationName } from './getServiceOperationName';
|
||||
|
||||
describe('getServiceOperationName', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getServiceOperationName('')).toEqual('');
|
||||
expect(getServiceOperationName('FooBar')).toEqual('fooBar');
|
||||
expect(getServiceOperationName('Foo Bar')).toEqual('fooBar');
|
||||
expect(getServiceOperationName('foo bar')).toEqual('fooBar');
|
||||
});
|
||||
});
|
||||
@ -1,11 +0,0 @@
|
||||
import camelCase from 'camelcase';
|
||||
|
||||
/**
|
||||
* Convert the input value to a correct operation (method) classname. This converts
|
||||
* the input string to cascalCase, so the method name follows the most popular
|
||||
* Javascript and Typescript writing style.
|
||||
* @param value
|
||||
*/
|
||||
export function getServiceOperationName(value: string): string {
|
||||
return camelCase(value);
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { getServiceOperationPath } from './getServiceOperationPath';
|
||||
|
||||
describe('getServiceOperationPath', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getServiceOperationPath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}/${type}');
|
||||
expect(getServiceOperationPath('/api/v{api-version}/list/{id}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}');
|
||||
expect(getServiceOperationPath('/api/v1/list/{id}')).toEqual('/api/v1/list/${id}');
|
||||
expect(getServiceOperationPath('/api/v1/list')).toEqual('/api/v1/list');
|
||||
});
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Get the final service path, this replaces the "{api-version}" placeholder
|
||||
* with a new template string placeholder so we can dynamically inject the
|
||||
* OpenAPI version without the need to hardcode this in the URL.
|
||||
* @param path
|
||||
*/
|
||||
export function getServiceOperationPath(path: string): string {
|
||||
return path.replace(/{api-version}/g, '{OpenAPI.VERSION}').replace(/\{(.*?)\}/g, '${$1}');
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
import { OpenApiResponses } from '../interfaces/OpenApiResponses';
|
||||
import { ServiceOperationResponse } from '../../../client/interfaces/ServiceOperationResponse';
|
||||
import { getServiceOperationResponsesCode } from './getServiceOperationResponseCode';
|
||||
|
||||
/**
|
||||
* Parse the service response object into a list with status codes and response messages.
|
||||
* @param responses Swagger responses.
|
||||
* @returns List of status codes and response messages.
|
||||
*/
|
||||
export function getServiceOperationResponses(responses: OpenApiResponses): ServiceOperationResponse[] {
|
||||
const result: ServiceOperationResponse[] = [];
|
||||
|
||||
// Iterate over each response code.
|
||||
for (const code in responses) {
|
||||
if (responses.hasOwnProperty(code)) {
|
||||
// Get the status code and response message (if any).
|
||||
const response = responses[code];
|
||||
const responseCode = getServiceOperationResponsesCode(code);
|
||||
const responseText = response.description || '';
|
||||
|
||||
if (responseCode) {
|
||||
result.push({
|
||||
code: responseCode,
|
||||
text: responseText,
|
||||
property: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the responses to 2XX success codes come before 4XX and 5XX error codes.
|
||||
return result.sort((a, b): number => {
|
||||
return a.code < b.code ? -1 : a.code > b.code ? 1 : 0;
|
||||
});
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
import { ServiceOperationResponse } from '../../../client/interfaces/ServiceOperationResponse';
|
||||
|
||||
export interface ServiceOperationResult {
|
||||
type: string;
|
||||
imports: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse service result.
|
||||
* @param responses List of service responses.
|
||||
* @returns Object containing the result type and needed imports.
|
||||
*/
|
||||
export function getServiceOperationResult(responses: ServiceOperationResponse[]): ServiceOperationResult {
|
||||
let resultType = 'any';
|
||||
let resultImports: string[] = [];
|
||||
|
||||
// Fetch the first valid (2XX range) response code and return that type.
|
||||
const result = responses.find(response => response.code && response.code >= 200 && response.code < 300 && response.property);
|
||||
|
||||
if (result) {
|
||||
resultType = result.property.type;
|
||||
resultImports = [...result.property.imports];
|
||||
}
|
||||
|
||||
return {
|
||||
type: resultType,
|
||||
imports: resultImports,
|
||||
};
|
||||
}
|
||||
@ -1,78 +1,54 @@
|
||||
import { Service } from '../../../client/interfaces/Service';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { OpenApiPath } from '../interfaces/OpenApiPath';
|
||||
import { OpenApiOperation } from '../interfaces/OpenApiOperation';
|
||||
import { getServiceClassName } from './getServiceClassName';
|
||||
import { getServiceOperationName } from './getServiceOperationName';
|
||||
import { getServiceOperationPath } from './getServiceOperationPath';
|
||||
import { ServiceOperation } from '../../../client/interfaces/ServiceOperation';
|
||||
import { getServiceOperationResponses } from './getServiceOperationResponses';
|
||||
import { getServiceOperationResult } from './getServiceOperationResult';
|
||||
import { getServiceOperationErrors } from './getServiceOperationErrors';
|
||||
|
||||
function getMethod(url: string, services: Map<string, Service>, op: OpenApiOperation, method: string): void {
|
||||
const serviceName = (op.tags && op.tags[0]) || 'Service';
|
||||
const serviceClassName: string = getServiceClassName(serviceName);
|
||||
const serviceOperationNameFallback = `${method}${serviceClassName}`;
|
||||
const serviceOperationName: string = getServiceOperationName(op.operationId || serviceOperationNameFallback);
|
||||
const servicePath: string = getServiceOperationPath(url);
|
||||
|
||||
// If we have already declared a service, then we should fetch that and
|
||||
// append the new method to it. Otherwise we should create a new service object.
|
||||
const service =
|
||||
services.get(serviceClassName) ||
|
||||
({
|
||||
name: serviceClassName,
|
||||
imports: [],
|
||||
operations: [],
|
||||
} as Service);
|
||||
|
||||
// Create a new operation object for this method.
|
||||
const operation: ServiceOperation = {
|
||||
name: serviceOperationName,
|
||||
summary: op.summary,
|
||||
description: op.description,
|
||||
deprecated: op.deprecated,
|
||||
method: method,
|
||||
path: servicePath,
|
||||
parameters: [],
|
||||
parametersPath: [],
|
||||
parametersQuery: [],
|
||||
parametersForm: [],
|
||||
parametersHeader: [],
|
||||
parametersBody: null,
|
||||
models: [],
|
||||
errors: [],
|
||||
response: null,
|
||||
result: 'any',
|
||||
};
|
||||
|
||||
if (op.responses) {
|
||||
const responses = getServiceOperationResponses(op.responses);
|
||||
const result = getServiceOperationResult(responses);
|
||||
operation.errors = getServiceOperationErrors(responses);
|
||||
operation.result = result.type;
|
||||
service.imports.push(...result.imports);
|
||||
}
|
||||
|
||||
service.operations.push(operation);
|
||||
services.set(serviceClassName, service);
|
||||
}
|
||||
import { getOperation } from './getOperation';
|
||||
import { Operation } from '../../../client/interfaces/Operation';
|
||||
|
||||
/**
|
||||
* Parse and return the OpenAPI services.
|
||||
* @param openApi
|
||||
* Get the OpenAPI services
|
||||
*/
|
||||
export function getServices(openApi: OpenApi): Map<string, Service> {
|
||||
const services = new Map<string, Service>();
|
||||
Object.keys(openApi.paths).forEach(url => {
|
||||
const path = openApi.paths[url];
|
||||
path.get && getMethod(url, services, path.get, 'get');
|
||||
path.put && getMethod(url, services, path.put, 'put');
|
||||
path.post && getMethod(url, services, path.post, 'post');
|
||||
path.delete && getMethod(url, services, path.delete, 'delete');
|
||||
path.options && getMethod(url, services, path.options, 'options');
|
||||
path.head && getMethod(url, services, path.head, 'head');
|
||||
path.patch && getMethod(url, services, path.patch, 'patch');
|
||||
});
|
||||
const services: Map<string, Service> = new Map<string, Service>();
|
||||
|
||||
const { paths } = openApi;
|
||||
for (const url in paths) {
|
||||
if (paths.hasOwnProperty(url)) {
|
||||
const path: OpenApiPath = paths[url];
|
||||
for (const method in path) {
|
||||
if (path.hasOwnProperty(method)) {
|
||||
// Check supported methods
|
||||
switch (method) {
|
||||
case 'get':
|
||||
case 'put':
|
||||
case 'post':
|
||||
case 'delete':
|
||||
case 'options':
|
||||
case 'head':
|
||||
case 'patch':
|
||||
// Each method contains an OpenAPI operation, we parse the operation
|
||||
const op: OpenApiOperation = path[method]!;
|
||||
const operation: Operation = getOperation(openApi, url, method, op);
|
||||
|
||||
// If we have already declared a service, then we should fetch that and
|
||||
// append the new method to it. Otherwise we should create a new service object.
|
||||
const service =
|
||||
services.get(operation.service) ||
|
||||
({
|
||||
name: operation.service,
|
||||
operations: [],
|
||||
imports: [],
|
||||
} as Service);
|
||||
|
||||
// Push the operation in the service
|
||||
service.operations.push(operation);
|
||||
service.imports.push(...operation.imports);
|
||||
services.set(operation.service, service);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import { Type } from '../../../client/interfaces/Type';
|
||||
import { getMappedType, hasMappedType } from './getMappedType';
|
||||
|
||||
/**
|
||||
* Parse any value into a type object.
|
||||
* Parse any string value into a type object.
|
||||
* @param value String value like "integer" or "Link[Model]".
|
||||
* @param template Optional template class from parent (needed to process generics)
|
||||
*/
|
||||
@ -14,16 +14,15 @@ export function getType(value: string, template: string | null = null): Type {
|
||||
let propertyImports: string[] = [];
|
||||
|
||||
// Remove definitions prefix and cleanup string.
|
||||
const valueTrimmed = stripNamespace(value || '');
|
||||
const valueTrimmed: string = stripNamespace(value || '');
|
||||
|
||||
// Check of we have an Array type or generic type, for instance: "Link[Model]".
|
||||
if (/\[.*\]$/g.test(valueTrimmed)) {
|
||||
// Find the first and second type
|
||||
const match = valueTrimmed.match(/(.*?)\[(.*)\]$/);
|
||||
if (match) {
|
||||
const matches: RegExpMatchArray | null = valueTrimmed.match(/(.*?)\[(.*)\]$/);
|
||||
if (matches) {
|
||||
// Both of the types can be complex types so parse each of them.
|
||||
const match1 = getType(match[1]);
|
||||
const match2 = getType(match[2]);
|
||||
const match1: Type = getType(matches[1]);
|
||||
const match2: Type = getType(matches[2]);
|
||||
|
||||
// If the first match is a generic array then construct a correct array type,
|
||||
// for example the type "Array[Model]" becomes "Model[]".
|
||||
@ -48,7 +47,7 @@ export function getType(value: string, template: string | null = null): Type {
|
||||
propertyImports.push(...match2.imports);
|
||||
}
|
||||
} else if (hasMappedType(valueTrimmed)) {
|
||||
const mapped = getMappedType(valueTrimmed);
|
||||
const mapped: string = getMappedType(valueTrimmed);
|
||||
propertyType = mapped;
|
||||
propertyBase = mapped;
|
||||
} else {
|
||||
|
||||
@ -3,7 +3,6 @@ import { Client } from '../../client/interfaces/Client';
|
||||
import { getServer } from './parser/getServer';
|
||||
import { getModels } from './parser/getModels';
|
||||
import { getServices } from './parser/getServices';
|
||||
import { getSchemas } from './parser/getSchemas';
|
||||
|
||||
/**
|
||||
* Parse the OpenAPI specification to a Client model that contains
|
||||
@ -15,7 +14,6 @@ export function parse(openApi: OpenApi): Client {
|
||||
version: openApi.info.version,
|
||||
server: getServer(openApi),
|
||||
models: getModels(openApi),
|
||||
schemas: getSchemas(openApi),
|
||||
services: getServices(openApi),
|
||||
};
|
||||
}
|
||||
|
||||
2
src/openApi/v3/interfaces/OpenApiSchema.d.ts
vendored
2
src/openApi/v3/interfaces/OpenApiSchema.d.ts
vendored
@ -23,7 +23,7 @@ export interface OpenApiSchema {
|
||||
maxProperties?: number;
|
||||
minProperties?: number;
|
||||
required?: string[];
|
||||
enum?: (string | number)[];
|
||||
enum?: string[];
|
||||
type?: string;
|
||||
allOf?: (OpenApiSchema & OpenApiReference)[];
|
||||
oneOf?: (OpenApiSchema & OpenApiReference)[];
|
||||
|
||||
@ -30,7 +30,7 @@ const MAPPINGS = new Map<string, string>([
|
||||
* @param type
|
||||
*/
|
||||
export function getMappedType(type: string): string {
|
||||
const mapped = MAPPINGS.get(type.toLowerCase());
|
||||
const mapped: string | undefined = MAPPINGS.get(type.toLowerCase());
|
||||
if (mapped) {
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@ -6,6 +6,6 @@ import { OpenApi } from '../interfaces/OpenApi';
|
||||
* @param openApi
|
||||
*/
|
||||
export function getModels(openApi: OpenApi): Map<string, Model> {
|
||||
const models = new Map<string, Model>();
|
||||
const models: Map<string, Model> = new Map<string, Model>();
|
||||
return models;
|
||||
}
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
import { Schema } from '../../../client/interfaces/Schema';
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
|
||||
/**
|
||||
* Parse and return the OpenAPI schemas.
|
||||
* @param openApi
|
||||
*/
|
||||
export function getSchemas(openApi: OpenApi): Map<string, Schema> {
|
||||
const schemas = new Map<string, Schema>();
|
||||
return schemas;
|
||||
}
|
||||
@ -4,6 +4,12 @@ describe('getServer', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(
|
||||
getServer({
|
||||
openapi: '3.0',
|
||||
info: {
|
||||
title: 'dummy',
|
||||
version: '1.0',
|
||||
},
|
||||
paths: {},
|
||||
servers: [
|
||||
{
|
||||
url: 'https://localhost:8080/api',
|
||||
@ -16,6 +22,12 @@ describe('getServer', () => {
|
||||
it('should produce correct result with variables', () => {
|
||||
expect(
|
||||
getServer({
|
||||
openapi: '3.0',
|
||||
info: {
|
||||
title: 'dummy',
|
||||
version: '1.0',
|
||||
},
|
||||
paths: {},
|
||||
servers: [
|
||||
{
|
||||
url: '{scheme}://localhost:{port}/api',
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { OpenApi } from '../interfaces/OpenApi';
|
||||
import { OpenApiServer } from '../interfaces/OpenApiServer';
|
||||
import { Dictionary } from '../../../utils/types';
|
||||
import { OpenApiServerVariable } from '../interfaces/OpenApiServerVariable';
|
||||
|
||||
type Props = Pick<OpenApi, 'servers'>;
|
||||
|
||||
export function getServer(openApi: Props): string {
|
||||
const server = openApi.servers && openApi.servers[0];
|
||||
const variables = (server && server.variables) || {};
|
||||
let url = (server && server.url) || '';
|
||||
Object.entries(variables).forEach(variable => {
|
||||
url = url.replace(`{${variable[0]}}`, variable[1].default);
|
||||
});
|
||||
export function getServer(openApi: OpenApi): string {
|
||||
const server: OpenApiServer | undefined = openApi.servers && openApi.servers[0];
|
||||
const variables: Dictionary<OpenApiServerVariable> = (server && server.variables) || {};
|
||||
let url: string = (server && server.url) || '';
|
||||
for (const variable in variables) {
|
||||
if (variables.hasOwnProperty(variable)) {
|
||||
url = url.replace(`{${variable}}`, variables[variable].default);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { getServiceClassName } from './getServiceClassName';
|
||||
|
||||
describe('getServiceClassName', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getServiceClassName('')).toEqual('');
|
||||
expect(getServiceClassName('FooBar')).toEqual('FooBarService');
|
||||
expect(getServiceClassName('Foo Bar')).toEqual('FooBarService');
|
||||
expect(getServiceClassName('foo bar')).toEqual('FooBarService');
|
||||
expect(getServiceClassName('FooBarService')).toEqual('FooBarService');
|
||||
expect(getServiceClassName('Foo Bar Service')).toEqual('FooBarService');
|
||||
expect(getServiceClassName('foo bar service')).toEqual('FooBarService');
|
||||
});
|
||||
});
|
||||
@ -1,14 +0,0 @@
|
||||
import camelCase from 'camelcase';
|
||||
|
||||
/**
|
||||
* Convert the input value to a correct service classname. This converts
|
||||
* the input string to PascalCase and appends the "Service" prefix if needed.
|
||||
* @param value
|
||||
*/
|
||||
export function getServiceClassName(value: string): string {
|
||||
const name = camelCase(value, { pascalCase: true });
|
||||
if (name && !name.endsWith('Service')) {
|
||||
return `${name}Service`;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { getServiceOperationName } from './getServiceOperationName';
|
||||
|
||||
describe('getServiceOperationName', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getServiceOperationName('')).toEqual('');
|
||||
expect(getServiceOperationName('FooBar')).toEqual('fooBar');
|
||||
expect(getServiceOperationName('Foo Bar')).toEqual('fooBar');
|
||||
expect(getServiceOperationName('foo bar')).toEqual('fooBar');
|
||||
});
|
||||
});
|
||||
@ -1,11 +0,0 @@
|
||||
import camelCase from 'camelcase';
|
||||
|
||||
/**
|
||||
* Convert the input value to a correct operation (method) classname. This converts
|
||||
* the input string to cascalCase, so the method name follows the most popular
|
||||
* Javascript and Typescript writing style.
|
||||
* @param value
|
||||
*/
|
||||
export function getServiceOperationName(value: string): string {
|
||||
return camelCase(value);
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { getServicePath } from './getServicePath';
|
||||
|
||||
describe('getServicePath', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getServicePath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}/${type}');
|
||||
expect(getServicePath('/api/v{api-version}/list/{id}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}');
|
||||
expect(getServicePath('/api/v1/list/{id}')).toEqual('/api/v1/list/${id}');
|
||||
expect(getServicePath('/api/v1/list')).toEqual('/api/v1/list');
|
||||
});
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
import { getServiceVersion } from './getServiceVersion';
|
||||
|
||||
describe('getServiceVersion', () => {
|
||||
it('should produce correct result', () => {
|
||||
expect(getServiceVersion('1.0')).toEqual('1.0');
|
||||
expect(getServiceVersion('v1.0')).toEqual('1.0');
|
||||
expect(getServiceVersion('V1.0')).toEqual('1.0');
|
||||
});
|
||||
});
|
||||
@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Convert the service version to 'normal' version.
|
||||
* This basically removes any "v" prefix from the version string.
|
||||
* @param version
|
||||
*/
|
||||
export function getServiceVersion(version = '1.0'): string {
|
||||
return version.replace(/^v/gi, '');
|
||||
}
|
||||
@ -6,6 +6,6 @@ import { OpenApi } from '../interfaces/OpenApi';
|
||||
* @param openApi
|
||||
*/
|
||||
export function getServices(openApi: OpenApi): Map<string, Service> {
|
||||
const services = new Map<string, Service>();
|
||||
const services: Map<string, Service> = new Map<string, Service>();
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -14,16 +14,16 @@ export function getType(value: string, template: string | null = null): Type {
|
||||
let propertyImports: string[] = [];
|
||||
|
||||
// Remove definitions prefix and cleanup string.
|
||||
const valueTrimmed = stripNamespace(value || '');
|
||||
const valueTrimmed: string = stripNamespace(value || '');
|
||||
|
||||
// Check of we have an Array type or generic type, for instance: "Link[Model]".
|
||||
if (/\[.*\]$/g.test(valueTrimmed)) {
|
||||
// Find the first and second type
|
||||
const match = valueTrimmed.match(/(.*?)\[(.*)\]$/);
|
||||
const match: RegExpMatchArray | null = valueTrimmed.match(/(.*?)\[(.*)\]$/);
|
||||
if (match) {
|
||||
// Both of the types can be complex types so parse each of them.
|
||||
const match1 = getType(match[1]);
|
||||
const match2 = getType(match[2]);
|
||||
const match1: Type = getType(match[1]);
|
||||
const match2: Type = getType(match[2]);
|
||||
|
||||
// If the first match is a generic array then construct a correct array type, for example:
|
||||
// The type "Array[Model]" becomes "Model[]".
|
||||
@ -48,7 +48,7 @@ export function getType(value: string, template: string | null = null): Type {
|
||||
propertyImports.push(...match2.imports);
|
||||
}
|
||||
} else if (hasMappedType(valueTrimmed)) {
|
||||
const mapped = getMappedType(valueTrimmed);
|
||||
const mapped: string = getMappedType(valueTrimmed);
|
||||
propertyType = mapped;
|
||||
propertyBase = mapped;
|
||||
} else {
|
||||
|
||||
51
src/templates/javascript/core/ApiError.js
Normal file
51
src/templates/javascript/core/ApiError.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
import { isSuccess } from "./isSuccess";
|
||||
|
||||
export class ApiError extends Error {
|
||||
|
||||
constructor(result, message) {
|
||||
super(message);
|
||||
|
||||
this.url = result.url;
|
||||
this.status = result.status;
|
||||
this.statusText = result.statusText;
|
||||
this.body = result.body;
|
||||
}
|
||||
}
|
||||
|
||||
(function (ApiError) {
|
||||
let Message;
|
||||
(function (Message) {
|
||||
Message.BAD_REQUEST = 'Bad Request';
|
||||
Message.UNAUTHORIZED = 'Unauthorized';
|
||||
Message.FORBIDDEN = 'Forbidden';
|
||||
Message.NOT_FOUND = 'Not Found';
|
||||
Message.INTERNAL_SERVER_ERROR = 'Internal Server Error';
|
||||
Message.BAD_GATEWAY = 'Bad Gateway';
|
||||
Message.SERVICE_UNAVAILABLE = 'Service Unavailable';
|
||||
Message.GENERIC_ERROR = 'Generic Error';
|
||||
})(Message = ApiError.Message || (ApiError.Message = {}));
|
||||
})(ApiError || (ApiError = {}));
|
||||
|
||||
/**
|
||||
* Catch common errors (based on status code).
|
||||
* @param result
|
||||
*/
|
||||
export function catchGenericError(result) {
|
||||
|
||||
switch (result.status) {
|
||||
case 400: throw new ApiError(result, ApiError.Message.BAD_REQUEST);
|
||||
case 401: throw new ApiError(result, ApiError.Message.UNAUTHORIZED);
|
||||
case 403: throw new ApiError(result, ApiError.Message.FORBIDDEN);
|
||||
case 404: throw new ApiError(result, ApiError.Message.NOT_FOUND);
|
||||
case 500: throw new ApiError(result, ApiError.Message.INTERNAL_SERVER_ERROR);
|
||||
case 502: throw new ApiError(result, ApiError.Message.BAD_GATEWAY);
|
||||
case 503: throw new ApiError(result, ApiError.Message.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
if (!isSuccess(result.status)) {
|
||||
throw new ApiError(result, ApiError.Message.GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
9
src/templates/javascript/core/OpenAPI.js
Normal file
9
src/templates/javascript/core/OpenAPI.js
Normal file
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
export let OpenAPI;
|
||||
(function (OpenAPI) {
|
||||
OpenAPI.BASE = '';
|
||||
OpenAPI.TOKEN = '';
|
||||
OpenAPI.VERSION = '{VERSION}';
|
||||
})(OpenAPI || (OpenAPI = {}));
|
||||
20
src/templates/javascript/core/getFormData.js
Normal file
20
src/templates/javascript/core/getFormData.js
Normal file
@ -0,0 +1,20 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Get FormData from object. This method is needed to upload
|
||||
* multipart form data to the REST API.
|
||||
* @param params Key value based object.
|
||||
*/
|
||||
export function getFormData(params) {
|
||||
const formData = new FormData();
|
||||
for (const key in params) {
|
||||
if (typeof params[key] !== 'undefined') {
|
||||
const value = params[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
29
src/templates/javascript/core/getQueryString.js
Normal file
29
src/templates/javascript/core/getQueryString.js
Normal file
@ -0,0 +1,29 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Get query string from query parameters object. This method also
|
||||
* supports multi-value items by creating a key for each item.
|
||||
* @param params Key value based object.
|
||||
*/
|
||||
export function getQueryString(params) {
|
||||
const qs = [];
|
||||
for (const key in params) {
|
||||
if (typeof params[key] !== 'undefined') {
|
||||
const value = params[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0, n = value.length; i < n; i++) {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value[i]))}`);
|
||||
}
|
||||
} else {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (qs.length > 0) {
|
||||
return `?${qs.join('&')}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
10
src/templates/javascript/core/isSuccess.js
Normal file
10
src/templates/javascript/core/isSuccess.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Check success response code.
|
||||
* @param status Status code
|
||||
*/
|
||||
export function isSuccess(status) {
|
||||
return (status >= 200 && status < 300);
|
||||
}
|
||||
13
src/templates/javascript/core/isValidRequiredParam.js
Normal file
13
src/templates/javascript/core/isValidRequiredParam.js
Normal file
@ -0,0 +1,13 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Check if a parameter is valid.
|
||||
* @param param The parameter value.
|
||||
* @param name The parameter name.
|
||||
*/
|
||||
export function isValidRequiredParam(param, name) {
|
||||
if (param === undefined || param === null) {
|
||||
throw new Error(`Required parameter '${name}' was undefined or null.`);
|
||||
}
|
||||
}
|
||||
74
src/templates/javascript/core/request.js
Normal file
74
src/templates/javascript/core/request.js
Normal file
@ -0,0 +1,74 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
import {getFormData} from './getFormData';
|
||||
import {getQueryString} from './getQueryString';
|
||||
import {OpenAPI} from './OpenAPI';
|
||||
import {requestUsingFetch} from './requestUsingFetch';
|
||||
|
||||
/**
|
||||
* Create the request.
|
||||
* @param options Request method options.
|
||||
* @returns Result object (see above)
|
||||
*/
|
||||
export async function request<T>(options) {
|
||||
|
||||
// Create the request URL
|
||||
let url = `${OpenAPI.BASE}${options.path}`;
|
||||
|
||||
// Create request headers
|
||||
const headers = new Headers({
|
||||
...options.headers,
|
||||
Accept: 'application/json',
|
||||
});
|
||||
|
||||
// Create request settings
|
||||
const request = {
|
||||
headers,
|
||||
method: options.method,
|
||||
credentials: 'same-origin',
|
||||
};
|
||||
|
||||
// If we have a bearer token then we set the authentication header.
|
||||
if (OpenAPI.TOKEN !== null && OpenAPI.TOKEN !== '') {
|
||||
headers.append('Authorization', `Bearer ${OpenAPI.TOKEN}`);
|
||||
}
|
||||
|
||||
// Add the query parameters (if defined).
|
||||
if (options.query) {
|
||||
url += getQueryString(options.query);
|
||||
}
|
||||
|
||||
// Append formData as body
|
||||
if (options.formData) {
|
||||
request.body = getFormData(options.formData);
|
||||
|
||||
} else if (options.body) {
|
||||
|
||||
// If this is blob data, then pass it directly to the body and set content type.
|
||||
// Otherwise we just convert request data to JSON string (needed for fetch api)
|
||||
if (options.body instanceof Blob) {
|
||||
request.body = options.body;
|
||||
if (options.body.type) {
|
||||
headers.append('Content-Type', options.body.type);
|
||||
}
|
||||
} else {
|
||||
request.body = JSON.stringify(options.body);
|
||||
headers.append('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return await requestUsingFetch(url, request);
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
url,
|
||||
ok: false,
|
||||
status: 0,
|
||||
statusText: '',
|
||||
body: error,
|
||||
};
|
||||
}
|
||||
}
|
||||
47
src/templates/javascript/core/requestUsingFetch.js
Normal file
47
src/templates/javascript/core/requestUsingFetch.js
Normal file
@ -0,0 +1,47 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Request content using the new Fetch API. This is the default API that is used and
|
||||
* is create for all JSON, XML and text objects. However it is limited to UTF-8.
|
||||
* This is a problem for some of the Docs content, since that requires UTF-16!
|
||||
* @param url The url to request.
|
||||
* @param request The request object, containing method, headers, body, etc.
|
||||
*/
|
||||
export async function requestUsingFetch<T>(url, request) {
|
||||
|
||||
// Fetch response using fetch API.
|
||||
const response = await fetch(url, request);
|
||||
|
||||
// Create result object.
|
||||
const result = {
|
||||
url,
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: null,
|
||||
};
|
||||
|
||||
// Try to parse the content for any response status code.
|
||||
// We check the "Content-Type" header to see if we need to parse the
|
||||
// content as json or as plain text.
|
||||
const contentType = response.headers.get('Content-Type');
|
||||
if (contentType) {
|
||||
switch (contentType.toLowerCase()) {
|
||||
|
||||
case 'application/json':
|
||||
case 'application/json; charset=utf-8':
|
||||
result.body = await response.json();
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'text/xml; charset=utf-8':
|
||||
case 'text/xml; charset=utf-16':
|
||||
result.body = await response.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
72
src/templates/javascript/core/requestUsingXHR.js
Normal file
72
src/templates/javascript/core/requestUsingXHR.js
Normal file
@ -0,0 +1,72 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Result } from './Result';
|
||||
import {isSuccess} from "./isSuccess";
|
||||
|
||||
/**
|
||||
* Request content using the new legacy XMLHttpRequest API. This method is usefull
|
||||
* when we want to request UTF-16 content, since it natively supports loading UTF-16.
|
||||
* We could do the same with the Fetch API, but then we will need to conver the
|
||||
* content using JavaScript... And that is very very slow.
|
||||
* @param url The url to request.
|
||||
* @param request The request object, containing method, headers, body, etc.
|
||||
*/
|
||||
export async function requestUsingXHR<T>(url, request) {
|
||||
return new Promise(resole => {
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
// Open the request, remember to do this before adding any headers,
|
||||
// because the request needs to be initialized!
|
||||
xhr.open(request.method, url, true);
|
||||
|
||||
// Add the headers (required when dealing with JSON)
|
||||
const headers = request.headers as Headers;
|
||||
headers.forEach((value, key) => {
|
||||
xhr.setRequestHeader(key, value);
|
||||
});
|
||||
|
||||
// Register the readystate handler, this will fire when the request is done.
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
|
||||
// Create result object.
|
||||
const result = {
|
||||
url,
|
||||
ok: isSuccess(xhr.status),
|
||||
status: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
body: null,
|
||||
};
|
||||
|
||||
// Try to parse the content for any response status code.
|
||||
// We check the "Content-Type" header to see if we need to parse the
|
||||
// content as json or as plain text.
|
||||
const contentType = xhr.getResponseHeader('Content-Type');
|
||||
if (contentType) {
|
||||
switch (contentType.toLowerCase()) {
|
||||
|
||||
case 'application/json':
|
||||
case 'application/json; charset=utf-8':
|
||||
result.body = JSON.parse(xhr.responseText);
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'text/xml; charset=utf-8':
|
||||
case 'text/xml; charset=utf-16':
|
||||
result.body = xhr.responseText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Done!
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
// Start the request!
|
||||
xhr.send(request.body);
|
||||
});
|
||||
}
|
||||
@ -1,20 +1,14 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
|
||||
const server = '{{{server}}}';
|
||||
const version = '{{{version}}}';
|
||||
export { ApiError } from './core/ApiError';
|
||||
export { OpenAPI } from './core/OpenAPI';
|
||||
{{#if models}}
|
||||
|
||||
{{#each models}}
|
||||
export { {{{basename}}} } from './models/{{{basename}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if schemas}}
|
||||
|
||||
{{#each schemas}}
|
||||
export { {{{basename}}} } from './schemas/{{{basename}}}';
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{#if services}}
|
||||
|
||||
{{#each services}}
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* eslint-disable */
|
||||
@ -2,6 +2,11 @@
|
||||
/* eslint-disable */
|
||||
import * as yup from 'yup';
|
||||
|
||||
import { ApiError, catchGenericError } from '../core/ApiError';
|
||||
import { request } from '../core/request';
|
||||
import { isValidRequiredParam } from '../core/isValidRequiredParam';
|
||||
import { OpenAPI } from '../core/OpenAPI';
|
||||
|
||||
export class {{{name}}} {
|
||||
|
||||
{{#each operations}}
|
||||
@ -50,8 +55,8 @@ export class {{{name}}} {
|
||||
},{{/if}}{{#if parametersBody}}
|
||||
body: {{{parametersBody.name}}},{{/if}}
|
||||
});
|
||||
|
||||
{{#if errors}}
|
||||
|
||||
if (!result.ok) {
|
||||
switch (result.status) {
|
||||
{{#each errors}}
|
||||
|
||||
62
src/templates/typescript/core/ApiError.ts
Normal file
62
src/templates/typescript/core/ApiError.ts
Normal file
@ -0,0 +1,62 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { isSuccess } from './isSuccess';
|
||||
import { Result } from './Result';
|
||||
|
||||
export class ApiError extends Error {
|
||||
public readonly url: string;
|
||||
public readonly status: number;
|
||||
public readonly statusText: string;
|
||||
public readonly body: any;
|
||||
|
||||
constructor(result: Readonly<Result>, message: string) {
|
||||
super(message);
|
||||
|
||||
this.url = result.url;
|
||||
this.status = result.status;
|
||||
this.statusText = result.statusText;
|
||||
this.body = result.body;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ApiError {
|
||||
export enum Message {
|
||||
BAD_REQUEST = 'Bad Request',
|
||||
UNAUTHORIZED = 'Unauthorized',
|
||||
FORBIDDEN = 'Forbidden',
|
||||
NOT_FOUND = 'Not Found',
|
||||
INTERNAL_SERVER_ERROR = 'Internal Server Error',
|
||||
BAD_GATEWAY = 'Bad Gateway',
|
||||
SERVICE_UNAVAILABLE = 'Service Unavailable',
|
||||
GENERIC_ERROR = 'Generic Error',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch common errors (based on status code).
|
||||
* @param result
|
||||
*/
|
||||
export function catchGenericError(result: Result): void {
|
||||
switch (result.status) {
|
||||
case 400:
|
||||
throw new ApiError(result, ApiError.Message.BAD_REQUEST);
|
||||
case 401:
|
||||
throw new ApiError(result, ApiError.Message.UNAUTHORIZED);
|
||||
case 403:
|
||||
throw new ApiError(result, ApiError.Message.FORBIDDEN);
|
||||
case 404:
|
||||
throw new ApiError(result, ApiError.Message.NOT_FOUND);
|
||||
case 500:
|
||||
throw new ApiError(result, ApiError.Message.INTERNAL_SERVER_ERROR);
|
||||
case 502:
|
||||
throw new ApiError(result, ApiError.Message.BAD_GATEWAY);
|
||||
case 503:
|
||||
throw new ApiError(result, ApiError.Message.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
if (!isSuccess(result.status)) {
|
||||
throw new ApiError(result, ApiError.Message.GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
3
src/templates/typescript/core/Dictionary.ts
Normal file
3
src/templates/typescript/core/Dictionary.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface Dictionary<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
9
src/templates/typescript/core/OpenAPI.ts
Normal file
9
src/templates/typescript/core/OpenAPI.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export namespace OpenAPI {
|
||||
export let BASE: string = '';
|
||||
export let TOKEN: string = '';
|
||||
export let VERSION: string = '{VERSION}';
|
||||
}
|
||||
12
src/templates/typescript/core/RequestOptions.ts
Normal file
12
src/templates/typescript/core/RequestOptions.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export interface RequestOptions {
|
||||
method: string;
|
||||
path: string;
|
||||
headers?: { [key: string]: any };
|
||||
query?: { [key: string]: any };
|
||||
formData?: { [key: string]: any };
|
||||
body?: any;
|
||||
}
|
||||
11
src/templates/typescript/core/Result.ts
Normal file
11
src/templates/typescript/core/Result.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export interface Result<T = any> {
|
||||
url: string;
|
||||
ok: boolean;
|
||||
status: number;
|
||||
statusText: string;
|
||||
body: T;
|
||||
}
|
||||
21
src/templates/typescript/core/getFormData.ts
Normal file
21
src/templates/typescript/core/getFormData.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Get FormData from object. This method is needed to upload
|
||||
* multipart form data to the REST API.
|
||||
* @param params Key value based object.
|
||||
*/
|
||||
export function getFormData(params: { [key: string]: any }): FormData {
|
||||
const formData: FormData = new FormData();
|
||||
for (const key in params) {
|
||||
if (typeof params[key] !== 'undefined') {
|
||||
const value: any = params[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
30
src/templates/typescript/core/getQueryString.ts
Normal file
30
src/templates/typescript/core/getQueryString.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Get query string from query parameters object. This method also
|
||||
* supports multi-value items by creating a key for each item.
|
||||
* @param params Key value based object.
|
||||
*/
|
||||
export function getQueryString(params: { [key: string]: any }): string {
|
||||
const qs: string[] = [];
|
||||
for (const key in params) {
|
||||
if (typeof params[key] !== 'undefined') {
|
||||
const value: any = params[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0, n = value.length; i < n; i++) {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value[i]))}`);
|
||||
}
|
||||
} else {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (qs.length > 0) {
|
||||
return `?${qs.join('&')}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
11
src/templates/typescript/core/isSuccess.ts
Normal file
11
src/templates/typescript/core/isSuccess.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Check success response code.
|
||||
* @param status Status code
|
||||
*/
|
||||
export function isSuccess(status: number): boolean {
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
14
src/templates/typescript/core/isValidRequiredParam.ts
Normal file
14
src/templates/typescript/core/isValidRequiredParam.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Check if a parameter is valid.
|
||||
* @param param The parameter value.
|
||||
* @param name The parameter name.
|
||||
*/
|
||||
export function isValidRequiredParam(param: any, name: string): void {
|
||||
if (param === undefined || param === null) {
|
||||
throw new Error(`Required parameter '${name}' was undefined or null.`);
|
||||
}
|
||||
}
|
||||
72
src/templates/typescript/core/request.ts
Normal file
72
src/templates/typescript/core/request.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { getFormData } from './getFormData';
|
||||
import { getQueryString } from './getQueryString';
|
||||
import { OpenAPI } from './OpenAPI';
|
||||
import { RequestOptions } from './RequestOptions';
|
||||
import { requestUsingFetch } from './requestUsingFetch';
|
||||
import { Result } from './Result';
|
||||
|
||||
/**
|
||||
* Create the request.
|
||||
* @param options Request method options.
|
||||
* @returns Result object (see above)
|
||||
*/
|
||||
export async function request<T>(options: Readonly<RequestOptions>): Promise<Result<T>> {
|
||||
// Create the request URL
|
||||
let url: string = `${OpenAPI.BASE}${options.path}`;
|
||||
|
||||
// Create request headers
|
||||
const headers: Headers = new Headers({
|
||||
...options.headers,
|
||||
Accept: 'application/json',
|
||||
});
|
||||
|
||||
// Create request settings
|
||||
const request: RequestInit = {
|
||||
headers,
|
||||
method: options.method,
|
||||
credentials: 'same-origin',
|
||||
};
|
||||
|
||||
// If we have a bearer token then we set the authentication header.
|
||||
if (OpenAPI.TOKEN !== null && OpenAPI.TOKEN !== '') {
|
||||
headers.append('Authorization', `Bearer ${OpenAPI.TOKEN}`);
|
||||
}
|
||||
|
||||
// Add the query parameters (if defined).
|
||||
if (options.query) {
|
||||
url += getQueryString(options.query);
|
||||
}
|
||||
|
||||
// Append formData as body
|
||||
if (options.formData) {
|
||||
request.body = getFormData(options.formData);
|
||||
} else if (options.body) {
|
||||
// If this is blob data, then pass it directly to the body and set content type.
|
||||
// Otherwise we just convert request data to JSON string (needed for fetch api)
|
||||
if (options.body instanceof Blob) {
|
||||
request.body = options.body;
|
||||
if (options.body.type) {
|
||||
headers.append('Content-Type', options.body.type);
|
||||
}
|
||||
} else {
|
||||
request.body = JSON.stringify(options.body);
|
||||
headers.append('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return await requestUsingFetch<T>(url, request);
|
||||
} catch (error) {
|
||||
return {
|
||||
url,
|
||||
ok: false,
|
||||
status: 0,
|
||||
statusText: '',
|
||||
body: error,
|
||||
};
|
||||
}
|
||||
}
|
||||
48
src/templates/typescript/core/requestUsingFetch.ts
Normal file
48
src/templates/typescript/core/requestUsingFetch.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Result } from './Result';
|
||||
|
||||
/**
|
||||
* Request content using the new Fetch API. This is the default API that is used and
|
||||
* is create for all JSON, XML and text objects. However it is limited to UTF-8.
|
||||
* This is a problem for some of the Docs content, since that requires UTF-16!
|
||||
* @param url The url to request.
|
||||
* @param request The request object, containing method, headers, body, etc.
|
||||
*/
|
||||
export async function requestUsingFetch<T>(url: string, request: Readonly<RequestInit>): Promise<Result<T>> {
|
||||
// Fetch response using fetch API.
|
||||
const response: Response = await fetch(url, request);
|
||||
|
||||
// Create result object.
|
||||
const result: Result = {
|
||||
url,
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: null,
|
||||
};
|
||||
|
||||
// Try to parse the content for any response status code.
|
||||
// We check the "Content-Type" header to see if we need to parse the
|
||||
// content as json or as plain text.
|
||||
const contentType: string | null = response.headers.get('Content-Type');
|
||||
if (contentType) {
|
||||
switch (contentType.toLowerCase()) {
|
||||
case 'application/json':
|
||||
case 'application/json; charset=utf-8':
|
||||
result.body = await response.json();
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'text/xml; charset=utf-8':
|
||||
case 'text/xml; charset=utf-16':
|
||||
result.body = await response.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
70
src/templates/typescript/core/requestUsingXHR.ts
Normal file
70
src/templates/typescript/core/requestUsingXHR.ts
Normal file
@ -0,0 +1,70 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { Result } from './Result';
|
||||
import { isSuccess } from './isSuccess';
|
||||
|
||||
/**
|
||||
* Request content using the new legacy XMLHttpRequest API. This method is usefull
|
||||
* when we want to request UTF-16 content, since it natively supports loading UTF-16.
|
||||
* We could do the same with the Fetch API, but then we will need to conver the
|
||||
* content using JavaScript... And that is very very slow.
|
||||
* @param url The url to request.
|
||||
* @param request The request object, containing method, headers, body, etc.
|
||||
*/
|
||||
export async function requestUsingXHR<T>(url: string, request: Readonly<RequestInit>): Promise<Result<T>> {
|
||||
return new Promise(resolve => {
|
||||
const xhr: XMLHttpRequest = new XMLHttpRequest();
|
||||
|
||||
// Open the request, remember to do this before adding any headers,
|
||||
// because the request needs to be initialized!
|
||||
xhr.open(request.method!, url, true);
|
||||
|
||||
// Add the headers (required when dealing with JSON)
|
||||
const headers: Headers = request.headers as Headers;
|
||||
headers.forEach((value: string, key: string): void => {
|
||||
xhr.setRequestHeader(key, value);
|
||||
});
|
||||
|
||||
// Register the readystate handler, this will fire when the request is done.
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
// Create result object.
|
||||
const result: Result = {
|
||||
url,
|
||||
ok: isSuccess(xhr.status),
|
||||
status: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
body: null,
|
||||
};
|
||||
|
||||
// Try to parse the content for any response status code.
|
||||
// We check the "Content-Type" header to see if we need to parse the
|
||||
// content as json or as plain text.
|
||||
const contentType: string | null = xhr.getResponseHeader('Content-Type');
|
||||
if (contentType) {
|
||||
switch (contentType.toLowerCase()) {
|
||||
case 'application/json':
|
||||
case 'application/json; charset=utf-8':
|
||||
result.body = JSON.parse(xhr.responseText);
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'text/xml; charset=utf-8':
|
||||
case 'text/xml; charset=utf-16':
|
||||
result.body = xhr.responseText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Done!
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
// Start the request!
|
||||
xhr.send(request.body);
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user