mirror of
https://github.com/ferdikoomen/openapi-typescript-codegen.git
synced 2025-12-08 20:16:21 +00:00
- Woking on babel support
- Working on test server - Embedding all templates
This commit is contained in:
parent
f5ed9696dc
commit
fd988e834c
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,4 +11,5 @@ junit.xml
|
||||
dist
|
||||
archive
|
||||
coverage
|
||||
samples/dist
|
||||
test/result
|
||||
|
||||
@ -1 +0,0 @@
|
||||
src/templates
|
||||
@ -12,7 +12,7 @@ program
|
||||
.version(pkg.version)
|
||||
.requiredOption('-i, --input <value>', 'OpenAPI specification, can be a path, url or string content (required)')
|
||||
.requiredOption('-o, --output <value>', 'Output directory (required)')
|
||||
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr]', 'fetch')
|
||||
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node]', 'fetch')
|
||||
.option('--useOptions', 'Use options instead of arguments')
|
||||
.option('--useUnionTypes', 'Use union types instead of enums')
|
||||
.option('--exportCore <value>', 'Write core files to disk', true)
|
||||
|
||||
37
package.json
37
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openapi-typescript-codegen",
|
||||
"version": "0.4.11",
|
||||
"version": "0.5.0",
|
||||
"description": "NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.",
|
||||
"author": "Ferdi Koomen",
|
||||
"homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen",
|
||||
@ -43,19 +43,20 @@
|
||||
"src/templates/**/*.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf ./dist ./test/result ./coverage ./samples/examples ./node_modules/.cache",
|
||||
"clean": "rimraf ./dist ./test/generator/dist ./test/server/dist ./coverage ./samples/dist ./node_modules/.cache",
|
||||
"build": "rollup --config --environment NODE_ENV:development",
|
||||
"build:watch": "rollup --config --environment NODE_ENV:development --watch",
|
||||
"release": "rollup --config --environment NODE_ENV:production",
|
||||
"run": "node ./test/index.js",
|
||||
"start": "nest start --path ./test/server/tsconfig.json",
|
||||
"start:watch": "nest start --path ./test/server/tsconfig.json --watch",
|
||||
"test": "jest",
|
||||
"test:update": "jest --updateSnapshot",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"eslint": "eslint \"./src/**/*.ts\" \"./bin/index.js\"",
|
||||
"eslint:fix": "eslint \"./src/**/*.ts\" \"./bin/index.js\" --fix",
|
||||
"prettier": "prettier \"./src/**/*.ts\" \"./bin/index.js\" --check",
|
||||
"prettier:fix": "prettier \"./src/**/*.ts\" \"./bin/index.js\" --write",
|
||||
"eslint": "eslint \"./src/**/*.{js,ts}\" \"./test/**/*.{js,ts}\" \"./bin/index.js\"",
|
||||
"eslint:fix": "eslint \"./src/**/*.{js,ts}\" \"./test/**/*.{js,ts}\" \"./bin/index.js\" --fix",
|
||||
"prettier": "prettier \"./src/**/*.{js,ts}\" \"./test/**/*.{js,ts}\" \"./bin/index.js\" --check",
|
||||
"prettier:fix": "prettier \"./src/**/*.{js,ts}\" \"./test/**/*.{js,ts}\" \"./bin/index.js\" --write",
|
||||
"prepublish": "yarn run clean && yarn run release",
|
||||
"codecov": "codecov --token=66c30c23-8954-4892-bef9-fbaed0a2e42b"
|
||||
},
|
||||
@ -72,15 +73,25 @@
|
||||
"@babel/core": "7.11.6",
|
||||
"@babel/preset-env": "7.11.5",
|
||||
"@babel/preset-typescript": "7.10.4",
|
||||
"@rollup/plugin-commonjs": "15.0.0",
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/schematics": "7.1.2",
|
||||
"@nestjs/swagger": "4.6.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@rollup/plugin-commonjs": "15.1.0",
|
||||
"@rollup/plugin-node-resolve": "9.0.0",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/jest": "26.0.14",
|
||||
"@types/js-yaml": "3.12.5",
|
||||
"@types/mkdirp": "1.0.1",
|
||||
"@types/node": "14.11.1",
|
||||
"@types/node": "14.11.2",
|
||||
"@types/rimraf": "3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.1.1",
|
||||
"@typescript-eslint/parser": "4.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "4.2.0",
|
||||
"@typescript-eslint/parser": "4.2.0",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"codecov": "3.7.2",
|
||||
"eslint": "7.9.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
@ -90,9 +101,11 @@
|
||||
"jest": "26.4.2",
|
||||
"jest-cli": "26.4.2",
|
||||
"prettier": "2.1.2",
|
||||
"rollup": "2.27.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rollup": "2.28.1",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"rollup-plugin-typescript2": "0.27.2",
|
||||
"swagger-ui-express": "4.1.4",
|
||||
"typescript": "4.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
5
samples/.gitignore
vendored
5
samples/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
examples
|
||||
node_modules
|
||||
swagger-codegen-cli-v2.jar
|
||||
swagger-codegen-cli-v3.jar
|
||||
yarn.lock
|
||||
@ -1,22 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -rf examples
|
||||
rm swagger-codegen-cli-v2.jar
|
||||
rm swagger-codegen-cli-v3.jar
|
||||
|
||||
curl https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.4.14/swagger-codegen-cli-2.4.14.jar -o swagger-codegen-cli-v2.jar
|
||||
curl https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.20/swagger-codegen-cli-3.0.20.jar -o swagger-codegen-cli-v3.jar
|
||||
curl https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.4.15/swagger-codegen-cli-2.4.15.jar -o swagger-codegen-cli-v2.jar
|
||||
curl https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.21/swagger-codegen-cli-3.0.21.jar -o swagger-codegen-cli-v3.jar
|
||||
|
||||
echo v2/typescript-aurelia && time java -jar ./swagger-codegen-cli-v2.jar generate -i v2/spec.json -l typescript-aurelia -o examples/v2/typescript-aurelia/
|
||||
echo v2/typescript-angular && time java -jar ./swagger-codegen-cli-v2.jar generate -i v2/spec.json -l typescript-angular -o examples/v2/typescript-angular/
|
||||
echo v2/typescript-inversify && time java -jar ./swagger-codegen-cli-v2.jar generate -i v2/spec.json -l typescript-inversify -o examples/v2/typescript-inversify/
|
||||
echo v2/typescript-fetch && time java -jar ./swagger-codegen-cli-v2.jar generate -i v2/spec.json -l typescript-fetch -o examples/v2/typescript-fetch/
|
||||
echo v2/typescript-jquery && time java -jar ./swagger-codegen-cli-v2.jar generate -i v2/spec.json -l typescript-jquery -o examples/v2/typescript-jquery/
|
||||
echo v2/typescript-node && time java -jar ./swagger-codegen-cli-v2.jar generate -i v2/spec.json -l typescript-node -o examples/v2/typescript-node/
|
||||
java -jar ./swagger-codegen-cli-v2.jar generate -i spec/v2.json -l typescript-aurelia -o dist/v2/typescript-aurelia/
|
||||
java -jar ./swagger-codegen-cli-v2.jar generate -i spec/v2.json -l typescript-angular -o dist/v2/typescript-angular/
|
||||
java -jar ./swagger-codegen-cli-v2.jar generate -i spec/v2.json -l typescript-inversify -o dist/v2/typescript-inversify/
|
||||
java -jar ./swagger-codegen-cli-v2.jar generate -i spec/v2.json -l typescript-fetch -o dist/v2/typescript-fetch/
|
||||
java -jar ./swagger-codegen-cli-v2.jar generate -i spec/v2.json -l typescript-jquery -o dist/v2/typescript-jquery/
|
||||
java -jar ./swagger-codegen-cli-v2.jar generate -i spec/v2.json -l typescript-node -o dist/v2/typescript-node/
|
||||
|
||||
echo v3/typescript-angular && time java -jar ./swagger-codegen-cli-v3.jar generate -i v3/spec.json -l typescript-angular -o examples/v3/typescript-angular/
|
||||
echo v3/typescript-fetch && time java -jar ./swagger-codegen-cli-v3.jar generate -i v3/spec.json -l typescript-fetch -o examples/v3/typescript-fetch/
|
||||
java -jar ./swagger-codegen-cli-v3.jar generate -i spec/v3.json -l typescript-angular -o dist/v3/typescript-angular/
|
||||
java -jar ./swagger-codegen-cli-v3.jar generate -i spec/v3.json -l typescript-fetch -o dist/v3/typescript-fetch/
|
||||
|
||||
echo v2/openapi-typescript-codegen && time node ../bin/index.js --input v2/spec.json --output examples/v2/openapi-typescript-codegen/
|
||||
echo v3/openapi-typescript-codegen && time node ../bin/index.js --input v3/spec.json --output examples/v3/openapi-typescript-codegen/
|
||||
|
||||
yarn install
|
||||
yarn run build
|
||||
node ../bin/index.js --input spec/v2.json --output dist/v2/openapi-typescript-codegen/
|
||||
node ../bin/index.js --input spec/v3.json --output dist/v3/openapi-typescript-codegen/
|
||||
|
||||
@ -258,13 +258,13 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Generation time</th>
|
||||
<td data-type="openapi-typescript-codegen"><span class="badge">0.132s</span></td>
|
||||
<td data-type="aurelia"><span class="badge">0.715s</span></td>
|
||||
<td data-type="inversify"><span class="badge">0.788s</span></td>
|
||||
<td data-type="angular"><span class="badge">1.386s</span></td>
|
||||
<td data-type="fetch"><span class="badge">1.103s</span></td>
|
||||
<td data-type="jquery"><span class="badge">0.728s</span></td>
|
||||
<td data-type="node"><span class="badge">0.752s</span></td>
|
||||
<td data-type="openapi-typescript-codegen"><span class="badge">0.2s</span></td>
|
||||
<td data-type="aurelia"><span class="badge">0.7s</span></td>
|
||||
<td data-type="inversify"><span class="badge">0.7s</span></td>
|
||||
<td data-type="angular"><span class="badge">1.4s</span></td>
|
||||
<td data-type="fetch"><span class="badge">1.1s</span></td>
|
||||
<td data-type="jquery"><span class="badge">0.7s</span></td>
|
||||
<td data-type="node"><span class="badge">0.7s</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "compare",
|
||||
"version": "1.0.0",
|
||||
"description": "Package file to compare generated libraries.",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/common": "9.1.11",
|
||||
"@angular/core": "9.1.11",
|
||||
"@types/bluebird": "3.5.32",
|
||||
"@types/jquery": "3.3.38",
|
||||
"@types/node": "14.0.13",
|
||||
"@types/request": "2.48.5",
|
||||
"aurelia-framework": "1.3.1",
|
||||
"aurelia-http-client": "1.3.1",
|
||||
"bluebird": "3.7.2",
|
||||
"jquery": "3.5.1",
|
||||
"request": "2.88.2",
|
||||
"rxjs": "6.5.5",
|
||||
"rxjs-compat": "6.5.5",
|
||||
"typescript": "3.9.5"
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"module": "ES6",
|
||||
"moduleResolution": "Node",
|
||||
"lib": ["ES2017", "DOM"],
|
||||
"types": ["node"],
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"removeComments": true,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
|
||||
"include": [
|
||||
"./examples/v2/openapi-typescript-codegen/**/*.ts",
|
||||
"./examples/v2/typescript-angular/**/*.ts",
|
||||
"./examples/v2/typescript-aurelia/**/*.ts",
|
||||
"./examples/v2/typescript-fetch/**/*.ts",
|
||||
"./examples/v2/typescript-inversify/**/*.ts",
|
||||
"./examples/v2/typescript-jquery/**/*.ts",
|
||||
"./examples/v2/typescript-node/**/*.ts",
|
||||
"./examples/v3/openapi-typescript-codegen/**/*.ts",
|
||||
"./examples/v3/typescript-angular/**/*.ts",
|
||||
"./examples/v3/typescript-fetch/**/*.ts"
|
||||
],
|
||||
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,37 +1,31 @@
|
||||
import * as OpenAPI from '.';
|
||||
|
||||
describe('index', () => {
|
||||
it('parses v2 without issues', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
useOptions: true,
|
||||
write: false,
|
||||
});
|
||||
// await OpenAPI.generate({
|
||||
// input: './test/mock/v2/spec.json',
|
||||
// output: './test/result/v2/',
|
||||
// useOptions: true
|
||||
// });
|
||||
});
|
||||
|
||||
it('parses v3 without issues', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
useOptions: true,
|
||||
write: false,
|
||||
});
|
||||
// await OpenAPI.generate({
|
||||
// input: './test/mock/v3/spec.json',
|
||||
// output: './test/result/v3/',
|
||||
// useOptions: true
|
||||
// });
|
||||
});
|
||||
|
||||
it('downloads and parses v2 without issues', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: 'https://raw.githubusercontent.com/ferdikoomen/openapi-typescript-codegen/master/test/mock/v2/spec.json',
|
||||
output: './test/result/v2-downloaded/',
|
||||
write: false,
|
||||
});
|
||||
// await OpenAPI.generate({
|
||||
// input: 'https://raw.githubusercontent.com/ferdikoomen/openapi-typescript-codegen/master/test/mock/v2/spec.json',
|
||||
// output: './test/result/v2-downloaded/'
|
||||
// });
|
||||
});
|
||||
|
||||
it('downloads and parses v3 without issues', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: 'https://raw.githubusercontent.com/ferdikoomen/openapi-typescript-codegen/master/test/mock/v3/spec.json',
|
||||
output: './test/result/v3-downloaded/',
|
||||
write: false,
|
||||
});
|
||||
// await OpenAPI.generate({
|
||||
// input: 'https://raw.githubusercontent.com/ferdikoomen/openapi-typescript-codegen/master/test/mock/v3/spec.json',
|
||||
// output: './test/result/v3-downloaded/'
|
||||
// });
|
||||
});
|
||||
});
|
||||
|
||||
11
src/index.ts
11
src/index.ts
@ -10,6 +10,7 @@ import { writeClient } from './utils/writeClient';
|
||||
export enum HttpClient {
|
||||
FETCH = 'fetch',
|
||||
XHR = 'xhr',
|
||||
NODE = 'node',
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
@ -22,7 +23,6 @@ export interface Options {
|
||||
exportServices?: boolean;
|
||||
exportModels?: boolean;
|
||||
exportSchemas?: boolean;
|
||||
write?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,7 +50,6 @@ export async function generate({
|
||||
exportServices = true,
|
||||
exportModels = true,
|
||||
exportSchemas = false,
|
||||
write = true,
|
||||
}: Options): Promise<void> {
|
||||
// Load the specification, read the OpenAPI version and load the
|
||||
// handlebar templates for the given language
|
||||
@ -62,18 +61,14 @@ export async function generate({
|
||||
case OpenApiVersion.V2: {
|
||||
const client = parseV2(openApi);
|
||||
const clientFinal = postProcessClient(client);
|
||||
if (write) {
|
||||
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
|
||||
}
|
||||
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpenApiVersion.V3: {
|
||||
const client = parseV3(openApi);
|
||||
const clientFinal = postProcessClient(client);
|
||||
if (write) {
|
||||
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
|
||||
}
|
||||
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +105,6 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
|
||||
model.base = additionalProperties.base;
|
||||
model.template = additionalProperties.template;
|
||||
model.imports.push(...additionalProperties.imports);
|
||||
model.imports.push('Dictionary');
|
||||
return model;
|
||||
} else {
|
||||
const additionalProperties = getModel(openApi, definition.additionalProperties);
|
||||
@ -115,7 +114,6 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
|
||||
model.template = additionalProperties.template;
|
||||
model.link = additionalProperties;
|
||||
model.imports.push(...additionalProperties.imports);
|
||||
model.imports.push('Dictionary');
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +99,6 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame
|
||||
operationParameter.base = items.base;
|
||||
operationParameter.template = items.template;
|
||||
operationParameter.imports.push(...items.imports);
|
||||
operationParameter.imports.push('Dictionary');
|
||||
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
|
||||
return operationParameter;
|
||||
}
|
||||
|
||||
@ -97,7 +97,6 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
|
||||
model.base = additionalProperties.base;
|
||||
model.template = additionalProperties.template;
|
||||
model.imports.push(...additionalProperties.imports);
|
||||
model.imports.push('Dictionary');
|
||||
model.default = getModelDefault(definition, model);
|
||||
return model;
|
||||
} else {
|
||||
@ -108,7 +107,6 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
|
||||
model.template = additionalProperties.template;
|
||||
model.link = additionalProperties;
|
||||
model.imports.push(...additionalProperties.imports);
|
||||
model.imports.push('Dictionary');
|
||||
model.default = getModelDefault(definition, model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
compiler: [8, '>= 4.3.0'],
|
||||
useData: true,
|
||||
main: function(container, depth0, helpers, partials, data) {
|
||||
main: function () {
|
||||
return '';
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type Dictionary<T> = {
|
||||
[key: string]: T;
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{{~#if link~}}
|
||||
Dictionary<{{>type link}}>{{>isNullable}}
|
||||
Record<string, {{>type link}}>{{>isNullable}}
|
||||
{{~else~}}
|
||||
Dictionary<{{{base}}}>{{>isNullable}}
|
||||
Record<string, {{{base}}}>{{>isNullable}}
|
||||
{{~/if~}}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import * as fs from 'fs';
|
||||
import { copyFile as __copyFile, exists as __exists, readFile as __readFile, writeFile as __writeFile } from 'fs';
|
||||
import mkdirp from 'mkdirp';
|
||||
import rimraf from 'rimraf';
|
||||
import * as util from 'util';
|
||||
import { promisify } from 'util';
|
||||
|
||||
// Wrapped file system calls
|
||||
export const readFile = util.promisify(fs.readFile);
|
||||
export const writeFile = util.promisify(fs.writeFile);
|
||||
export const copyFile = util.promisify(fs.copyFile);
|
||||
export const exists = util.promisify(fs.exists);
|
||||
export const readFile = promisify(__readFile);
|
||||
export const writeFile = promisify(__writeFile);
|
||||
export const copyFile = promisify(__copyFile);
|
||||
export const exists = promisify(__exists);
|
||||
|
||||
// Re-export from mkdirp to make mocking easier
|
||||
export const mkdir = mkdirp;
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { flatMap } from './flatMap';
|
||||
import { unique } from './unique';
|
||||
|
||||
/**
|
||||
* Get the full list of models that are extended by the given model.
|
||||
* @param model
|
||||
* @param client
|
||||
*/
|
||||
export function getExtendedByList(model: Model, client: Client): Model[] {
|
||||
const extendedBy = client.models.filter(ref => {
|
||||
const names = model.isDefinition ? [model.name] : model.base.split(' | ');
|
||||
return names.find(name => {
|
||||
return ref.extends.includes(name);
|
||||
});
|
||||
});
|
||||
|
||||
if (extendedBy.length) {
|
||||
extendedBy.push(...flatMap(extendedBy, ref => getExtendedByList(ref, client)));
|
||||
}
|
||||
return extendedBy.filter(unique);
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { flatMap } from './flatMap';
|
||||
import { unique } from './unique';
|
||||
|
||||
/**
|
||||
* Get the full list of models that are extended from the given model.
|
||||
* @param model
|
||||
* @param client
|
||||
*/
|
||||
export function getExtendedFromList(model: Model, client: Client): Model[] {
|
||||
const extendedFrom = client.models.filter(ref => {
|
||||
const names = ref.isDefinition ? [ref.name] : ref.base.split(' | ');
|
||||
return names.find(name => {
|
||||
return model.extends.includes(name);
|
||||
});
|
||||
});
|
||||
|
||||
if (extendedFrom.length) {
|
||||
extendedFrom.push(...flatMap(extendedFrom, ref => getExtendedFromList(ref, client)));
|
||||
}
|
||||
return extendedFrom.filter(unique);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import * as yaml from 'js-yaml';
|
||||
import * as path from 'path';
|
||||
import { safeLoad } from 'js-yaml';
|
||||
import { extname } from 'path';
|
||||
|
||||
import { readSpec } from './readSpec';
|
||||
|
||||
@ -10,13 +10,13 @@ import { readSpec } from './readSpec';
|
||||
* @param input
|
||||
*/
|
||||
export async function getOpenApiSpec(input: string): Promise<any> {
|
||||
const extname = path.extname(input).toLowerCase();
|
||||
const extension = extname(input).toLowerCase();
|
||||
const content = await readSpec(input);
|
||||
switch (extname) {
|
||||
switch (extension) {
|
||||
case '.yml':
|
||||
case '.yaml':
|
||||
try {
|
||||
return yaml.safeLoad(content);
|
||||
return safeLoad(content);
|
||||
} catch (e) {
|
||||
throw new Error(`Could not parse OpenApi YAML: "${input}"`);
|
||||
}
|
||||
|
||||
@ -1,40 +1,62 @@
|
||||
import * as Handlebars from 'handlebars/runtime';
|
||||
|
||||
import $OpenAPI from '../templates/core/OpenAPI.hbs';
|
||||
import $exportModel from '../templates/exportModel.hbs';
|
||||
import $exportSchema from '../templates/exportSchema.hbs';
|
||||
import $exportService from '../templates/exportService.hbs';
|
||||
import $index from '../templates/index.hbs';
|
||||
import $exportEnum from '../templates/partials/exportEnum.hbs';
|
||||
import $exportInterface from '../templates/partials/exportInterface.hbs';
|
||||
import $exportType from '../templates/partials/exportType.hbs';
|
||||
import $extends from '../templates/partials/extends.hbs';
|
||||
import $isNullable from '../templates/partials/isNullable.hbs';
|
||||
import $isReadOnly from '../templates/partials/isReadOnly.hbs';
|
||||
import $isRequired from '../templates/partials/isRequired.hbs';
|
||||
import $parameters from '../templates/partials/parameters.hbs';
|
||||
import $result from '../templates/partials/result.hbs';
|
||||
import $schema from '../templates/partials/schema.hbs';
|
||||
import $schemaArray from '../templates/partials/schemaArray.hbs';
|
||||
import $schemaDictionary from '../templates/partials/schemaDictionary.hbs';
|
||||
import $schemaEnum from '../templates/partials/schemaEnum.hbs';
|
||||
import $schemaGeneric from '../templates/partials/schemaGeneric.hbs';
|
||||
import $schemaInterface from '../templates/partials/schemaInterface.hbs';
|
||||
import $type from '../templates/partials/type.hbs';
|
||||
import $typeArray from '../templates/partials/typeArray.hbs';
|
||||
import $typeDictionary from '../templates/partials/typeDictionary.hbs';
|
||||
import $typeEnum from '../templates/partials/typeEnum.hbs';
|
||||
import $typeGeneric from '../templates/partials/typeGeneric.hbs';
|
||||
import $typeInterface from '../templates/partials/typeInterface.hbs';
|
||||
import $typeReference from '../templates/partials/typeReference.hbs';
|
||||
import templateCoreApiError from '../templates/core/ApiError.hbs';
|
||||
import templateCoreGetFormData from '../templates/core/getFormData.hbs';
|
||||
import templateCoreGetQueryString from '../templates/core/getQueryString.hbs';
|
||||
import templateCoreIsSuccess from '../templates/core/isSuccess.hbs';
|
||||
import templateCoreSettings from '../templates/core/OpenAPI.hbs';
|
||||
import templateCoreRequest from '../templates/core/request.hbs';
|
||||
import templateCoreRequestOptions from '../templates/core/RequestOptions.hbs';
|
||||
import templateCoreRequestUsingFetch from '../templates/core/requestUsingFetch.hbs';
|
||||
import templateCoreRequestUsingXHR from '../templates/core/requestUsingXHR.hbs';
|
||||
import templateCoreResult from '../templates/core/Result.hbs';
|
||||
import templateExportModel from '../templates/exportModel.hbs';
|
||||
import templateExportSchema from '../templates/exportSchema.hbs';
|
||||
import templateExportService from '../templates/exportService.hbs';
|
||||
import templateIndex from '../templates/index.hbs';
|
||||
import partialExportEnum from '../templates/partials/exportEnum.hbs';
|
||||
import partialExportInterface from '../templates/partials/exportInterface.hbs';
|
||||
import partialExportType from '../templates/partials/exportType.hbs';
|
||||
import partialExtends from '../templates/partials/extends.hbs';
|
||||
import partialIsNullable from '../templates/partials/isNullable.hbs';
|
||||
import partialIsReadOnly from '../templates/partials/isReadOnly.hbs';
|
||||
import partialIsRequired from '../templates/partials/isRequired.hbs';
|
||||
import partialParameters from '../templates/partials/parameters.hbs';
|
||||
import partialResult from '../templates/partials/result.hbs';
|
||||
import partialSchema from '../templates/partials/schema.hbs';
|
||||
import partialSchemaArray from '../templates/partials/schemaArray.hbs';
|
||||
import partialSchemaDictionary from '../templates/partials/schemaDictionary.hbs';
|
||||
import partialSchemaEnum from '../templates/partials/schemaEnum.hbs';
|
||||
import partialSchemaGeneric from '../templates/partials/schemaGeneric.hbs';
|
||||
import partialSchemaInterface from '../templates/partials/schemaInterface.hbs';
|
||||
import partialType from '../templates/partials/type.hbs';
|
||||
import partialTypeArray from '../templates/partials/typeArray.hbs';
|
||||
import partialTypeDictionary from '../templates/partials/typeDictionary.hbs';
|
||||
import partialTypeEnum from '../templates/partials/typeEnum.hbs';
|
||||
import partialTypeGeneric from '../templates/partials/typeGeneric.hbs';
|
||||
import partialTypeInterface from '../templates/partials/typeInterface.hbs';
|
||||
import partialTypeReference from '../templates/partials/typeReference.hbs';
|
||||
import { registerHandlebarHelpers } from './registerHandlebarHelpers';
|
||||
|
||||
export interface Templates {
|
||||
index: Handlebars.TemplateDelegate;
|
||||
model: Handlebars.TemplateDelegate;
|
||||
schema: Handlebars.TemplateDelegate;
|
||||
service: Handlebars.TemplateDelegate;
|
||||
settings: Handlebars.TemplateDelegate;
|
||||
exports: {
|
||||
model: Handlebars.TemplateDelegate;
|
||||
schema: Handlebars.TemplateDelegate;
|
||||
service: Handlebars.TemplateDelegate;
|
||||
};
|
||||
core: {
|
||||
settings: Handlebars.TemplateDelegate;
|
||||
apiError: Handlebars.TemplateDelegate;
|
||||
getFormData: Handlebars.TemplateDelegate;
|
||||
getQueryString: Handlebars.TemplateDelegate;
|
||||
isSuccess: Handlebars.TemplateDelegate;
|
||||
request: Handlebars.TemplateDelegate;
|
||||
requestOptions: Handlebars.TemplateDelegate;
|
||||
requestUsingFetch: Handlebars.TemplateDelegate;
|
||||
requestUsingXHR: Handlebars.TemplateDelegate;
|
||||
result: Handlebars.TemplateDelegate;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,35 +67,48 @@ export function registerHandlebarTemplates(): Templates {
|
||||
registerHandlebarHelpers();
|
||||
|
||||
const templates: Templates = {
|
||||
index: Handlebars.template($index),
|
||||
model: Handlebars.template($exportModel),
|
||||
schema: Handlebars.template($exportSchema),
|
||||
service: Handlebars.template($exportService),
|
||||
settings: Handlebars.template($OpenAPI),
|
||||
index: Handlebars.template(templateIndex),
|
||||
exports: {
|
||||
model: Handlebars.template(templateExportModel),
|
||||
schema: Handlebars.template(templateExportSchema),
|
||||
service: Handlebars.template(templateExportService),
|
||||
},
|
||||
core: {
|
||||
settings: Handlebars.template(templateCoreSettings),
|
||||
apiError: Handlebars.template(templateCoreApiError),
|
||||
getFormData: Handlebars.template(templateCoreGetFormData),
|
||||
getQueryString: Handlebars.template(templateCoreGetQueryString),
|
||||
isSuccess: Handlebars.template(templateCoreIsSuccess),
|
||||
request: Handlebars.template(templateCoreRequest),
|
||||
requestOptions: Handlebars.template(templateCoreRequestOptions),
|
||||
requestUsingFetch: Handlebars.template(templateCoreRequestUsingFetch),
|
||||
requestUsingXHR: Handlebars.template(templateCoreRequestUsingXHR),
|
||||
result: Handlebars.template(templateCoreResult),
|
||||
},
|
||||
};
|
||||
|
||||
Handlebars.registerPartial('exportEnum', Handlebars.template($exportEnum));
|
||||
Handlebars.registerPartial('exportInterface', Handlebars.template($exportInterface));
|
||||
Handlebars.registerPartial('exportType', Handlebars.template($exportType));
|
||||
Handlebars.registerPartial('extends', Handlebars.template($extends));
|
||||
Handlebars.registerPartial('isNullable', Handlebars.template($isNullable));
|
||||
Handlebars.registerPartial('isReadOnly', Handlebars.template($isReadOnly));
|
||||
Handlebars.registerPartial('isRequired', Handlebars.template($isRequired));
|
||||
Handlebars.registerPartial('parameters', Handlebars.template($parameters));
|
||||
Handlebars.registerPartial('result', Handlebars.template($result));
|
||||
Handlebars.registerPartial('schema', Handlebars.template($schema));
|
||||
Handlebars.registerPartial('schemaArray', Handlebars.template($schemaArray));
|
||||
Handlebars.registerPartial('schemaDictionary', Handlebars.template($schemaDictionary));
|
||||
Handlebars.registerPartial('schemaEnum', Handlebars.template($schemaEnum));
|
||||
Handlebars.registerPartial('schemaGeneric', Handlebars.template($schemaGeneric));
|
||||
Handlebars.registerPartial('schemaInterface', Handlebars.template($schemaInterface));
|
||||
Handlebars.registerPartial('type', Handlebars.template($type));
|
||||
Handlebars.registerPartial('typeArray', Handlebars.template($typeArray));
|
||||
Handlebars.registerPartial('typeDictionary', Handlebars.template($typeDictionary));
|
||||
Handlebars.registerPartial('typeEnum', Handlebars.template($typeEnum));
|
||||
Handlebars.registerPartial('typeGeneric', Handlebars.template($typeGeneric));
|
||||
Handlebars.registerPartial('typeInterface', Handlebars.template($typeInterface));
|
||||
Handlebars.registerPartial('typeReference', Handlebars.template($typeReference));
|
||||
Handlebars.registerPartial('exportEnum', Handlebars.template(partialExportEnum));
|
||||
Handlebars.registerPartial('exportInterface', Handlebars.template(partialExportInterface));
|
||||
Handlebars.registerPartial('exportType', Handlebars.template(partialExportType));
|
||||
Handlebars.registerPartial('extends', Handlebars.template(partialExtends));
|
||||
Handlebars.registerPartial('isNullable', Handlebars.template(partialIsNullable));
|
||||
Handlebars.registerPartial('isReadOnly', Handlebars.template(partialIsReadOnly));
|
||||
Handlebars.registerPartial('isRequired', Handlebars.template(partialIsRequired));
|
||||
Handlebars.registerPartial('parameters', Handlebars.template(partialParameters));
|
||||
Handlebars.registerPartial('result', Handlebars.template(partialResult));
|
||||
Handlebars.registerPartial('schema', Handlebars.template(partialSchema));
|
||||
Handlebars.registerPartial('schemaArray', Handlebars.template(partialSchemaArray));
|
||||
Handlebars.registerPartial('schemaDictionary', Handlebars.template(partialSchemaDictionary));
|
||||
Handlebars.registerPartial('schemaEnum', Handlebars.template(partialSchemaEnum));
|
||||
Handlebars.registerPartial('schemaGeneric', Handlebars.template(partialSchemaGeneric));
|
||||
Handlebars.registerPartial('schemaInterface', Handlebars.template(partialSchemaInterface));
|
||||
Handlebars.registerPartial('type', Handlebars.template(partialType));
|
||||
Handlebars.registerPartial('typeArray', Handlebars.template(partialTypeArray));
|
||||
Handlebars.registerPartial('typeDictionary', Handlebars.template(partialTypeDictionary));
|
||||
Handlebars.registerPartial('typeEnum', Handlebars.template(partialTypeEnum));
|
||||
Handlebars.registerPartial('typeGeneric', Handlebars.template(partialTypeGeneric));
|
||||
Handlebars.registerPartial('typeInterface', Handlebars.template(partialTypeInterface));
|
||||
Handlebars.registerPartial('typeReference', Handlebars.template(partialTypeReference));
|
||||
|
||||
return templates;
|
||||
}
|
||||
|
||||
@ -16,14 +16,27 @@ describe('writeClient', () => {
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
index: () => 'index',
|
||||
exports: {
|
||||
model: () => 'model',
|
||||
schema: () => 'schema',
|
||||
service: () => 'service',
|
||||
},
|
||||
core: {
|
||||
settings: () => 'settings',
|
||||
apiError: () => 'apiError',
|
||||
getFormData: () => 'getFormData',
|
||||
getQueryString: () => 'getQueryString',
|
||||
isSuccess: () => 'isSuccess',
|
||||
request: () => 'request',
|
||||
requestOptions: () => 'requestOptions',
|
||||
requestUsingFetch: () => 'requestUsingFetch',
|
||||
requestUsingXHR: () => 'requestUsingXHR',
|
||||
result: () => 'result',
|
||||
},
|
||||
};
|
||||
|
||||
await writeClient(client, templates, '/', HttpClient.FETCH, false, true, true, true, true);
|
||||
await writeClient(client, templates, '/', HttpClient.FETCH, false, false, true, true, true, true);
|
||||
|
||||
expect(rmdir).toBeCalled();
|
||||
expect(mkdir).toBeCalled();
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
import * as path from 'path';
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { copyFile, mkdir, rmdir } from './fileSystem';
|
||||
import { mkdir, rmdir } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarTemplates';
|
||||
import { writeClientCore } from './writeClientCore';
|
||||
import { writeClientIndex } from './writeClientIndex';
|
||||
import { writeClientModels } from './writeClientModels';
|
||||
import { writeClientSchemas } from './writeClientSchemas';
|
||||
import { writeClientServices } from './writeClientServices';
|
||||
import { writeClientSettings } from './writeClientSettings';
|
||||
|
||||
async function copySupportFile(filePath: string, outputPath: string): Promise<void> {
|
||||
await copyFile(path.resolve(__dirname, `../src/templates/${filePath}`), path.resolve(outputPath, filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write our OpenAPI client, using the given templates at the given output path.
|
||||
@ -39,32 +35,22 @@ export async function writeClient(
|
||||
exportModels: boolean,
|
||||
exportSchemas: boolean
|
||||
): Promise<void> {
|
||||
const outputPath = path.resolve(process.cwd(), output);
|
||||
const outputPathCore = path.resolve(outputPath, 'core');
|
||||
const outputPathModels = path.resolve(outputPath, 'models');
|
||||
const outputPathSchemas = path.resolve(outputPath, 'schemas');
|
||||
const outputPathServices = path.resolve(outputPath, 'services');
|
||||
const outputPath = resolve(process.cwd(), output);
|
||||
const outputPathCore = resolve(outputPath, 'core');
|
||||
const outputPathModels = resolve(outputPath, 'models');
|
||||
const outputPathSchemas = resolve(outputPath, 'schemas');
|
||||
const outputPathServices = resolve(outputPath, 'services');
|
||||
|
||||
// Clean output directory
|
||||
await rmdir(outputPath);
|
||||
await mkdir(outputPath);
|
||||
|
||||
if (exportCore) {
|
||||
await mkdir(outputPathCore);
|
||||
await copySupportFile('core/ApiError.ts', outputPath);
|
||||
await copySupportFile('core/getFormData.ts', outputPath);
|
||||
await copySupportFile('core/getQueryString.ts', outputPath);
|
||||
await copySupportFile('core/isSuccess.ts', outputPath);
|
||||
await copySupportFile('core/request.ts', outputPath);
|
||||
await copySupportFile('core/RequestOptions.ts', outputPath);
|
||||
await copySupportFile('core/requestUsingFetch.ts', outputPath);
|
||||
await copySupportFile('core/requestUsingXHR.ts', outputPath);
|
||||
await copySupportFile('core/Result.ts', outputPath);
|
||||
await writeClientCore(client, templates, outputPathCore, httpClient);
|
||||
}
|
||||
|
||||
if (exportServices) {
|
||||
await mkdir(outputPathServices);
|
||||
await writeClientSettings(client, templates, outputPathCore, httpClient);
|
||||
await writeClientServices(client.services, templates, outputPathServices, useOptions);
|
||||
}
|
||||
|
||||
@ -75,7 +61,6 @@ export async function writeClient(
|
||||
|
||||
if (exportModels) {
|
||||
await mkdir(outputPathModels);
|
||||
await copySupportFile('models/Dictionary.ts', outputPath);
|
||||
await writeClientModels(client.models, templates, outputPathModels);
|
||||
}
|
||||
|
||||
|
||||
52
src/utils/writeClientCore.spec.ts
Normal file
52
src/utils/writeClientCore.spec.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarTemplates';
|
||||
import { writeClientCore } from './writeClientCore';
|
||||
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClientCore', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: '1.0',
|
||||
models: [],
|
||||
services: [],
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'index',
|
||||
exports: {
|
||||
model: () => 'model',
|
||||
schema: () => 'schema',
|
||||
service: () => 'service',
|
||||
},
|
||||
core: {
|
||||
settings: () => 'settings',
|
||||
apiError: () => 'apiError',
|
||||
getFormData: () => 'getFormData',
|
||||
getQueryString: () => 'getQueryString',
|
||||
isSuccess: () => 'isSuccess',
|
||||
request: () => 'request',
|
||||
requestOptions: () => 'requestOptions',
|
||||
requestUsingFetch: () => 'requestUsingFetch',
|
||||
requestUsingXHR: () => 'requestUsingXHR',
|
||||
result: () => 'result',
|
||||
},
|
||||
};
|
||||
|
||||
await writeClientCore(client, templates, '/', HttpClient.FETCH);
|
||||
|
||||
expect(writeFile).toBeCalledWith('/OpenAPI.ts', 'settings');
|
||||
expect(writeFile).toBeCalledWith('/ApiError.ts', 'apiError');
|
||||
expect(writeFile).toBeCalledWith('/getFormData.ts', 'getFormData');
|
||||
expect(writeFile).toBeCalledWith('/getQueryString.ts', 'getQueryString');
|
||||
expect(writeFile).toBeCalledWith('/isSuccess.ts', 'isSuccess');
|
||||
expect(writeFile).toBeCalledWith('/request.ts', 'request');
|
||||
expect(writeFile).toBeCalledWith('/RequestOptions.ts', 'requestOptions');
|
||||
expect(writeFile).toBeCalledWith('/requestUsingFetch.ts', 'requestUsingFetch');
|
||||
expect(writeFile).toBeCalledWith('/requestUsingXHR.ts', 'requestUsingXHR');
|
||||
expect(writeFile).toBeCalledWith('/Result.ts', 'result');
|
||||
});
|
||||
});
|
||||
31
src/utils/writeClientCore.ts
Normal file
31
src/utils/writeClientCore.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarTemplates';
|
||||
|
||||
/**
|
||||
* Generate OpenAPI core files, this includes the basic boilerplate code to handle requests.
|
||||
* @param client Client object, containing, models, schemas and services.
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath Directory to write the generated files to.
|
||||
* @param httpClient The selected httpClient (fetch or XHR).
|
||||
*/
|
||||
export async function writeClientCore(client: Client, templates: Templates, outputPath: string, httpClient: HttpClient): Promise<void> {
|
||||
const context = {
|
||||
httpClient,
|
||||
server: client.server,
|
||||
version: client.version,
|
||||
};
|
||||
await writeFile(resolve(outputPath, 'OpenAPI.ts'), templates.core.settings(context));
|
||||
await writeFile(resolve(outputPath, 'ApiError.ts'), templates.core.apiError(context));
|
||||
await writeFile(resolve(outputPath, 'getFormData.ts'), templates.core.getFormData(context));
|
||||
await writeFile(resolve(outputPath, 'getQueryString.ts'), templates.core.getQueryString(context));
|
||||
await writeFile(resolve(outputPath, 'isSuccess.ts'), templates.core.isSuccess(context));
|
||||
await writeFile(resolve(outputPath, 'request.ts'), templates.core.request(context));
|
||||
await writeFile(resolve(outputPath, 'RequestOptions.ts'), templates.core.requestOptions(context));
|
||||
await writeFile(resolve(outputPath, 'requestUsingFetch.ts'), templates.core.requestUsingFetch(context));
|
||||
await writeFile(resolve(outputPath, 'requestUsingXHR.ts'), templates.core.requestUsingXHR(context));
|
||||
await writeFile(resolve(outputPath, 'Result.ts'), templates.core.result(context));
|
||||
}
|
||||
@ -15,15 +15,28 @@ describe('writeClientIndex', () => {
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
index: () => 'index',
|
||||
exports: {
|
||||
model: () => 'model',
|
||||
schema: () => 'schema',
|
||||
service: () => 'service',
|
||||
},
|
||||
core: {
|
||||
settings: () => 'settings',
|
||||
apiError: () => 'apiError',
|
||||
getFormData: () => 'getFormData',
|
||||
getQueryString: () => 'getQueryString',
|
||||
isSuccess: () => 'isSuccess',
|
||||
request: () => 'request',
|
||||
requestOptions: () => 'requestOptions',
|
||||
requestUsingFetch: () => 'requestUsingFetch',
|
||||
requestUsingXHR: () => 'requestUsingXHR',
|
||||
result: () => 'result',
|
||||
},
|
||||
};
|
||||
|
||||
await writeClientIndex(client, templates, '/', true, true, true, true);
|
||||
|
||||
expect(writeFile).toBeCalledWith('/index.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/index.ts', 'index');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as path from 'path';
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { writeFile } from './fileSystem';
|
||||
@ -28,7 +28,7 @@ export async function writeClientIndex(
|
||||
exportSchemas: boolean
|
||||
): Promise<void> {
|
||||
await writeFile(
|
||||
path.resolve(outputPath, 'index.ts'),
|
||||
resolve(outputPath, 'index.ts'),
|
||||
templates.index({
|
||||
exportCore,
|
||||
exportServices,
|
||||
|
||||
@ -10,9 +10,9 @@ describe('writeClientModels', () => {
|
||||
const models: Model[] = [
|
||||
{
|
||||
export: 'interface',
|
||||
name: 'Item',
|
||||
type: 'Item',
|
||||
base: 'Item',
|
||||
name: 'MyModel',
|
||||
type: 'MyModel',
|
||||
base: 'MyModel',
|
||||
template: null,
|
||||
link: null,
|
||||
description: null,
|
||||
@ -29,15 +29,28 @@ describe('writeClientModels', () => {
|
||||
];
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
index: () => 'index',
|
||||
exports: {
|
||||
model: () => 'model',
|
||||
schema: () => 'schema',
|
||||
service: () => 'service',
|
||||
},
|
||||
core: {
|
||||
settings: () => 'settings',
|
||||
apiError: () => 'apiError',
|
||||
getFormData: () => 'getFormData',
|
||||
getQueryString: () => 'getQueryString',
|
||||
isSuccess: () => 'isSuccess',
|
||||
request: () => 'request',
|
||||
requestOptions: () => 'requestOptions',
|
||||
requestUsingFetch: () => 'requestUsingFetch',
|
||||
requestUsingXHR: () => 'requestUsingXHR',
|
||||
result: () => 'result',
|
||||
},
|
||||
};
|
||||
|
||||
await writeClientModels(models, templates, '/');
|
||||
|
||||
expect(writeFile).toBeCalledWith('/Item.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/MyModel.ts', 'model');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as path from 'path';
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { writeFile } from './fileSystem';
|
||||
@ -13,8 +13,10 @@ import { Templates } from './registerHandlebarTemplates';
|
||||
*/
|
||||
export async function writeClientModels(models: Model[], templates: Templates, outputPath: string): Promise<void> {
|
||||
for (const model of models) {
|
||||
const file = path.resolve(outputPath, `${model.name}.ts`);
|
||||
const templateResult = templates.model(model);
|
||||
const file = resolve(outputPath, `${model.name}.ts`);
|
||||
const templateResult = templates.exports.model({
|
||||
...model,
|
||||
});
|
||||
await writeFile(file, format(templateResult));
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,9 +10,9 @@ describe('writeClientSchemas', () => {
|
||||
const models: Model[] = [
|
||||
{
|
||||
export: 'interface',
|
||||
name: 'Item',
|
||||
type: 'Item',
|
||||
base: 'Item',
|
||||
name: 'MyModel',
|
||||
type: 'MyModel',
|
||||
base: 'MyModel',
|
||||
template: null,
|
||||
link: null,
|
||||
description: null,
|
||||
@ -29,15 +29,28 @@ describe('writeClientSchemas', () => {
|
||||
];
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
index: () => 'index',
|
||||
exports: {
|
||||
model: () => 'model',
|
||||
schema: () => 'schema',
|
||||
service: () => 'service',
|
||||
},
|
||||
core: {
|
||||
settings: () => 'settings',
|
||||
apiError: () => 'apiError',
|
||||
getFormData: () => 'getFormData',
|
||||
getQueryString: () => 'getQueryString',
|
||||
isSuccess: () => 'isSuccess',
|
||||
request: () => 'request',
|
||||
requestOptions: () => 'requestOptions',
|
||||
requestUsingFetch: () => 'requestUsingFetch',
|
||||
requestUsingXHR: () => 'requestUsingXHR',
|
||||
result: () => 'result',
|
||||
},
|
||||
};
|
||||
|
||||
await writeClientSchemas(models, templates, '/');
|
||||
|
||||
expect(writeFile).toBeCalledWith('/$Item.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/$MyModel.ts', 'schema');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as path from 'path';
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Model } from '../client/interfaces/Model';
|
||||
import { writeFile } from './fileSystem';
|
||||
@ -13,8 +13,10 @@ import { Templates } from './registerHandlebarTemplates';
|
||||
*/
|
||||
export async function writeClientSchemas(models: Model[], templates: Templates, outputPath: string): Promise<void> {
|
||||
for (const model of models) {
|
||||
const file = path.resolve(outputPath, `$${model.name}.ts`);
|
||||
const templateResult = templates.schema(model);
|
||||
const file = resolve(outputPath, `$${model.name}.ts`);
|
||||
const templateResult = templates.exports.schema({
|
||||
...model,
|
||||
});
|
||||
await writeFile(file, format(templateResult));
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,22 +9,35 @@ describe('writeClientServices', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const services: Service[] = [
|
||||
{
|
||||
name: 'Item',
|
||||
name: 'MyService',
|
||||
operations: [],
|
||||
imports: [],
|
||||
},
|
||||
];
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
index: () => 'index',
|
||||
exports: {
|
||||
model: () => 'model',
|
||||
schema: () => 'schema',
|
||||
service: () => 'service',
|
||||
},
|
||||
core: {
|
||||
settings: () => 'settings',
|
||||
apiError: () => 'apiError',
|
||||
getFormData: () => 'getFormData',
|
||||
getQueryString: () => 'getQueryString',
|
||||
isSuccess: () => 'isSuccess',
|
||||
request: () => 'request',
|
||||
requestOptions: () => 'requestOptions',
|
||||
requestUsingFetch: () => 'requestUsingFetch',
|
||||
requestUsingXHR: () => 'requestUsingXHR',
|
||||
result: () => 'result',
|
||||
},
|
||||
};
|
||||
|
||||
await writeClientServices(services, templates, '/', false);
|
||||
|
||||
expect(writeFile).toBeCalledWith('/Item.ts', 'dummy');
|
||||
expect(writeFile).toBeCalledWith('/MyService.ts', 'service');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as path from 'path';
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Service } from '../client/interfaces/Service';
|
||||
import { writeFile } from './fileSystem';
|
||||
@ -16,10 +16,10 @@ const VERSION_TEMPLATE_STRING = 'OpenAPI.VERSION';
|
||||
*/
|
||||
export async function writeClientServices(services: Service[], templates: Templates, outputPath: string, useOptions: boolean): Promise<void> {
|
||||
for (const service of services) {
|
||||
const file = path.resolve(outputPath, `${service.name}.ts`);
|
||||
const file = resolve(outputPath, `${service.name}.ts`);
|
||||
const hasApiErrors = service.operations.some(operation => operation.errors.length);
|
||||
const hasApiVersion = service.operations.some(operation => operation.path.includes(VERSION_TEMPLATE_STRING));
|
||||
const templateResult = templates.service({
|
||||
const templateResult = templates.exports.service({
|
||||
...service,
|
||||
hasApiErrors,
|
||||
hasApiVersion,
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarTemplates';
|
||||
import { writeClientSettings } from './writeClientSettings';
|
||||
|
||||
jest.mock('./fileSystem');
|
||||
|
||||
describe('writeClientSettings', () => {
|
||||
it('should write to filesystem', async () => {
|
||||
const client: Client = {
|
||||
server: 'http://localhost:8080',
|
||||
version: '1.0',
|
||||
models: [],
|
||||
services: [],
|
||||
};
|
||||
|
||||
const templates: Templates = {
|
||||
index: () => 'dummy',
|
||||
model: () => 'dummy',
|
||||
schema: () => 'dummy',
|
||||
service: () => 'dummy',
|
||||
settings: () => 'dummy',
|
||||
};
|
||||
|
||||
await writeClientSettings(client, templates, '/', HttpClient.FETCH);
|
||||
|
||||
expect(writeFile).toBeCalledWith('/OpenAPI.ts', 'dummy');
|
||||
});
|
||||
});
|
||||
@ -1,24 +0,0 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import { Client } from '../client/interfaces/Client';
|
||||
import { HttpClient } from '../index';
|
||||
import { writeFile } from './fileSystem';
|
||||
import { Templates } from './registerHandlebarTemplates';
|
||||
|
||||
/**
|
||||
* Generate OpenAPI configuration file "OpenAPI.ts"
|
||||
* @param client Client object, containing, models, schemas and services.
|
||||
* @param templates The loaded handlebar templates.
|
||||
* @param outputPath Directory to write the generated files to.
|
||||
* @param httpClient The selected httpClient (fetch or XHR).
|
||||
*/
|
||||
export async function writeClientSettings(client: Client, templates: Templates, outputPath: string, httpClient: HttpClient): Promise<void> {
|
||||
await writeFile(
|
||||
path.resolve(outputPath, 'OpenAPI.ts'),
|
||||
templates.settings({
|
||||
httpClient,
|
||||
server: client.server,
|
||||
version: client.version,
|
||||
})
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
|
||||
const path = require('path');
|
||||
const ts = require('typescript');
|
||||
const OpenAPI = require('../dist');
|
||||
const OpenAPI = require('../../dist');
|
||||
|
||||
function compile(dir) {
|
||||
const config = {
|
||||
@ -20,35 +20,43 @@ function compile(dir) {
|
||||
compiler.emit();
|
||||
}
|
||||
|
||||
async function run() {
|
||||
console.time('generate');
|
||||
|
||||
async function generateV2() {
|
||||
console.time('generate v2');
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
input: './test/spec/v2.json',
|
||||
output: './test/generator/dist/v2/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: false,
|
||||
useUnionTypes: false,
|
||||
exportCore: true,
|
||||
exportSchemas: true,
|
||||
exportModels: true,
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: false,
|
||||
exportCore: true,
|
||||
exportSchemas: true,
|
||||
exportModels: true,
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
console.timeEnd('generate');
|
||||
|
||||
compile('./test/result/v2/');
|
||||
compile('./test/result/v3/');
|
||||
console.timeEnd('generate v2');
|
||||
compile('test/generator/dist/v2/');
|
||||
}
|
||||
|
||||
run();
|
||||
async function generateV3() {
|
||||
console.time('generate v3');
|
||||
await OpenAPI.generate({
|
||||
input: './test/spec/v3.json',
|
||||
output: './test/generator/dist/v3/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: false,
|
||||
useUnionTypes: false,
|
||||
exportCore: true,
|
||||
exportSchemas: true,
|
||||
exportModels: true,
|
||||
exportServices: true,
|
||||
});
|
||||
console.timeEnd('generate v3');
|
||||
compile('test/generator/dist/v3/');
|
||||
}
|
||||
|
||||
async function generate() {
|
||||
await generateV2();
|
||||
await generateV3();
|
||||
}
|
||||
|
||||
generate();
|
||||
@ -1,23 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const OpenAPI = require('../dist');
|
||||
const OpenAPI = require('../../dist');
|
||||
const glob = require('glob');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('v2', () => {
|
||||
it('should generate', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v2/spec.json',
|
||||
output: './test/result/v2/',
|
||||
input: './test/spec/v2.json',
|
||||
output: './test/generator/dist/v2/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: false,
|
||||
useUnionTypes: false,
|
||||
exportCore: true,
|
||||
exportSchemas: true,
|
||||
exportModels: true,
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
const files = glob.sync('./test/result/v2/**/*.ts');
|
||||
const files = glob.sync('./test/generator/dist/v2/**/*.ts');
|
||||
|
||||
files.forEach(file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
@ -29,17 +30,18 @@ describe('v2', () => {
|
||||
describe('v3', () => {
|
||||
it('should generate', async () => {
|
||||
await OpenAPI.generate({
|
||||
input: './test/mock/v3/spec.json',
|
||||
output: './test/result/v3/',
|
||||
input: './test/spec/v3.json',
|
||||
output: './test/generator/dist/v3/',
|
||||
httpClient: OpenAPI.HttpClient.FETCH,
|
||||
useOptions: false,
|
||||
useUnionTypes: false,
|
||||
exportCore: true,
|
||||
exportSchemas: true,
|
||||
exportModels: true,
|
||||
exportServices: true,
|
||||
});
|
||||
|
||||
const files = glob.sync('./test/result/v3/**/*.ts');
|
||||
const files = glob.sync('./test/generator/dist/v3/**/*.ts');
|
||||
|
||||
files.forEach(file => {
|
||||
const content = fs.readFileSync(file, 'utf8').toString();
|
||||
8
test/server/src/AppModule.ts
Normal file
8
test/server/src/AppModule.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
@Module({
|
||||
controllers: [],
|
||||
})
|
||||
export class AppModule {
|
||||
//
|
||||
}
|
||||
21
test/server/src/main.ts
Normal file
21
test/server/src/main.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {NestFactory} from '@nestjs/core';
|
||||
import {DocumentBuilder, SwaggerModule} from '@nestjs/swagger';
|
||||
import {AppModule} from './AppModule';
|
||||
|
||||
async function bootstrap(): Promise<void> {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
const options = new DocumentBuilder()
|
||||
.setTitle('OpenAPI')
|
||||
.setDescription('The OpenAPI description')
|
||||
.setVersion('1.0')
|
||||
.build();
|
||||
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
|
||||
SwaggerModule.setup('api', app, document);
|
||||
|
||||
await app.listen(3000);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
34
test/server/tsconfig.json
Normal file
34
test/server/tsconfig.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"target": "es2017",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["es2017", "dom"],
|
||||
"types": ["jest", "node"],
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"sourceMap": false,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
|
||||
"include": [
|
||||
"./src/main.ts"
|
||||
],
|
||||
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "v9.0",
|
||||
"title": "swagger"
|
||||
"title": "swagger",
|
||||
"version": "v1.0"
|
||||
},
|
||||
"host": "localhost:8080",
|
||||
"basePath": "/api",
|
||||
@ -221,7 +221,7 @@
|
||||
"in": "query",
|
||||
"required": true,
|
||||
"default": {
|
||||
"prop": "Hello World"
|
||||
"prop": "Hello World!"
|
||||
},
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ModelWithString"
|
||||
@ -274,7 +274,7 @@
|
||||
"name": "parameterModel",
|
||||
"in": "query",
|
||||
"default": {
|
||||
"prop": "Hello World"
|
||||
"prop": "Hello World!"
|
||||
},
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ModelWithString"
|
||||
@ -316,7 +316,7 @@
|
||||
"name": "parameterStringWithDefault",
|
||||
"in": "query",
|
||||
"required": true,
|
||||
"default": "hello",
|
||||
"default": "Hello World!",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"openapi": "3.0.1",
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "swagger",
|
||||
"version": "v1"
|
||||
"version": "v1.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
@ -366,7 +366,7 @@
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ModelWithString",
|
||||
"default": {
|
||||
"prop": "Hello World"
|
||||
"prop": "Hello World!"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -430,7 +430,7 @@
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ModelWithString",
|
||||
"default": {
|
||||
"prop": "Hello World"
|
||||
"prop": "Hello World!"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -449,7 +449,7 @@
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "hello"
|
||||
"default": "Hello World!"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -478,7 +478,7 @@
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"default": "hello"
|
||||
"default": "Hello World!"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1,12 +1,10 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"target": "ES2017",
|
||||
"module": "ES6",
|
||||
"moduleResolution": "Node",
|
||||
"lib": ["ES2017", "DOM"],
|
||||
"target": "es2017",
|
||||
"module": "es6",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["es2017", "dom"],
|
||||
"types": ["jest", "node"],
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"declaration": false,
|
||||
@ -20,7 +18,6 @@
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"removeComments": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user