mirror of
https://gitee.com/eolink_admin/postcat.git
synced 2024-12-02 19:57:45 +08:00
feat: local mock service (#62)
This commit is contained in:
parent
a9b61b76c9
commit
ef815767b3
14
package.json
14
package.json
@ -19,17 +19,21 @@
|
|||||||
"test:workbench": "cd src/workbench/browser && yarn test",
|
"test:workbench": "cd src/workbench/browser && yarn test",
|
||||||
"electron:serve": "wait-on tcp:4200 && npm run electron:dev",
|
"electron:serve": "wait-on tcp:4200 && npm run electron:dev",
|
||||||
"electron:dev:static": "npm run electron:tsc && electron .",
|
"electron:dev:static": "npm run electron:tsc && electron .",
|
||||||
"electron:dev": "npm run electron:tsc && electron . --development",
|
"electron:dev": "npm run electron:tsc && npm run copyfile:out && electron . --development",
|
||||||
"build": "npm-run-all -s build:workbench electron:tsc && electron-builder build",
|
"build": "npm-run-all -s build:workbench electron:tsc && electron-builder build",
|
||||||
"build:static": "npm run electron:tsc && electron-builder build",
|
"build:static": "npm run electron:tsc && electron-builder build",
|
||||||
"release": "npm-run-all -s build:workbench electron:tsc && electron-builder --publish=always",
|
"release": "npm-run-all -s build:workbench electron:tsc && electron-builder --publish=always",
|
||||||
"test": "npm-run-all --serial test:*",
|
"test": "npm-run-all --serial test:*",
|
||||||
"electron:tsc": "tsc -p tsconfig.json"
|
"electron:tsc": "tsc -p tsconfig.json",
|
||||||
|
"copyfile:out": "copyfiles -u 1 src/**/*.json src/app/common/images/** out"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bqy/node-module-alias": "^1.0.1",
|
"@bqy/node-module-alias": "^1.0.1",
|
||||||
"@electron/remote": "2.0.8",
|
"@electron/remote": "2.0.8",
|
||||||
|
"@koa/cors": "3.3.0",
|
||||||
|
"@koa/router": "10.1.1",
|
||||||
"content-disposition": "^0.5.4",
|
"content-disposition": "^0.5.4",
|
||||||
|
"copyfiles": "2.4.1",
|
||||||
"cross-spawn": "^7.0.3",
|
"cross-spawn": "^7.0.3",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"dexie": "3.2.2",
|
"dexie": "3.2.2",
|
||||||
@ -38,13 +42,19 @@
|
|||||||
"fix-path": "3.0.0",
|
"fix-path": "3.0.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
|
"koa": "2.13.4",
|
||||||
|
"koa-bodyparser": "4.3.0",
|
||||||
|
"mockjs": "1.1.0",
|
||||||
"npm": "6.14.17",
|
"npm": "6.14.17",
|
||||||
|
"portfinder": "1.0.28",
|
||||||
"resolve": "^1.22.0",
|
"resolve": "^1.22.0",
|
||||||
"rxjs": "7.5.5",
|
"rxjs": "7.5.5",
|
||||||
"xml2js": "^0.4.23"
|
"xml2js": "^0.4.23"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cross-spawn": "6.0.2",
|
"@types/cross-spawn": "6.0.2",
|
||||||
|
"@types/koa": "2.13.4",
|
||||||
|
"@types/koa__router": "8.0.11",
|
||||||
"@types/node": "17.0.32",
|
"@types/node": "17.0.32",
|
||||||
"@typescript-eslint/eslint-plugin": "5.23.0",
|
"@typescript-eslint/eslint-plugin": "5.23.0",
|
||||||
"@typescript-eslint/parser": "5.23.0",
|
"@typescript-eslint/parser": "5.23.0",
|
||||||
|
@ -12,13 +12,16 @@ import { deleteFile, readJson } from 'eo/shared/node/file';
|
|||||||
import { STORAGE_TEMP as storageTemp } from 'eo/shared/common/constant';
|
import { STORAGE_TEMP as storageTemp } from 'eo/shared/common/constant';
|
||||||
import { UnitWorkerModule } from 'eo/workbench/node/unitWorker';
|
import { UnitWorkerModule } from 'eo/workbench/node/unitWorker';
|
||||||
import Configuration from 'eo/platform/node/configuration/lib';
|
import Configuration from 'eo/platform/node/configuration/lib';
|
||||||
import { ConfigurationInterface } from 'eo/platform/node/configuration';
|
import { ConfigurationInterface } from 'src/platform/node/configuration';
|
||||||
|
import { MockServer } from 'eo/platform/node/mock-server';
|
||||||
|
|
||||||
let win: BrowserWindow = null;
|
let win: BrowserWindow = null;
|
||||||
export const subView = {
|
export const subView = {
|
||||||
appView: null,
|
appView: null,
|
||||||
mainView: null,
|
mainView: null,
|
||||||
};
|
};
|
||||||
const eoUpdater = new EoUpdater();
|
const eoUpdater = new EoUpdater();
|
||||||
|
const mockServer = new MockServer();
|
||||||
const moduleManager: ModuleManagerInterface = ModuleManager();
|
const moduleManager: ModuleManagerInterface = ModuleManager();
|
||||||
const configuration: ConfigurationInterface = Configuration();
|
const configuration: ConfigurationInterface = Configuration();
|
||||||
// Remote
|
// Remote
|
||||||
@ -85,9 +88,11 @@ try {
|
|||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
// Added 400 ms to fix the black background issue while using transparent window. More detais at https://github.com/electron/electron/issues/15947
|
// Added 400 ms to fix the black background issue while using transparent window. More detais at https://github.com/electron/electron/issues/15947
|
||||||
app.on('ready', () => {
|
app.on('ready', async () => {
|
||||||
setTimeout(createWindow, 400);
|
setTimeout(createWindow, 400);
|
||||||
eoUpdater.check();
|
eoUpdater.check();
|
||||||
|
// 启动mock服务
|
||||||
|
await mockServer.start();
|
||||||
});
|
});
|
||||||
//!TODO only api manage app need this
|
//!TODO only api manage app need this
|
||||||
// setupUnit(subView.appView);
|
// setupUnit(subView.appView);
|
||||||
@ -99,6 +104,7 @@ try {
|
|||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
mockServer.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
@ -204,6 +210,20 @@ try {
|
|||||||
returnValue = configuration.getModuleSettings(arg.data.moduleID);
|
returnValue = configuration.getModuleSettings(arg.data.moduleID);
|
||||||
} else if (arg.action === 'getSidePosition') {
|
} else if (arg.action === 'getSidePosition') {
|
||||||
returnValue = subView.appView?.sidePosition;
|
returnValue = subView.appView?.sidePosition;
|
||||||
|
// 注册单个mock路由
|
||||||
|
} else if (arg.action === 'registerMockRoute') {
|
||||||
|
const { method, path, data } = arg.data;
|
||||||
|
returnValue = mockServer.registerRoute(method, path, data);
|
||||||
|
// 注销mock路由
|
||||||
|
} else if (arg.action === 'unRegisterMockRoute') {
|
||||||
|
const { method, path } = arg.data;
|
||||||
|
returnValue = mockServer.unRegisterRoute(method, path);
|
||||||
|
// 获取mock服务地址
|
||||||
|
} else if (arg.action === 'getMockUrl') {
|
||||||
|
returnValue = mockServer.getMockUrl();
|
||||||
|
// 重置并初始化mock路由
|
||||||
|
} else if (arg.action === 'resetAndInitRoutes') {
|
||||||
|
returnValue = mockServer.resetAndInitRoutes();
|
||||||
} else if (arg.action === 'hook') {
|
} else if (arg.action === 'hook') {
|
||||||
returnValue = 'hook返回';
|
returnValue = 'hook返回';
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,7 +8,7 @@ interface StorageModel {
|
|||||||
* 主键UUID,字符串UUID或数值型
|
* 主键UUID,字符串UUID或数值型
|
||||||
* @type {string|number}
|
* @type {string|number}
|
||||||
*/
|
*/
|
||||||
uuid?: string|number;
|
uuid?: string | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 名称
|
* 名称
|
||||||
@ -49,7 +49,7 @@ export interface Environment extends StorageModel {
|
|||||||
* 项目主键ID
|
* 项目主键ID
|
||||||
* @type {string|number}
|
* @type {string|number}
|
||||||
*/
|
*/
|
||||||
projectID: string|number;
|
projectID: string | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前置url
|
* 前置url
|
||||||
@ -64,7 +64,6 @@ export interface Environment extends StorageModel {
|
|||||||
parameters?: object;
|
parameters?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分组对象接口
|
* 分组对象接口
|
||||||
*/
|
*/
|
||||||
@ -79,13 +78,13 @@ export interface Group extends StorageModel {
|
|||||||
* 项目主键ID
|
* 项目主键ID
|
||||||
* @type {string|number}
|
* @type {string|number}
|
||||||
*/
|
*/
|
||||||
projectID: string|number;
|
projectID: string | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上级分组主键,最顶层是0
|
* 上级分组主键,最顶层是0
|
||||||
* @type {string|number}
|
* @type {string|number}
|
||||||
*/
|
*/
|
||||||
parentID?: string|number;
|
parentID?: string | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分组排序号
|
* 分组排序号
|
||||||
@ -391,6 +390,10 @@ export interface ApiData extends StorageModel {
|
|||||||
* @type {JsonRootType|string}
|
* @type {JsonRootType|string}
|
||||||
*/
|
*/
|
||||||
responseBodyJsonType?: JsonRootType | string;
|
responseBodyJsonType?: JsonRootType | string;
|
||||||
|
/**
|
||||||
|
* mock列表
|
||||||
|
*/
|
||||||
|
mockList?: ApiEditMock[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -450,6 +453,18 @@ export interface ParamsEnum {
|
|||||||
*/
|
*/
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ApiEditMock = {
|
||||||
|
/** mock名称 */
|
||||||
|
name: string;
|
||||||
|
/** mock地址 */
|
||||||
|
url: string;
|
||||||
|
/** mock返回值 */
|
||||||
|
response: string;
|
||||||
|
/** 是否系统默认mock */
|
||||||
|
isDefault?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export interface BasiApiEditParams {
|
export interface BasiApiEditParams {
|
||||||
/**
|
/**
|
||||||
* 参数名
|
* 参数名
|
||||||
@ -512,56 +527,59 @@ export interface ApiEditBody extends BasiApiEditParams {
|
|||||||
export interface StorageInterface {
|
export interface StorageInterface {
|
||||||
// Project
|
// Project
|
||||||
projectCreate: (item: Project) => Observable<object>;
|
projectCreate: (item: Project) => Observable<object>;
|
||||||
projectUpdate: (item: Project, uuid: number|string) => Observable<object>;
|
projectUpdate: (item: Project, uuid: number | string) => Observable<object>;
|
||||||
projectBulkUpdate: (items: Array<Project>) => Observable<object>;
|
projectBulkUpdate: (items: Array<Project>) => Observable<object>;
|
||||||
projectRemove: (uuid: number|string) => Observable<boolean>;
|
projectRemove: (uuid: number | string) => Observable<boolean>;
|
||||||
projectBulkRemove: (uuids: Array<number|string>) => Observable<boolean>;
|
projectBulkRemove: (uuids: Array<number | string>) => Observable<boolean>;
|
||||||
projectLoad: (uuid: number|string) => Observable<object>;
|
projectLoad: (uuid: number | string) => Observable<object>;
|
||||||
projectBulkLoad: (uuids: Array<number|string>) => Observable<Array<object>>;
|
projectBulkLoad: (uuids: Array<number | string>) => Observable<Array<object>>;
|
||||||
projectExport: () => Observable<object>;
|
projectExport: () => Observable<object>;
|
||||||
// Environment
|
// Environment
|
||||||
environmentCreate: (item: Environment) => Observable<object>;
|
environmentCreate: (item: Environment) => Observable<object>;
|
||||||
environmentUpdate: (item: Environment, uuid: number|string) => Observable<object>;
|
environmentUpdate: (item: Environment, uuid: number | string) => Observable<object>;
|
||||||
environmentBulkCreate: (items: Array<Environment>) => Observable<object>;
|
environmentBulkCreate: (items: Array<Environment>) => Observable<object>;
|
||||||
environmentBulkUpdate: (items: Array<Environment>) => Observable<object>;
|
environmentBulkUpdate: (items: Array<Environment>) => Observable<object>;
|
||||||
environmentRemove: (uuid: number|string) => Observable<boolean>;
|
environmentRemove: (uuid: number | string) => Observable<boolean>;
|
||||||
environmentBulkRemove: (uuids: Array<number|string>) => Observable<boolean>;
|
environmentBulkRemove: (uuids: Array<number | string>) => Observable<boolean>;
|
||||||
environmentLoad: (uuid: number|string) => Observable<object>;
|
environmentLoad: (uuid: number | string) => Observable<object>;
|
||||||
environmentBulkLoad: (uuids: Array<number|string>) => Observable<Array<object>>;
|
environmentBulkLoad: (uuids: Array<number | string>) => Observable<Array<object>>;
|
||||||
environmentLoadAllByProjectID: (projectID: number|string) => Observable<Array<object>>;
|
environmentLoadAllByProjectID: (projectID: number | string) => Observable<Array<object>>;
|
||||||
// Group
|
// Group
|
||||||
groupCreate: (item: Group) => Observable<object>;
|
groupCreate: (item: Group) => Observable<object>;
|
||||||
groupUpdate: (item: Group, uuid: number|string) => Observable<object>;
|
groupUpdate: (item: Group, uuid: number | string) => Observable<object>;
|
||||||
groupBulkCreate: (items: Array<Group>) => Observable<object>;
|
groupBulkCreate: (items: Array<Group>) => Observable<object>;
|
||||||
groupBulkUpdate: (items: Array<Group>) => Observable<object>;
|
groupBulkUpdate: (items: Array<Group>) => Observable<object>;
|
||||||
groupRemove: (uuid: number|string) => Observable<boolean>;
|
groupRemove: (uuid: number | string) => Observable<boolean>;
|
||||||
groupBulkRemove: (uuids: Array<number|string>) => Observable<boolean>;
|
groupBulkRemove: (uuids: Array<number | string>) => Observable<boolean>;
|
||||||
groupLoad: (uuid: number|string) => Observable<object>;
|
groupLoad: (uuid: number | string) => Observable<object>;
|
||||||
groupBulkLoad: (uuids: Array<number|string>) => Observable<Array<object>>;
|
groupBulkLoad: (uuids: Array<number | string>) => Observable<Array<object>>;
|
||||||
groupLoadAllByProjectID: (projectID: number|string) => Observable<Array<object>>;
|
groupLoadAllByProjectID: (projectID: number | string) => Observable<Array<object>>;
|
||||||
// Api Data
|
// Api Data
|
||||||
apiDataCreate: (item: ApiData) => Observable<object>;
|
apiDataCreate: (item: ApiData) => Observable<object>;
|
||||||
apiDataUpdate: (item: ApiData, uuid: number|string) => Observable<object>;
|
apiDataUpdate: (item: ApiData, uuid: number | string) => Observable<object>;
|
||||||
apiDataBulkCreate: (items: Array<ApiData>) => Observable<object>;
|
apiDataBulkCreate: (items: Array<ApiData>) => Observable<object>;
|
||||||
apiDataBulkUpdate: (items: Array<ApiData>) => Observable<object>;
|
apiDataBulkUpdate: (items: Array<ApiData>) => Observable<object>;
|
||||||
apiDataRemove: (uuid: number|string) => Observable<boolean>;
|
apiDataRemove: (uuid: number | string) => Observable<boolean>;
|
||||||
apiDataBulkRemove: (uuids: Array<number|string>) => Observable<boolean>;
|
apiDataBulkRemove: (uuids: Array<number | string>) => Observable<boolean>;
|
||||||
apiDataLoad: (uuid: number|string) => Observable<object>;
|
apiDataLoad: (uuid: number | string) => Observable<object>;
|
||||||
apiDataBulkLoad: (uuids: Array<number|string>) => Observable<Array<object>>;
|
apiDataBulkLoad: (uuids: Array<number | string>) => Observable<Array<object>>;
|
||||||
apiDataLoadAllByProjectID: (projectID: number|string) => Observable<Array<object>>;
|
apiDataLoadAllByProjectID: (projectID: number | string) => Observable<Array<object>>;
|
||||||
apiDataLoadAllByGroupID: (groupID: number|string) => Observable<Array<object>>;
|
apiDataLoadAllByGroupID: (groupID: number | string) => Observable<Array<object>>;
|
||||||
apiDataLoadAllByProjectIDAndGroupID: (projectID: number|string, groupID: number|string) => Observable<Array<object>>;
|
apiDataLoadAllByProjectIDAndGroupID: (
|
||||||
|
projectID: number | string,
|
||||||
|
groupID: number | string
|
||||||
|
) => Observable<Array<object>>;
|
||||||
// Api Test History
|
// Api Test History
|
||||||
apiTestHistoryCreate: (item: ApiTestHistory) => Observable<object>;
|
apiTestHistoryCreate: (item: ApiTestHistory) => Observable<object>;
|
||||||
apiTestHistoryUpdate: (item: ApiTestHistory, uuid: number|string) => Observable<object>;
|
apiTestHistoryUpdate: (item: ApiTestHistory, uuid: number | string) => Observable<object>;
|
||||||
apiTestHistoryBulkCreate: (items: Array<ApiTestHistory>) => Observable<object>;
|
apiTestHistoryBulkCreate: (items: Array<ApiTestHistory>) => Observable<object>;
|
||||||
apiTestHistoryBulkUpdate: (items: Array<ApiTestHistory>) => Observable<object>;
|
apiTestHistoryBulkUpdate: (items: Array<ApiTestHistory>) => Observable<object>;
|
||||||
apiTestHistoryRemove: (uuid: number|string) => Observable<boolean>;
|
apiTestHistoryRemove: (uuid: number | string) => Observable<boolean>;
|
||||||
apiTestHistoryBulkRemove: (uuids: Array<number|string>) => Observable<boolean>;
|
apiTestHistoryBulkRemove: (uuids: Array<number | string>) => Observable<boolean>;
|
||||||
apiTestHistoryLoad: (uuid: number|string) => Observable<object>;
|
apiTestHistoryLoad: (uuid: number | string) => Observable<object>;
|
||||||
apiTestHistoryBulkLoad: (uuids: Array<number|string>) => Observable<Array<object>>;
|
apiTestHistoryBulkLoad: (uuids: Array<number | string>) => Observable<Array<object>>;
|
||||||
apiTestHistoryLoadAllByProjectID: (projectID: number|string) => Observable<Array<object>>;
|
apiTestHistoryLoadAllByProjectID: (projectID: number | string) => Observable<Array<object>>;
|
||||||
apiTestHistoryLoadAllByApiDataID: (apiDataID: number|string) => Observable<Array<object>>;
|
apiTestHistoryLoadAllByApiDataID: (apiDataID: number | string) => Observable<Array<object>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StorageItem = Project | Environment | Group | ApiData | ApiTestHistory;
|
export type StorageItem = Project | Environment | Group | ApiData | ApiTestHistory;
|
||||||
@ -583,11 +601,11 @@ export enum StorageHandleStatus {
|
|||||||
success = 'success',
|
success = 'success',
|
||||||
empty = 'empty',
|
empty = 'empty',
|
||||||
error = 'error',
|
error = 'error',
|
||||||
invalid = 'invalid'
|
invalid = 'invalid',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum StorageProcessType {
|
export enum StorageProcessType {
|
||||||
default = 'default',
|
default = 'default',
|
||||||
remote = 'remote',
|
remote = 'remote',
|
||||||
sync = 'sync'
|
sync = 'sync',
|
||||||
}
|
}
|
||||||
|
@ -147,3 +147,22 @@ window.eo.getSettings = (settings) => {
|
|||||||
window.eo.getModuleSettings = (moduleID) => {
|
window.eo.getModuleSettings = (moduleID) => {
|
||||||
return ipcRenderer.sendSync('eo-sync', { action: 'getModuleSettings', data: { moduleID: moduleID } });
|
return ipcRenderer.sendSync('eo-sync', { action: 'getModuleSettings', data: { moduleID: moduleID } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 注册单个mock路由
|
||||||
|
window.eo.registerMockRoute = ({ method, path, data }) => {
|
||||||
|
return ipcRenderer.sendSync('eo-sync', { action: 'registerMockRoute', data: { method, path, data } });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 注销mock路由
|
||||||
|
window.eo.unRegisterMockRoute = ({ method, path }) => {
|
||||||
|
return ipcRenderer.sendSync('eo-sync', { action: 'unRegisterMockRoute', data: { method, path } });
|
||||||
|
};
|
||||||
|
// 获取mock服务地址
|
||||||
|
window.eo.getMockUrl = () => {
|
||||||
|
return ipcRenderer.sendSync('eo-sync', { action: 'getMockUrl' });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置并初始化路由
|
||||||
|
window.eo.resetAndInitRoutes = () => {
|
||||||
|
return ipcRenderer.sendSync('eo-sync', { action: 'resetAndInitRoutes' });
|
||||||
|
};
|
||||||
|
@ -59,7 +59,7 @@ export class Configuration implements ConfigurationInterface {
|
|||||||
data.nestedSettings ??= {};
|
data.nestedSettings ??= {};
|
||||||
data.settings[moduleID] = settings;
|
data.settings[moduleID] = settings;
|
||||||
const propArr = moduleID.split('.');
|
const propArr = moduleID.split('.');
|
||||||
const target = propArr.slice(0, -1).reduce((p, k) => p[k], data.nestedSettings);
|
const target = propArr.slice(0, -1).reduce((p, k) => p?.[k], data.nestedSettings);
|
||||||
target[propArr.at(-1)] = settings;
|
target[propArr.at(-1)] = settings;
|
||||||
return this.saveConfig(data);
|
return this.saveConfig(data);
|
||||||
}
|
}
|
||||||
|
53
src/platform/node/mock-server/index copy.ts
Normal file
53
src/platform/node/mock-server/index copy.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
const Koa = require('koa');
|
||||||
|
const Router = require('koa-router');
|
||||||
|
const glob = require('glob');
|
||||||
|
const logger = require('koa-logger');
|
||||||
|
const { resolve } = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const app = new Koa();
|
||||||
|
const router = new Router({ prefix: '/api' });
|
||||||
|
const routerMap = {}; // 存放路由映射
|
||||||
|
|
||||||
|
app.use(logger());
|
||||||
|
|
||||||
|
// 注册路由
|
||||||
|
glob.sync(resolve('./api', '**/*.json')).forEach((item, i) => {
|
||||||
|
let apiJsonPath = item && item.split('/api')[1];
|
||||||
|
let apiPath = apiJsonPath.replace('.json', '');
|
||||||
|
|
||||||
|
router.get(apiPath, (ctx, next) => {
|
||||||
|
try {
|
||||||
|
let jsonStr = fs.readFileSync(item).toString();
|
||||||
|
ctx.body = {
|
||||||
|
data: JSON.parse(jsonStr),
|
||||||
|
state: 200,
|
||||||
|
type: 'success', // 自定义响应体
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
ctx.throw('服务器错误', 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 记录路由
|
||||||
|
routerMap[apiJsonPath] = apiPath;
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFile('./routerMap.json', JSON.stringify(routerMap, null, 4), (err) => {
|
||||||
|
if (!err) {
|
||||||
|
console.log('路由地图生成成功!');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
|
|
||||||
|
app.listen(3040);
|
||||||
|
// const Koa = require('koa');
|
||||||
|
// const app = new Koa();
|
||||||
|
|
||||||
|
// app.use(async (ctx) => {
|
||||||
|
// ctx.body = 'hello koa2';
|
||||||
|
// });
|
||||||
|
|
||||||
|
// app.listen(3000);
|
||||||
|
// console.log('[demo] start-quick is starting at port 3000');
|
146
src/platform/node/mock-server/index.ts
Normal file
146
src/platform/node/mock-server/index.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import Koa from 'koa';
|
||||||
|
import Router from '@koa/router';
|
||||||
|
import cors from '@koa/cors';
|
||||||
|
import bodyParser from 'koa-bodyparser';
|
||||||
|
import portfinder from 'portfinder';
|
||||||
|
import mockjs from 'mockjs';
|
||||||
|
|
||||||
|
export class MockServer {
|
||||||
|
private app: Koa;
|
||||||
|
private router: Router;
|
||||||
|
/** mock服务地址 */
|
||||||
|
private mockUrl = '';
|
||||||
|
|
||||||
|
constructor(prefix = '') {
|
||||||
|
this.app = new Koa();
|
||||||
|
this.router = new Router({ prefix });
|
||||||
|
|
||||||
|
// 使用ctx.body解析中间件
|
||||||
|
this.app.use(bodyParser());
|
||||||
|
// 加载路由中间件
|
||||||
|
this.app.use(this.router.routes()).use(this.router.allowedMethods());
|
||||||
|
// 允许跨域请求
|
||||||
|
this.app.use(cors());
|
||||||
|
this.initRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动mock服务
|
||||||
|
* @param port mock服务端口号
|
||||||
|
*/
|
||||||
|
async start(port = 3040) {
|
||||||
|
portfinder.basePort = port;
|
||||||
|
// 使用 portfinder 做端口检测,若发现端口被占用则端口自增1
|
||||||
|
const _port = await portfinder.getPortPromise();
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.app
|
||||||
|
.listen(_port, () => {
|
||||||
|
this.mockUrl = `http://localhost:${_port}`;
|
||||||
|
console.log(`mock服务已启动: ${this.mockUrl}`);
|
||||||
|
resolve(this.mockUrl);
|
||||||
|
})
|
||||||
|
.on('error', (error) => {
|
||||||
|
console.error('mock服务启动失败: ' + error);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终止mock服务
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取mock服务地址
|
||||||
|
* @returns mock服务地址
|
||||||
|
*/
|
||||||
|
getMockUrl() {
|
||||||
|
return this.mockUrl;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 重置\清空 路由
|
||||||
|
*/
|
||||||
|
resetRoutes() {
|
||||||
|
this.router.stack = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置\清空 并初始化路由
|
||||||
|
*/
|
||||||
|
resetAndInitRoutes() {
|
||||||
|
this.resetRoutes();
|
||||||
|
this.initRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册路由
|
||||||
|
* @param method 请求方法
|
||||||
|
* @param path 请求路径
|
||||||
|
* @param data 响应的数据
|
||||||
|
*/
|
||||||
|
registerRoute(method: string, path: string, data = {}) {
|
||||||
|
const { pathname, search } = new URL(path, this.mockUrl);
|
||||||
|
// Object.fromEntries(searchParams.entries())
|
||||||
|
// console.log('registerRoute', method.toLocaleLowerCase(), pathname + search);
|
||||||
|
this.router[method.toLocaleLowerCase()](pathname + search, async (ctx, next) => {
|
||||||
|
try {
|
||||||
|
const mockData = typeof data === 'string' ? JSON.parse(data) : data;
|
||||||
|
ctx.body = mockjs.mock(mockData);
|
||||||
|
} catch (e) {
|
||||||
|
ctx.body = {
|
||||||
|
tips: '返回数据格式有误,请检查!',
|
||||||
|
errorMsg: e.message,
|
||||||
|
originData: data,
|
||||||
|
};
|
||||||
|
ctx.status = 500;
|
||||||
|
}
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注销路由
|
||||||
|
* @param methods 请求方法
|
||||||
|
* @param path 请求路径
|
||||||
|
*/
|
||||||
|
unRegisterRoute(methods: string[], path: string) {
|
||||||
|
const _methods = methods.map((n) => n.toLocaleUpperCase());
|
||||||
|
// 将匹配到的路由注销掉
|
||||||
|
this.router.stack = this.router.stack.filter((item) => {
|
||||||
|
const isMatch = item.methods.some((n) => _methods.includes(n)) && item.path === path;
|
||||||
|
return !isMatch;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化默认路由
|
||||||
|
*/
|
||||||
|
initRoutes() {
|
||||||
|
this.router.get('/', async (ctx, next) => {
|
||||||
|
const mockPeople = mockjs.mock({
|
||||||
|
'peoples|10': [
|
||||||
|
{
|
||||||
|
'id|+1': 1,
|
||||||
|
guid: '@guid',
|
||||||
|
name: '@cname',
|
||||||
|
age: '@integer(20, 50)',
|
||||||
|
birthday: '@date("MM-dd")',
|
||||||
|
address: '@county(true)',
|
||||||
|
email: '@email',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
ctx.body = mockPeople;
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.router.get('/mock_stack', async (ctx, next) => {
|
||||||
|
ctx.body = this.router;
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -20,13 +20,11 @@
|
|||||||
<div *ngIf="apiData.requestBody?.length">
|
<div *ngIf="apiData.requestBody?.length">
|
||||||
<div class="api_line">
|
<div class="api_line">
|
||||||
Body 请求参数<nz-tag class="ml10" nzColor="default">{{ CONST.BODY_TYPE[apiData.requestBodyType] }}</nz-tag>
|
Body 请求参数<nz-tag class="ml10" nzColor="default">{{ CONST.BODY_TYPE[apiData.requestBodyType] }}</nz-tag>
|
||||||
<nz-tag *ngIf="apiData.requestBodyType==='json'" nzColor="default">最外层结构为:{{ CONST.JSON_ROOT_TYPE[apiData.requestBodyJsonType] }}</nz-tag>
|
<nz-tag *ngIf="apiData.requestBodyType==='json'" nzColor="default">最外层结构为:{{
|
||||||
|
CONST.JSON_ROOT_TYPE[apiData.requestBodyJsonType] }}</nz-tag>
|
||||||
</div>
|
</div>
|
||||||
<eo-api-detail-body
|
<eo-api-detail-body [bodyType]="apiData.requestBodyType" [model]="apiData.requestBody"
|
||||||
[bodyType]="apiData.requestBodyType"
|
[jsonRootType]="apiData.requestBodyJsonType"></eo-api-detail-body>
|
||||||
[model]="apiData.requestBody"
|
|
||||||
[jsonRootType]="apiData.requestBodyJsonType"
|
|
||||||
></eo-api-detail-body>
|
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="apiData.responseHeaders && apiData.responseHeaders.length">
|
<div *ngIf="apiData.responseHeaders && apiData.responseHeaders.length">
|
||||||
<p class="api_line">返回头部</p>
|
<p class="api_line">返回头部</p>
|
||||||
@ -34,10 +32,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div *ngIf="apiData.responseBody && apiData.responseBody.length">
|
<div *ngIf="apiData.responseBody && apiData.responseBody.length">
|
||||||
<p class="api_line">返回参数</p>
|
<p class="api_line">返回参数</p>
|
||||||
<eo-api-detail-body
|
<eo-api-detail-body [bodyType]="apiData.responseBodyType" [model]="apiData.responseBody"
|
||||||
[bodyType]="apiData.responseBodyType"
|
[jsonRootType]="apiData.responseBodyJsonType"></eo-api-detail-body>
|
||||||
[model]="apiData.responseBody"
|
</div>
|
||||||
[jsonRootType]="apiData.responseBodyJsonType"
|
<div>
|
||||||
></eo-api-detail-body>
|
<p class="api_line">MOCK </p>
|
||||||
|
<eo-api-detail-mock [model]="apiData.mockList"></eo-api-detail-mock>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
border-left: 3px solid var(--GREEN_NORMAL);
|
||||||
|
text-indent: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-1 {
|
.t-1 {
|
||||||
|
@ -9,38 +9,30 @@ import { SharedModule } from '../../../shared/shared.module';
|
|||||||
import { NzButtonModule } from 'ng-zorro-antd/button';
|
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||||
import { NzIconModule } from 'ng-zorro-antd/icon';
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
||||||
import { NzTagModule } from 'ng-zorro-antd/tag';
|
import { NzTagModule } from 'ng-zorro-antd/tag';
|
||||||
|
import { NzModalModule } from 'ng-zorro-antd/modal';
|
||||||
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||||
|
|
||||||
import { ApiDetailComponent } from './api-detail.component';
|
import { ApiDetailComponent } from './api-detail.component';
|
||||||
import { ApiDetailHeaderComponent } from './header/api-detail-header.component';
|
import { ApiDetailHeaderComponent } from './header/api-detail-header.component';
|
||||||
import { ApiDetailBodyComponent } from './body/api-detail-body.component';
|
import { ApiDetailBodyComponent } from './body/api-detail-body.component';
|
||||||
import { ApiDetailQueryComponent } from './query/api-detail-query.component';
|
import { ApiDetailQueryComponent } from './query/api-detail-query.component';
|
||||||
import { ApiDetailRestComponent } from './rest/api-detail-rest.component';
|
import { ApiDetailRestComponent } from './rest/api-detail-rest.component';
|
||||||
|
import { ApiDetailMockComponent } from './mock/api-detail-mock.component';
|
||||||
|
|
||||||
import { ApiDetailService } from './api-detail.service';
|
import { ApiDetailService } from './api-detail.service';
|
||||||
|
|
||||||
const NZ_COMPONETS = [
|
const NZ_COMPONETS = [NzButtonModule, NzIconModule, NzTagModule, NzModalModule, NzFormModule];
|
||||||
NzButtonModule,
|
|
||||||
NzIconModule,
|
|
||||||
NzTagModule
|
|
||||||
];
|
|
||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
ApiDetailComponent,
|
ApiDetailComponent,
|
||||||
ApiDetailHeaderComponent,
|
ApiDetailHeaderComponent,
|
||||||
ApiDetailBodyComponent,
|
ApiDetailBodyComponent,
|
||||||
ApiDetailQueryComponent,
|
ApiDetailQueryComponent,
|
||||||
ApiDetailRestComponent
|
ApiDetailRestComponent,
|
||||||
|
ApiDetailMockComponent,
|
||||||
];
|
];
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [...COMPONENTS],
|
declarations: [...COMPONENTS],
|
||||||
imports: [
|
imports: [FormsModule, ReactiveFormsModule, Ng1Module, CommonModule, ...NZ_COMPONETS, EouiModule, SharedModule],
|
||||||
FormsModule,
|
providers: [ApiDetailService],
|
||||||
ReactiveFormsModule,
|
|
||||||
Ng1Module,
|
|
||||||
CommonModule,
|
|
||||||
...NZ_COMPONETS,
|
|
||||||
EouiModule,
|
|
||||||
SharedModule,
|
|
||||||
],
|
|
||||||
providers:[ApiDetailService]
|
|
||||||
})
|
})
|
||||||
export class ApiDetailModule {}
|
export class ApiDetailModule {}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
<eo-table [(model)]="model" [columns]="mockListColumns" [dataModel]="{ name: '', value: '', description: '' }">
|
||||||
|
<ng-template cell="url" let-scope="scope" let-index="index">
|
||||||
|
<span>{{ scope.url }}</span>
|
||||||
|
</ng-template>
|
||||||
|
</eo-table>
|
@ -0,0 +1,27 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ModalService } from '../../../../shared/services/modal.service';
|
||||||
|
import { ApiDetailService } from '../api-detail.service';
|
||||||
|
|
||||||
|
import { ApiDetailHeaderComponent } from './api-detail-mock.component';
|
||||||
|
|
||||||
|
describe('ApiDetailHeaderComponent', () => {
|
||||||
|
let component: ApiDetailHeaderComponent;
|
||||||
|
let fixture: ComponentFixture<ApiDetailHeaderComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
providers: [ApiDetailService, { provide: ModalService, useValue: {} }],
|
||||||
|
declarations: [ApiDetailHeaderComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ApiDetailHeaderComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,27 @@
|
|||||||
|
import { Component, Input, OnChanges } from '@angular/core';
|
||||||
|
import { ApiEditMock } from 'eo/platform/browser/IndexedDB';
|
||||||
|
import { ApiDetailService } from '../api-detail.service';
|
||||||
|
@Component({
|
||||||
|
selector: 'eo-api-detail-mock',
|
||||||
|
templateUrl: './api-detail-mock.component.html',
|
||||||
|
styleUrls: ['./api-detail-mock.component.scss'],
|
||||||
|
})
|
||||||
|
export class ApiDetailMockComponent implements OnChanges {
|
||||||
|
@Input() model: ApiEditMock[] = [];
|
||||||
|
listConf: object = {};
|
||||||
|
isVisible = false;
|
||||||
|
mockListColumns = [
|
||||||
|
{ title: '名称', key: 'name' },
|
||||||
|
{ title: 'URL', slot: 'url' },
|
||||||
|
];
|
||||||
|
constructor(private detailService: ApiDetailService) {}
|
||||||
|
|
||||||
|
ngOnChanges(changes) {
|
||||||
|
// if (changes.model&&!changes.model.previousValue&&changes.model.currentValue) {
|
||||||
|
// this.model.push(Object.assign({}, this.itemStructure));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEditMockItem(index: number) {}
|
||||||
|
handleDeleteMockItem(index: number) {}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<eo-message></eo-message>
|
<eo-message></eo-message>
|
||||||
<div class="!pt-0 p15">
|
<nz-collapse class="!pt-0 p15">
|
||||||
<div class="sticky top-0 z-10 pt-6 bg-white">
|
<div class="sticky top-0 z-10 pt-6 bg-white">
|
||||||
<button type="submit" nz-button nztype="primary" class="eo_theme_btn_success" (click)="saveApi()">保存</button>
|
<button type="submit" nz-button nztype="primary" class="eo_theme_btn_success" (click)="saveApi()">保存</button>
|
||||||
<nz-divider></nz-divider>
|
<nz-divider></nz-divider>
|
||||||
@ -122,4 +122,8 @@
|
|||||||
</nz-tabset>
|
</nz-tabset>
|
||||||
</nz-collapse-panel>
|
</nz-collapse-panel>
|
||||||
</nz-collapse>
|
</nz-collapse>
|
||||||
</div>
|
<!-- mock -->
|
||||||
|
<nz-collapse class="eo_collapse mt40" [nzGhost]="true" *ngIf="electron.isElectron">
|
||||||
|
<p class="api_line">MOCK <a class="text-xs text-blue-500" (click)="openAddMockModal()">+添加</a></p>
|
||||||
|
<eo-api-edit-mock [model]="apiData.mockList"></eo-api-edit-mock>
|
||||||
|
</nz-collapse>
|
||||||
|
@ -30,6 +30,10 @@ import {
|
|||||||
getExpandGroupByKey,
|
getExpandGroupByKey,
|
||||||
} from '../../../utils/tree/tree.utils';
|
} from '../../../utils/tree/tree.utils';
|
||||||
import { ApiParamsNumPipe } from '../../../shared/pipes/api-param-num.pipe';
|
import { ApiParamsNumPipe } from '../../../shared/pipes/api-param-num.pipe';
|
||||||
|
import { tree2obj } from '../../../utils/tree/tree.utils';
|
||||||
|
import { ApiEditMockComponent } from './mock/api-edit-mock.component';
|
||||||
|
import { ElectronService } from 'eo/workbench/browser/src/app/core/services/electron/electron.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'eo-api-edit-edit',
|
selector: 'eo-api-edit-edit',
|
||||||
templateUrl: './api-edit.component.html',
|
templateUrl: './api-edit.component.html',
|
||||||
@ -37,6 +41,7 @@ import { ApiParamsNumPipe } from '../../../shared/pipes/api-param-num.pipe';
|
|||||||
})
|
})
|
||||||
export class ApiEditComponent implements OnInit, OnDestroy {
|
export class ApiEditComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild('apiGroup') apiGroup: NzTreeSelectComponent;
|
@ViewChild('apiGroup') apiGroup: NzTreeSelectComponent;
|
||||||
|
@ViewChild(ApiEditMockComponent) apiEditMockComp: ApiEditMockComponent;
|
||||||
validateForm!: FormGroup;
|
validateForm!: FormGroup;
|
||||||
apiData: ApiData;
|
apiData: ApiData;
|
||||||
groups: any[];
|
groups: any[];
|
||||||
@ -53,7 +58,8 @@ export class ApiEditComponent implements OnInit, OnDestroy {
|
|||||||
private message: EoMessageService,
|
private message: EoMessageService,
|
||||||
private messageService: MessageService,
|
private messageService: MessageService,
|
||||||
private apiTab: ApiTabService,
|
private apiTab: ApiTabService,
|
||||||
private storage: StorageService
|
private storage: StorageService,
|
||||||
|
public electron: ElectronService
|
||||||
) {}
|
) {}
|
||||||
getApiGroup() {
|
getApiGroup() {
|
||||||
this.groups = [];
|
this.groups = [];
|
||||||
@ -88,12 +94,26 @@ export class ApiEditComponent implements OnInit, OnDestroy {
|
|||||||
getApi(id) {
|
getApi(id) {
|
||||||
this.storage.run('apiDataLoad', [id], (result: StorageHandleResult) => {
|
this.storage.run('apiDataLoad', [id], (result: StorageHandleResult) => {
|
||||||
if (result.status === StorageHandleStatus.success) {
|
if (result.status === StorageHandleStatus.success) {
|
||||||
|
this.apiData = result.data;
|
||||||
|
// 如果没有mock,则生成系统默认mock
|
||||||
|
if ((window.eo?.getMockUrl && !Array.isArray(this.apiData.mockList)) || this.apiData.mockList?.length === 0) {
|
||||||
|
const url = new URL(this.apiData.uri, window.eo.getMockUrl());
|
||||||
|
this.apiData.mockList = [
|
||||||
|
{
|
||||||
|
name: '系统默认期望',
|
||||||
|
url: url.toString(),
|
||||||
|
response: JSON.stringify(tree2obj([].concat(this.apiData.responseBody))),
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
['requestBody', 'responseBody'].forEach((tableName) => {
|
['requestBody', 'responseBody'].forEach((tableName) => {
|
||||||
if (['xml', 'json'].includes(result.data[`${tableName}Type`])) {
|
if (['xml', 'json'].includes(result.data[`${tableName}Type`])) {
|
||||||
result.data[tableName] = treeToListHasLevel(result.data[tableName]);
|
result.data[tableName] = treeToListHasLevel(result.data[tableName]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.apiData = result.data;
|
|
||||||
this.changeGroupID$.next(this.apiData.groupID);
|
this.changeGroupID$.next(this.apiData.groupID);
|
||||||
this.validateForm.patchValue(this.apiData);
|
this.validateForm.patchValue(this.apiData);
|
||||||
}
|
}
|
||||||
@ -112,19 +132,26 @@ export class ApiEditComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
const formData: any = Object.assign({}, this.apiData, this.validateForm.value);
|
const formData: any = Object.assign({}, this.apiData, this.validateForm.value);
|
||||||
formData.groupID = Number(formData.groupID === '-1' ? '0' : formData.groupID);
|
formData.groupID = Number(formData.groupID === '-1' ? '0' : formData.groupID);
|
||||||
['requestBody', 'queryParams', 'restParams', 'requestHeaders', 'responseHeaders', 'responseBody'].forEach(
|
[
|
||||||
(tableName) => {
|
'requestBody',
|
||||||
if (typeof this.apiData[tableName] !== 'object') {
|
'queryParams',
|
||||||
return;
|
'restParams',
|
||||||
}
|
'requestHeaders',
|
||||||
formData[tableName] = this.apiData[tableName].filter((val) => val.name);
|
'responseHeaders',
|
||||||
if (['requestBody', 'responseBody'].includes(tableName)) {
|
'responseBody',
|
||||||
if (['xml', 'json'].includes(formData[`${tableName}Type`])) {
|
'mockList',
|
||||||
formData[tableName] = listToTreeHasLevel(formData[tableName]);
|
].forEach((tableName) => {
|
||||||
}
|
if (typeof this.apiData[tableName] !== 'object') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
formData[tableName] = this.apiData[tableName].filter((val) => val.name);
|
||||||
|
if (['requestBody', 'responseBody'].includes(tableName)) {
|
||||||
|
if (['xml', 'json'].includes(formData[`${tableName}Type`])) {
|
||||||
|
formData[tableName] = listToTreeHasLevel(formData[tableName]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
this.editApi(formData);
|
this.editApi(formData);
|
||||||
}
|
}
|
||||||
bindGetApiParamNum(params) {
|
bindGetApiParamNum(params) {
|
||||||
@ -142,6 +169,13 @@ export class ApiEditComponent implements OnInit, OnDestroy {
|
|||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 打开添加mock弹窗
|
||||||
|
*/
|
||||||
|
openAddMockModal() {
|
||||||
|
this.apiEditMockComp.openAddModal();
|
||||||
|
}
|
||||||
|
|
||||||
private initApi(id) {
|
private initApi(id) {
|
||||||
this.resetForm();
|
this.resetForm();
|
||||||
this.initBasicForm();
|
this.initBasicForm();
|
||||||
@ -149,7 +183,6 @@ export class ApiEditComponent implements OnInit, OnDestroy {
|
|||||||
if (this.apiTab.currentTab && this.apiTab.tabCache[this.apiTab.tabID]) {
|
if (this.apiTab.currentTab && this.apiTab.tabCache[this.apiTab.tabID]) {
|
||||||
let tabData = this.apiTab.tabCache[this.apiTab.tabID];
|
let tabData = this.apiTab.tabCache[this.apiTab.tabID];
|
||||||
this.apiData = tabData.apiData;
|
this.apiData = tabData.apiData;
|
||||||
this.validateForm.patchValue(this.apiData);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!id) {
|
if (!id) {
|
||||||
|
@ -20,6 +20,7 @@ import { NzTabsModule } from 'ng-zorro-antd/tabs';
|
|||||||
import { NzRadioModule } from 'ng-zorro-antd/radio';
|
import { NzRadioModule } from 'ng-zorro-antd/radio';
|
||||||
import { NzDividerModule } from 'ng-zorro-antd/divider';
|
import { NzDividerModule } from 'ng-zorro-antd/divider';
|
||||||
import { NzAffixModule } from 'ng-zorro-antd/affix';
|
import { NzAffixModule } from 'ng-zorro-antd/affix';
|
||||||
|
import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
|
||||||
|
|
||||||
import { ApiEditComponent } from './api-edit.component';
|
import { ApiEditComponent } from './api-edit.component';
|
||||||
import { ApiEditHeaderComponent } from './header/api-edit-header.component';
|
import { ApiEditHeaderComponent } from './header/api-edit-header.component';
|
||||||
@ -27,6 +28,7 @@ import { ApiEditBodyComponent } from './body/api-edit-body.component';
|
|||||||
import { ApiEditQueryComponent } from './query/api-edit-query.component';
|
import { ApiEditQueryComponent } from './query/api-edit-query.component';
|
||||||
import { ApiEditRestComponent } from './rest/api-edit-rest.component';
|
import { ApiEditRestComponent } from './rest/api-edit-rest.component';
|
||||||
import { ApiParamsExtraSettingComponent } from './extra-setting/api-params-extra-setting.component';
|
import { ApiParamsExtraSettingComponent } from './extra-setting/api-params-extra-setting.component';
|
||||||
|
import { ApiEditMockComponent } from './mock/api-edit-mock.component';
|
||||||
|
|
||||||
import { ApiEditService } from './api-edit.service';
|
import { ApiEditService } from './api-edit.service';
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ const NZ_COMPONETS = [
|
|||||||
NzRadioModule,
|
NzRadioModule,
|
||||||
NzDividerModule,
|
NzDividerModule,
|
||||||
NzAffixModule,
|
NzAffixModule,
|
||||||
|
NzPopconfirmModule,
|
||||||
];
|
];
|
||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
ApiEditComponent,
|
ApiEditComponent,
|
||||||
@ -52,6 +55,7 @@ const COMPONENTS = [
|
|||||||
ApiEditQueryComponent,
|
ApiEditQueryComponent,
|
||||||
ApiEditRestComponent,
|
ApiEditRestComponent,
|
||||||
ApiParamsExtraSettingComponent,
|
ApiParamsExtraSettingComponent,
|
||||||
|
ApiEditMockComponent,
|
||||||
];
|
];
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [...COMPONENTS],
|
declarations: [...COMPONENTS],
|
||||||
@ -65,6 +69,6 @@ const COMPONENTS = [
|
|||||||
SharedModule,
|
SharedModule,
|
||||||
ParamsImportModule,
|
ParamsImportModule,
|
||||||
],
|
],
|
||||||
providers:[ApiEditService]
|
providers: [ApiEditService],
|
||||||
})
|
})
|
||||||
export class ApiEditModule {}
|
export class ApiEditModule {}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
<eo-table [(model)]="mocklList" [columns]="mockListColumns" [dataModel]="{ name: '', value: '', description: '' }">
|
||||||
|
<ng-template cell="url" let-scope="scope" let-index="index">
|
||||||
|
<span>{{ scope.url }}</span>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template cell="action" let-scope="scope" let-index="index">
|
||||||
|
<div class="flex justify-evenly">
|
||||||
|
<a nz-button nzType="link" *ngIf="scope.name || scope.url" (click)="handleEditMockItem(index)">编辑</a>
|
||||||
|
<a nz-button nzType="link" *ngIf="scope.name || scope.url" nz-popconfirm nzPopconfirmTitle="您确定要删除此mock吗?"
|
||||||
|
nzPopconfirmPlacement="topRight" (nzOnConfirm)="handleDeleteMockItem(index)" [disabled]="scope.isDefault">删除</a>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</eo-table>
|
||||||
|
|
||||||
|
<nz-modal [(nzVisible)]="isVisible" nzWidth="70%" nzTitle="{{this.currentEditMockIndex === -1 ? '添加' : '编辑' }}mock">
|
||||||
|
<section *nzModalContent class="flex">
|
||||||
|
<div class="main-content">
|
||||||
|
<form nz-form nzLayout="vertical">
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label nzFor="currentEditMock.name">mock名称</nz-form-label>
|
||||||
|
<nz-form-control>
|
||||||
|
<input nz-input name="name" type="text" [(ngModel)]="currentEditMock.name" />
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label nzFor="currentEditMock.response">返回值</nz-form-label>
|
||||||
|
<nz-form-control>
|
||||||
|
<eo-editor [(code)]="currentEditMock.response" (codeChange)="rawDataChange()"
|
||||||
|
[eventList]="['type', 'format', 'copy', 'download', 'newTab', 'search', 'replace']"></eo-editor>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<div *nzModalFooter class="footer">
|
||||||
|
<button nz-button nzType="primary" (click)="handleSave()">保存</button>
|
||||||
|
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
|
||||||
|
</div>
|
||||||
|
</nz-modal>
|
@ -0,0 +1,27 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ModalService } from '../../../../shared/services/modal.service';
|
||||||
|
import { ApiDetailService } from '../api-detail.service';
|
||||||
|
|
||||||
|
import { ApiDetailHeaderComponent } from './api-detail-mock.component';
|
||||||
|
|
||||||
|
describe('ApiDetailHeaderComponent', () => {
|
||||||
|
let component: ApiDetailHeaderComponent;
|
||||||
|
let fixture: ComponentFixture<ApiDetailHeaderComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
providers: [ApiDetailService, { provide: ModalService, useValue: {} }],
|
||||||
|
declarations: [ApiDetailHeaderComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ApiDetailHeaderComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,84 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
|
import { ApiEditMock } from 'eo/platform/browser/IndexedDB';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil, debounceTime } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'eo-api-edit-mock',
|
||||||
|
templateUrl: './api-edit-mock.component.html',
|
||||||
|
styleUrls: ['./api-edit-mock.component.scss'],
|
||||||
|
})
|
||||||
|
export class ApiEditMockComponent implements OnChanges {
|
||||||
|
@Input() model: ApiEditMock[] = [];
|
||||||
|
@Output() modelChange: EventEmitter<any> = new EventEmitter();
|
||||||
|
isVisible = false;
|
||||||
|
mockUrl = window.eo?.getMockUrl?.();
|
||||||
|
private $mocklList: ApiEditMock[] = [];
|
||||||
|
get mocklList() {
|
||||||
|
return this.$mocklList;
|
||||||
|
}
|
||||||
|
set mocklList(_) {
|
||||||
|
this.$mocklList = this.model.map((item) => {
|
||||||
|
const { pathname, search } = new URL(item.url, this.mockUrl);
|
||||||
|
item.url = `${new URL(pathname + search, this.mockUrl)}`;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
mockListColumns = [
|
||||||
|
{ title: '名称', key: 'name' },
|
||||||
|
{ title: 'URL', slot: 'url' },
|
||||||
|
{ title: '', slot: 'action', width: '15%' },
|
||||||
|
];
|
||||||
|
/** 当前被编辑的mock */
|
||||||
|
currentEditMock: ApiEditMock;
|
||||||
|
/** 当前被编辑的mock索引 */
|
||||||
|
currentEditMockIndex = -1;
|
||||||
|
private destroy$: Subject<void> = new Subject<void>();
|
||||||
|
private rawChange$: Subject<string> = new Subject<string>();
|
||||||
|
constructor() {
|
||||||
|
this.rawChange$.pipe(debounceTime(700), takeUntil(this.destroy$)).subscribe(() => {});
|
||||||
|
this.mocklList = [...this.model];
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
const { model } = changes;
|
||||||
|
|
||||||
|
if (model.currentValue) {
|
||||||
|
this.mocklList = [...this.model];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rawDataChange() {
|
||||||
|
this.rawChange$.next(this.currentEditMock.response);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEditMockItem(index: number) {
|
||||||
|
this.currentEditMock = { ...this.model[index] };
|
||||||
|
this.currentEditMockIndex = index;
|
||||||
|
this.isVisible = true;
|
||||||
|
}
|
||||||
|
handleDeleteMockItem(index: number) {
|
||||||
|
this.model.splice(index, 1);
|
||||||
|
this.mocklList = [...this.model];
|
||||||
|
}
|
||||||
|
handleSave() {
|
||||||
|
this.isVisible = false;
|
||||||
|
this.currentEditMockIndex === -1
|
||||||
|
? this.model.push(this.currentEditMock)
|
||||||
|
: (this.model[this.currentEditMockIndex] = this.currentEditMock);
|
||||||
|
this.mocklList = [...this.model];
|
||||||
|
this.modelChange.emit([...this.model]);
|
||||||
|
}
|
||||||
|
handleCancel() {
|
||||||
|
this.isVisible = false;
|
||||||
|
}
|
||||||
|
openAddModal() {
|
||||||
|
this.currentEditMockIndex = -1;
|
||||||
|
this.isVisible = true;
|
||||||
|
this.currentEditMock = {
|
||||||
|
url: this.model.at(0).url,
|
||||||
|
name: '',
|
||||||
|
response: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ import { NzTreeComponent } from 'ng-zorro-antd/tree';
|
|||||||
import { ModalService } from '../../../../shared/services/modal.service';
|
import { ModalService } from '../../../../shared/services/modal.service';
|
||||||
import { StorageService } from '../../../../shared/services/storage';
|
import { StorageService } from '../../../../shared/services/storage';
|
||||||
import { ElectronService } from '../../../../core/services';
|
import { ElectronService } from '../../../../core/services';
|
||||||
|
import { tree2obj } from '../../../../utils/tree/tree.utils';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'eo-api-group-tree',
|
selector: 'eo-api-group-tree',
|
||||||
templateUrl: './api-group-tree.component.html',
|
templateUrl: './api-group-tree.component.html',
|
||||||
@ -114,11 +115,16 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
getApis() {
|
getApis() {
|
||||||
|
// 注册mock路由
|
||||||
|
const registerMockRoute = window.eo?.registerMockRoute;
|
||||||
|
// 重置并初始化路由
|
||||||
|
window.eo?.resetAndInitRoutes?.();
|
||||||
|
|
||||||
this.storage.run('apiDataLoadAllByProjectID', [this.projectID], (result: StorageHandleResult) => {
|
this.storage.run('apiDataLoadAllByProjectID', [this.projectID], (result: StorageHandleResult) => {
|
||||||
const { success, empty } = StorageHandleStatus;
|
const { success, empty } = StorageHandleStatus;
|
||||||
if ([success, empty].includes(result.status)) {
|
if ([success, empty].includes(result.status)) {
|
||||||
let apiItems = {};
|
let apiItems = {};
|
||||||
result.data.forEach((item) => {
|
result.data.forEach((item: ApiData) => {
|
||||||
delete item.updatedAt;
|
delete item.updatedAt;
|
||||||
apiItems[item.uuid] = item;
|
apiItems[item.uuid] = item;
|
||||||
this.treeItems.push({
|
this.treeItems.push({
|
||||||
@ -129,6 +135,21 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
|
|||||||
method: item.method,
|
method: item.method,
|
||||||
isLeaf: true,
|
isLeaf: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.electron.isElectron && registerMockRoute) {
|
||||||
|
if (Array.isArray(item.mockList) && item.mockList.length > 0) {
|
||||||
|
item.mockList.forEach((n) => {
|
||||||
|
registerMockRoute({ method: item.method, path: n.url, data: n.response });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
registerMockRoute({
|
||||||
|
method: item.method,
|
||||||
|
path: item.uri,
|
||||||
|
data: tree2obj(item.responseBody as any[]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// console.log('registerMockRoute', { method: item.method, path: item.uri, data: tree2obj(item.responseBody) });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.apiDataItems = apiItems;
|
this.apiDataItems = apiItems;
|
||||||
this.messageService.send({ type: 'loadApi', data: this.apiDataItems });
|
this.messageService.send({ type: 'loadApi', data: this.apiDataItems });
|
||||||
@ -136,6 +157,7 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
|
|||||||
this.generateGroupTreeData();
|
this.generateGroupTreeData();
|
||||||
this.restoreExpandStatus();
|
this.restoreExpandStatus();
|
||||||
}
|
}
|
||||||
|
console.log('result', result.data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
restoreExpandStatus() {
|
restoreExpandStatus() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
(nzSelectChange)="pickTab()" [nzTabBarExtraContent]="extraTemplate">
|
(nzSelectChange)="pickTab()" [nzTabBarExtraContent]="extraTemplate">
|
||||||
<nz-tab *ngFor="let tab of tabSerive.tabs; let i = index" nzClosable [nzTitle]="titleTemplate">
|
<nz-tab *ngFor="let tab of tabSerive.tabs; let i = index" nzClosable [nzTitle]="titleTemplate">
|
||||||
<ng-template #titleTemplate>
|
<ng-template #titleTemplate>
|
||||||
<span class="mr5 method_text method_text_{{ tab.method }}" *ngIf="tab.method">{{ tab.method }}</span>
|
<span class="mr5 method_text_{{ tab.method }}" *ngIf="tab.method">{{ tab.method }}</span>
|
||||||
<span class="text_omit tab_text"> {{ tab.title }}</span>
|
<span class="text_omit tab_text"> {{ tab.title }}</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</nz-tab>
|
</nz-tab>
|
||||||
|
@ -90,7 +90,7 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
restoreHistory(item) {
|
restoreHistory(item) {
|
||||||
let result = this.apiTest.getTestDataFromHistory(item);
|
let result = this.apiTest.getTestDataFromHistory(item);
|
||||||
console.log('restoreHistory',result)
|
console.log('restoreHistory', result);
|
||||||
//restore request
|
//restore request
|
||||||
this.apiData = result.testData;
|
this.apiData = result.testData;
|
||||||
this.changeUri();
|
this.changeUri();
|
||||||
@ -173,7 +173,7 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
|||||||
* Receive Test Server Message
|
* Receive Test Server Message
|
||||||
*/
|
*/
|
||||||
private receiveMessage(message) {
|
private receiveMessage(message) {
|
||||||
console.log('receiveMessage',message);
|
console.log('receiveMessage', message);
|
||||||
let tmpHistory = {
|
let tmpHistory = {
|
||||||
general: message.general,
|
general: message.general,
|
||||||
request: message.report.request,
|
request: message.report.request,
|
||||||
|
@ -152,7 +152,7 @@ export class SettingComponent implements OnInit {
|
|||||||
* 解析所有模块的配置信息
|
* 解析所有模块的配置信息
|
||||||
*/
|
*/
|
||||||
private init() {
|
private init() {
|
||||||
if (!window.eo && !window.eo.getFeature) return;
|
if (!window.eo && !window.eo?.getFeature) return;
|
||||||
this.isVisible = true;
|
this.isVisible = true;
|
||||||
this.settings = {};
|
this.settings = {};
|
||||||
this.nestedSettings = {};
|
this.nestedSettings = {};
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import { GroupTreeItem } from '../../shared/models';
|
import { GroupTreeItem } from '../../shared/models';
|
||||||
|
|
||||||
|
export type TreeToObjOpts = {
|
||||||
|
key?: string;
|
||||||
|
valueKey?: string;
|
||||||
|
childKey?: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert old component listBlock array items has level without parent id to tree nodes
|
* Convert old component listBlock array items has level without parent id to tree nodes
|
||||||
* @param list Array<GroupTreeItem>
|
* @param list Array<GroupTreeItem>
|
||||||
@ -13,7 +20,7 @@ export const listToTreeHasLevel = (
|
|||||||
) => {
|
) => {
|
||||||
const listDepths = [];
|
const listDepths = [];
|
||||||
//delete useless key
|
//delete useless key
|
||||||
const uselessKeys = ['listDepth', 'isHide','isShrink'];
|
const uselessKeys = ['listDepth', 'isHide', 'isShrink'];
|
||||||
list = list.map((item) => {
|
list = list.map((item) => {
|
||||||
listDepths.push(item.listDepth);
|
listDepths.push(item.listDepth);
|
||||||
return Object.keys(item).reduce(
|
return Object.keys(item).reduce(
|
||||||
@ -146,3 +153,22 @@ export const getExpandGroupByKey = (component, key) => {
|
|||||||
}
|
}
|
||||||
return expandKeys;
|
return expandKeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将树形数据转成 key => value 对象
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const tree2obj = (list: any[], opts: TreeToObjOpts = {}, initObj = {}) => {
|
||||||
|
const { key = 'name', valueKey = 'description', childKey = 'children' } = opts;
|
||||||
|
|
||||||
|
return list.reduce((prev, curr) => {
|
||||||
|
prev[curr[key]] = curr[valueKey];
|
||||||
|
if (Array.isArray(curr[childKey]) && curr[childKey].length > 0) {
|
||||||
|
tree2obj(curr[childKey], opts, (prev[curr[key]] = {}));
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, initObj);
|
||||||
|
};
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": false,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"declaration": false,
|
"declaration": false,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"outDir": "./out",
|
"outDir": "./out",
|
||||||
|
"rootDir": "./src",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"types": [
|
"types": [
|
||||||
"node"
|
"node"
|
||||||
@ -25,12 +31,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/**.ts",
|
"./src/**/**.ts",
|
||||||
|
"./src/**/**.js",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"**/*.spec.ts",
|
"**/*.spec.ts",
|
||||||
"**/browser/**/*.ts"
|
"**/browser/**/*.ts",
|
||||||
|
"**/browser/**/*.js",
|
||||||
|
"out"
|
||||||
],
|
],
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"enableIvy": true
|
"enableIvy": true
|
||||||
|
Loading…
Reference in New Issue
Block a user