- Fixed build and prep for e2e test

This commit is contained in:
Ferdi Koomen 2020-09-24 22:46:04 +02:00
parent c450461bd3
commit 0b6fd22c99
32 changed files with 175 additions and 116 deletions

View File

@ -2,14 +2,11 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
esmodules: true,
},
},
],
['@babel/preset-env', {
targets: {
node: 'current'
}
}],
'@babel/preset-typescript',
],
};

View File

@ -1,5 +1,10 @@
module.exports = {
testRegex: '\\.spec\\.(ts|js)$',
testRegex: '.*\\.spec\\.(ts|js)$',
testPathIgnorePatterns: [
'/node_modules/',
'<rootDir>/dist/',
'<rootDir>/samples/',
],
testEnvironment: 'node',
moduleNameMapper: {
'\\.hbs$': '<rootDir>/src/templates/__mocks__/index.js',
@ -7,7 +12,6 @@ module.exports = {
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/templates/**',
'!**/node_modules/**',
],
};

View File

@ -102,7 +102,7 @@
"jest-cli": "26.4.2",
"prettier": "2.1.2",
"reflect-metadata": "0.1.13",
"rollup": "2.28.1",
"rollup": "2.28.2",
"rollup-plugin-terser": "7.0.2",
"rollup-plugin-typescript2": "0.27.2",
"swagger-ui-express": "4.1.4",

View File

@ -1,8 +1,8 @@
'use strict';
const commonjs = require('@rollup/plugin-commonjs');
const {nodeResolve} = require('@rollup/plugin-node-resolve');
const {terser} = require('rollup-plugin-terser');
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const { terser } = require('rollup-plugin-terser');
const typescript = require('rollup-plugin-typescript2');
const handlebars = require('handlebars');
const path = require('path');

View File

@ -4,18 +4,18 @@ rm -rf dist
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.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
#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
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/
#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/
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/
#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/
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/

View File

@ -1,31 +1,35 @@
import * as OpenAPI from './index';
describe('index', () => {
it('parses v2 without issues', async () => {
// await OpenAPI.generate({
// input: './test/mock/v2/spec.json',
// output: './test/result/v2/',
// useOptions: true
// });
await OpenAPI.generate({
input: './test/spec/v3.json',
output: './temp/v3/',
write: false,
});
});
it('parses v3 without issues', async () => {
// await OpenAPI.generate({
// input: './test/mock/v3/spec.json',
// output: './test/result/v3/',
// useOptions: true
// });
await OpenAPI.generate({
input: './test/spec/v3.json',
output: './temp/v3/',
write: false,
});
});
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/'
// });
await OpenAPI.generate({
input: 'https://raw.githubusercontent.com/ferdikoomen/openapi-typescript-codegen/master/test/spec/v2.json',
output: './temp/v2-downloaded/',
write: false,
});
});
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/'
// });
await OpenAPI.generate({
input: 'https://raw.githubusercontent.com/ferdikoomen/openapi-typescript-codegen/master/test/spec/v3.json',
output: './temp/v3-downloaded/',
write: false,
});
});
});

View File

@ -23,6 +23,7 @@ export interface Options {
exportServices?: boolean;
exportModels?: boolean;
exportSchemas?: boolean;
write?: boolean;
}
/**
@ -50,6 +51,7 @@ 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
@ -61,6 +63,7 @@ export async function generate({
case OpenApiVersion.V2: {
const client = parseV2(openApi);
const clientFinal = postProcessClient(client);
if (!write) break;
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
break;
}
@ -68,6 +71,7 @@ export async function generate({
case OpenApiVersion.V3: {
const client = parseV3(openApi);
const clientFinal = postProcessClient(client);
if (!write) break;
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
break;
}

View File

@ -1,10 +1,10 @@
import { EOL } from 'os';
import * as os from 'os';
import { getComment } from './getComment';
describe('getComment', () => {
it('should parse comments', () => {
const multiline = 'Testing multiline comments.' + EOL + ' * This must go to the next line.' + EOL + ' * ' + EOL + ' * This will contain a break.';
const multiline = 'Testing multiline comments.' + os.EOL + ' * This must go to the next line.' + os.EOL + ' * ' + os.EOL + ' * This will contain a break.';
expect(getComment('')).toEqual(null);
expect(getComment('Hello')).toEqual('Hello');
expect(getComment('Hello World!')).toEqual('Hello World!');

View File

@ -1,4 +1,4 @@
import { EOL } from 'os';
import * as os from 'os';
/**
* Cleanup comment and prefix multiline comments with "*",
@ -7,7 +7,7 @@ import { EOL } from 'os';
*/
export function getComment(comment?: string): string | null {
if (comment) {
return comment.replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`);
return comment.replace(/\r?\n(.*)/g, (_, w) => `${os.EOL} * ${w.trim()}`);
}
return null;
}

View File

@ -1,10 +1,10 @@
import { EOL } from 'os';
import * as os from 'os';
import { getComment } from './getComment';
describe('getComment', () => {
it('should parse comments', () => {
const multiline = 'Testing multiline comments.' + EOL + ' * This must go to the next line.' + EOL + ' * ' + EOL + ' * This will contain a break.';
const multiline = 'Testing multiline comments.' + os.EOL + ' * This must go to the next line.' + os.EOL + ' * ' + os.EOL + ' * This will contain a break.';
expect(getComment('')).toEqual(null);
expect(getComment('Hello')).toEqual('Hello');
expect(getComment('Hello World!')).toEqual('Hello World!');

View File

@ -1,4 +1,4 @@
import { EOL } from 'os';
import * as os from 'os';
/**
* Cleanup comment and prefix multiline comments with "*",
@ -7,7 +7,7 @@ import { EOL } from 'os';
*/
export function getComment(comment?: string): string | null {
if (comment) {
return comment.replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`);
return comment.replace(/\r?\n(.*)/g, (_, w) => `${os.EOL} * ${w.trim()}`);
}
return null;
}

View File

@ -1,8 +1,8 @@
import { EOL } from 'os';
import * as os from 'os';
export function format(s: string): string {
let indent: number = 0;
let lines = s.split(EOL);
let lines = s.split(os.EOL);
lines = lines.map(line => {
line = line.trim().replace(/^\*/g, ' *');
let i = indent;
@ -19,5 +19,5 @@ export function format(s: string): string {
}
return result;
});
return lines.join(EOL);
return lines.join(os.EOL);
}

View File

@ -1,5 +1,5 @@
import { safeLoad } from 'js-yaml';
import { extname } from 'path';
import * as yaml from 'js-yaml';
import * as path 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 extension = extname(input).toLowerCase();
const extension = path.extname(input).toLowerCase();
const content = await readSpec(input);
switch (extension) {
case '.yml':
case '.yaml':
try {
return safeLoad(content);
return yaml.safeLoad(content);
} catch (e) {
throw new Error(`Could not parse OpenApi YAML: "${input}"`);
}

View File

@ -0,0 +1,15 @@
import * as path from 'path';
import { isSubDirectory } from './isSubdirectory';
describe('isSubDirectory', () => {
it('should return correct result', () => {
expect(isSubDirectory(path.resolve('/'), path.resolve('/'))).toBeFalsy();
expect(isSubDirectory(path.resolve('.'), path.resolve('.'))).toBeFalsy();
expect(isSubDirectory(path.resolve('./project'), path.resolve('./project'))).toBeFalsy();
expect(isSubDirectory(path.resolve('./project'), path.resolve('../'))).toBeFalsy();
expect(isSubDirectory(path.resolve('./project'), path.resolve('../../'))).toBeFalsy();
expect(isSubDirectory(path.resolve('./'), path.resolve('./output'))).toBeTruthy();
expect(isSubDirectory(path.resolve('./'), path.resolve('../output'))).toBeTruthy();
});
});

View File

@ -1,5 +1,5 @@
import { relative } from 'path';
import * as path from 'path';
export function isSubDirectory(parent: string, child: string) {
return relative(child, parent).startsWith('..');
return path.relative(child, parent).startsWith('..');
}

View File

@ -1,4 +1,4 @@
import path from 'path';
import * as path from 'path';
import { exists, readFile } from './fileSystem';

View File

@ -1,4 +1,4 @@
import http from 'http';
import * as http from 'http';
/**
* Download the spec file from a HTTP resource

View File

@ -1,4 +1,4 @@
import https from 'https';
import * as https from 'https';
/**
* Download the spec file from a HTTPS resource

View File

@ -0,0 +1,12 @@
import * as Handlebars from 'handlebars/runtime';
import { registerHandlebarHelpers } from './registerHandlebarHelpers';
describe('registerHandlebarHelpers', () => {
it('should register the helpers', () => {
registerHandlebarHelpers();
const helpers = Object.keys(Handlebars.helpers);
expect(helpers).toContain('equals');
expect(helpers).toContain('notEquals');
});
});

View File

@ -0,0 +1,21 @@
import { registerHandlebarTemplates } from './registerHandlebarTemplates';
describe('registerHandlebarTemplates', () => {
it('should return correct templates', () => {
const templates = registerHandlebarTemplates();
expect(templates.index).toBeDefined();
expect(templates.exports.model).toBeDefined();
expect(templates.exports.schema).toBeDefined();
expect(templates.exports.service).toBeDefined();
expect(templates.core.settings).toBeDefined();
expect(templates.core.apiError).toBeDefined();
expect(templates.core.getFormData).toBeDefined();
expect(templates.core.getQueryString).toBeDefined();
expect(templates.core.isSuccess).toBeDefined();
expect(templates.core.request).toBeDefined();
expect(templates.core.requestOptions).toBeDefined();
expect(templates.core.requestUsingFetch).toBeDefined();
expect(templates.core.requestUsingXHR).toBeDefined();
expect(templates.core.result).toBeDefined();
});
});

10
src/utils/sort.spec.ts Normal file
View File

@ -0,0 +1,10 @@
import { sort } from './sort';
describe('sort', () => {
it('should return correct index', () => {
expect(sort('a', 'b')).toEqual(-1);
expect(sort('b', 'a')).toEqual(1);
expect(sort('a', 'a')).toEqual(0);
expect(sort('', '')).toEqual(0);
});
});

12
src/utils/unique.spec.ts Normal file
View File

@ -0,0 +1,12 @@
import { unique } from './unique';
describe('unique', () => {
it('should return correct index', () => {
expect(unique('a', 0, ['a', 'b', 'c'])).toBeTruthy();
expect(unique('a', 1, ['a', 'b', 'c'])).toBeFalsy();
expect(unique('a', 2, ['a', 'b', 'c'])).toBeFalsy();
expect(unique('a', 0, ['a', 'b', 'c'])).toBeTruthy();
expect(unique('a', 1, ['z', 'a', 'b'])).toBeTruthy();
expect(unique('a', 2, ['y', 'z', 'a'])).toBeTruthy();
});
});

View File

@ -36,7 +36,7 @@ describe('writeClient', () => {
},
};
await writeClient(client, templates, '/', HttpClient.FETCH, false, false, true, true, true, true);
await writeClient(client, templates, './dist', HttpClient.FETCH, false, false, true, true, true, true);
expect(rmdir).toBeCalled();
expect(mkdir).toBeCalled();

View File

@ -1,4 +1,4 @@
import { resolve } from 'path';
import * as path from 'path';
import { Client } from '../client/interfaces/Client';
import { HttpClient } from '../index';
@ -36,11 +36,11 @@ export async function writeClient(
exportModels: boolean,
exportSchemas: boolean
): Promise<void> {
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');
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');
if (!isSubDirectory(process.cwd(), output)) {
throw new Error(`Output folder is not a subdirectory of the current working directory`);

View File

@ -1,4 +1,4 @@
import { resolve } from 'path';
import * as path from 'path';
import { Client } from '../client/interfaces/Client';
import { HttpClient } from '../index';
@ -18,14 +18,14 @@ export async function writeClientCore(client: Client, templates: Templates, outp
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));
await writeFile(path.resolve(outputPath, 'OpenAPI.ts'), templates.core.settings(context));
await writeFile(path.resolve(outputPath, 'ApiError.ts'), templates.core.apiError(context));
await writeFile(path.resolve(outputPath, 'getFormData.ts'), templates.core.getFormData(context));
await writeFile(path.resolve(outputPath, 'getQueryString.ts'), templates.core.getQueryString(context));
await writeFile(path.resolve(outputPath, 'isSuccess.ts'), templates.core.isSuccess(context));
await writeFile(path.resolve(outputPath, 'request.ts'), templates.core.request(context));
await writeFile(path.resolve(outputPath, 'RequestOptions.ts'), templates.core.requestOptions(context));
await writeFile(path.resolve(outputPath, 'requestUsingFetch.ts'), templates.core.requestUsingFetch(context));
await writeFile(path.resolve(outputPath, 'requestUsingXHR.ts'), templates.core.requestUsingXHR(context));
await writeFile(path.resolve(outputPath, 'Result.ts'), templates.core.result(context));
}

View File

@ -1,4 +1,4 @@
import { resolve } from 'path';
import * as path 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(
resolve(outputPath, 'index.ts'),
path.resolve(outputPath, 'index.ts'),
templates.index({
exportCore,
exportServices,

View File

@ -1,4 +1,4 @@
import { resolve } from 'path';
import * as path from 'path';
import { Model } from '../client/interfaces/Model';
import { writeFile } from './fileSystem';
@ -13,7 +13,7 @@ import { Templates } from './registerHandlebarTemplates';
*/
export async function writeClientModels(models: Model[], templates: Templates, outputPath: string): Promise<void> {
for (const model of models) {
const file = resolve(outputPath, `${model.name}.ts`);
const file = path.resolve(outputPath, `${model.name}.ts`);
const templateResult = templates.exports.model({
...model,
});

View File

@ -1,4 +1,4 @@
import { resolve } from 'path';
import * as path from 'path';
import { Model } from '../client/interfaces/Model';
import { writeFile } from './fileSystem';
@ -13,7 +13,7 @@ import { Templates } from './registerHandlebarTemplates';
*/
export async function writeClientSchemas(models: Model[], templates: Templates, outputPath: string): Promise<void> {
for (const model of models) {
const file = resolve(outputPath, `$${model.name}.ts`);
const file = path.resolve(outputPath, `$${model.name}.ts`);
const templateResult = templates.exports.schema({
...model,
});

View File

@ -1,4 +1,4 @@
import { resolve } from 'path';
import * as path from 'path';
import { Service } from '../client/interfaces/Service';
import { writeFile } from './fileSystem';
@ -16,7 +16,7 @@ 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 = resolve(outputPath, `${service.name}.ts`);
const file = path.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.exports.service({

View File

@ -1,34 +1,13 @@
{
"extends": "../../tsconfig.json",
"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
"module": "commonjs"
},
"include": [
"./src/**/*.ts"
],
"exclude": [
"node_modules"
]
}

View File

@ -6,7 +6,6 @@
"moduleResolution": "node",
"lib": ["es2017", "dom"],
"types": ["jest", "node"],
"typeRoots": ["node_modules/@types"],
"declaration": false,
"declarationMap": false,
"sourceMap": false,
@ -18,6 +17,8 @@
"strictNullChecks": true,
"strictFunctionTypes": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true
},

View File

@ -6703,10 +6703,10 @@ rollup-plugin-typescript2@0.27.2:
resolve "1.17.0"
tslib "2.0.1"
rollup@2.28.1:
version "2.28.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.28.1.tgz#ceedca3cdb013c2fa8f22f958a29c203368159ea"
integrity sha512-DOtVoqOZt3+FjPJWLU8hDIvBjUylc9s6IZvy76XklxzcLvAQLtVAG/bbhsMhcWnYxC0TKKcf1QQ/tg29zeID0Q==
rollup@2.28.2:
version "2.28.2"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.28.2.tgz#599ec4978144a82d8a8ec3d37670a8440cb04e4b"
integrity sha512-8txbsFBFLmm9Xdt4ByTOGa9Muonmc8MfNjnGAR8U8scJlF1ZW7AgNZa7aqBXaKtlvnYP/ab++fQIq9dB9NWUbg==
optionalDependencies:
fsevents "~2.1.2"