├── .DS_Store
├── .gitignore
├── Learn.md
├── Plan.md
├── README.md
├── dist
├── base
│ └── base.js
├── file
│ ├── file.js
│ └── urlTpl.js
├── html
│ ├── desc.css
│ └── temp.html
├── main.js
├── model
│ ├── dataModel.js
│ ├── log.js
│ └── swagger
│ │ ├── model.js
│ │ └── swagger.js
├── server
│ ├── describe.js
│ ├── server.js
│ └── valid.js
└── utils
│ ├── dict.js
│ ├── mock.js
│ └── utils.js
├── example
├── fetch.js
├── index.js
├── test.js
└── urlsReal.js
├── gulpfile.js
├── jest.config.json
├── package-lock.json
├── package.json
├── src
├── base
│ └── base.ts
├── file
│ ├── file.ts
│ └── urlTpl.ts
├── html
│ ├── desc.scss
│ └── temp.html
├── main.ts
├── model
│ ├── dataModel.ts
│ ├── log.ts
│ └── swagger
│ │ ├── model.ts
│ │ └── swagger.ts
├── server
│ ├── describe.ts
│ ├── server.ts
│ └── valid.ts
└── utils
│ ├── dict.ts
│ ├── mock.ts
│ └── utils.ts
├── test
└── utils.test.js
└── tsconfig.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jdf2e/SMock/71a199c25b6ff555adb3a6e45e9c24199086a284/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | *mock/
3 | SMock.json
4 | .DS_Store
--------------------------------------------------------------------------------
/Learn.md:
--------------------------------------------------------------------------------
1 |
8 | .vscode 使用vscode调试的时候配置的内容用于执行node index.js
9 | 怎么实现不编译出来的,直接在Ts中调试代码?
10 | 现在是在两个地方,一个是打包的dist文件夹一个是在默认的ts位置
11 | 应该是
12 |
13 | smock的学习:
14 | 打开node基础语言,调试方式
15 | 关于Smock的研究和编写代码是和node相互关联的
16 | 主线和函数,达到可以用的程度
17 | 和阿里的pont进行对比,提升产品的能力
18 |
19 | smock的核心
20 | 入参:
21 | 出参:
22 | 打包方式:gulp
23 | 整个的数据流动,在外面调用传入到里面
24 |
25 | vscode调试的方法:
26 | 在vscode中去除掉插件需要重新开启下vscode
--------------------------------------------------------------------------------
/Plan.md:
--------------------------------------------------------------------------------
1 | ### 后续计划
2 |
3 | - 导出的URL支持es6 module引入方式
4 | - smock服务启动后,修改json文件,服务器热更新
5 |
6 | ### 项目技术选型
7 |
8 | - TypeScript架构开发
9 | - Gulp项目构建。
10 | - Jest进行单元测试。
11 | - ESLint进行代码标准化。
12 | - 全程使用async异步编程进行流程控制。
13 |
14 | ### 项目涉及模块计划
15 |
16 | | 模块名 | 开发人员| 描述 |
17 | | --- | --- | --- |
18 | | 项目构建 | - | 负责gulp环境维护搭建,主要负责针对ts文件编译后进行压缩合并,以及文件移动整理 |
19 | | 主文件入口 | - | 负责调用每个环节的功能 |
20 | | 文件操作流 | - | 负责根据数据生成对应的JSON假数据,以及url文件 |
21 | | 服务操作流 | - | 负责启动本地服务、把所有mock接口插入到SMock中 |
22 | | 校验流程 | - | 负责在启动服务前对文件进行整理、以及调用接口是对入参进行验证、调用接口后可以提供参数描述功能 |
23 |
24 | ### 功能模块以及完成情况
25 | | 功能名 | 完成情况 | 完成人 | 单元测试覆盖 |
26 | | --- | --- | --- | --- |
27 | | TS框架搭建 | 100% | 杨磊 | - |
28 | | Gulp环境搭建 | 100% | 杨磊 | - |
29 | | Jest环境搭建 | - | 张誉、印凤 | - |
30 | | 入口逻辑 | 100% | 杨磊 | - |
31 | | swagger数据解析| 100% | 杨磊 | - |
32 | | 创建文件功能 | 100% | 杨磊 | - |
33 | | 创建URL功能 | 100% | 孙印凤 | - |
34 | | 注入API功能 | 100% | 王悦、杨磊 | - |
35 | | 服务启动 | 100% | 杨磊 | - |
36 | | 入参校验 | 100% | 杨磊、廖艳丽、杨进军 | - |
37 | | 接口调用描述 | 100% | 杨磊 | - |
38 | | VS Code插件 | - | 王悦 | - |
39 | | 创建配置文件的html页 | - | - | - |
40 | | 网站增加更新日志页面功能展示 | - | - | - |
41 | | 增加测试用例覆盖度 | - | - | - |
42 | | 为SMock增加生命周期功能 | - | all | - |
43 | | 增加SMock支持plugins功能 | - | 王悦 | - |
44 |
45 | ### 整个项目流程
46 |
47 | 1. 开始 ->
48 | 2. 根据文档类型进入不同功能分支 ->
49 | 3. 获取对应的假数据文件(接口或者json文件性质) ->
50 | 4. 把所有数据全部转换成对应的SMockData类型 ->
51 | 5. 基于SMockData生成本地服务的数据文件(可以合并为一个文件也可以单独存在) ->
52 | 6. 基于SMockData生成URL的Map ->
53 | 7. 基于URLMap创建服务接口 ->
54 | 8. 启动服务以供用户访问 ->
55 | 9. 访问接口是校验入参是否合法
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
smock-core
5 |
SMock的核心代码,smock run的主要逻辑
6 |
7 |
8 | ### 版本命名规范
9 | 采用银河系九大行星的顺序来命名。
10 | - 1.0->mercury
11 | - 2.0->venus
12 |
13 | ### 安装
14 |
15 | ```bash
16 | npm install smock-core --save-dev
17 | ```
18 |
19 | ### 调用
20 |
21 | ```bash
22 | let Core = require('smock-core').Core;
23 | new Core({
24 | docPath:'xxx.xxx.xx.xx',
25 | docPort:'80',
26 | path:''
27 | })
28 | ```
29 |
30 | ### 参数说明
31 |
32 | |Attributes|forma|describe|default|
33 | |---|---|---|---|
34 | |type|String|文档数据源类型,暂只支持swagger|swagger|
35 | |docPath|String|type为swagger时,swagger文档访问路径|-|
36 | |docPort|Number|type为swagger时,swagger的文档端口号|80|
37 | |path|String|type为swagger时,swagger模式接口路径|/v2/api-docs|
38 | |method|String|type为swagger时,文档数据请求方式|GET|
39 | |realHostName|String|项目上线后访问的真实域名|-|
40 | |mockPort|Number|启动服务的端口号|3000|
41 | |customProtocol|String|type为swagger时,具体文档服务器协议http或https|http|
42 | |headers|Object|创建本地服务器时接口header附加参数|-|
43 | |jsPath|String|创建服务器时抽取Url路径文件的存储路径|-|
44 | |descInclude|Array|调用接口时展示接口文档的白名单|-|
45 | |override|Boolean|重启服务时是否重新刷新数据|false|
46 |
47 | ## 代码架构
48 |
49 | 代码采用 typescript。
50 | 代码校验:ESLint
51 |
52 | ## 项目命令
53 |
54 | npm run dev: 执行Demo,可热更新,使用VSCode来调试开发即可
55 | npm run build: 打包编译
56 | npm run test: 运行单元测试js
57 |
--------------------------------------------------------------------------------
/dist/base/base.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | class Base {
4 | constructor(opts, data) {
5 | this.option = opts;
6 | this.data = data;
7 | }
8 | }
9 | exports.Base = Base;
10 |
--------------------------------------------------------------------------------
/dist/file/file.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | return new (P || (P = Promise))(function (resolve, reject) {
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
8 | });
9 | };
10 | Object.defineProperty(exports, "__esModule", { value: true });
11 | const base_1 = require("./../base/base");
12 | const dict_1 = require("./../utils/dict");
13 | const utils_1 = require("./../utils/utils");
14 | const log_1 = require("./../model/log");
15 | class File extends base_1.Base {
16 | constructor(opts, data) {
17 | super(opts, data);
18 | }
19 | //创建JSON文件
20 | createJSONFile() {
21 | return __awaiter(this, void 0, void 0, function* () {
22 | let filePromise = [];
23 | let customFileDir = utils_1.join(process.cwd(), dict_1.mockDirName); //默认mock相关文件目录名
24 | utils_1.createDir(customFileDir);
25 | for (let fileIndex = 0; fileIndex < this.data.length; fileIndex++) {
26 | let item = this.data[fileIndex];
27 | let data = JSON.stringify(item.data);
28 | let fileUrl = utils_1.join2(process.cwd(), dict_1.mockDirName, item.id + ".json");
29 | filePromise.push(utils_1.makeFileSync(fileUrl, data));
30 | }
31 | Promise.all(filePromise).then((data) => {
32 | return;
33 | });
34 | });
35 | }
36 | // 创建URL文件
37 | createUrlFile() {
38 | return __awaiter(this, void 0, void 0, function* () {
39 | return yield new Promise((resolve, reject) => {
40 | let option = this.option, urlDatas = this.data;
41 | let jsContent = this.customJsTpl(urlDatas);
42 | let customFileDir = utils_1.join(process.cwd(), dict_1.mockDirName); //默认mock相关文件目录名
43 | let jsFilePath = utils_1.join2(process.cwd(), dict_1.mockDirName, `${dict_1.urlsRealName}.js`); //默认生成位置,如果用户配置则生成至用户配置的位置
44 | if (option.jsPath) {
45 | //用户如果有自定义文件目录,则需要生成至用户自定义目录
46 | customFileDir = utils_1.join(process.cwd(), option.jsPath);
47 | if (!utils_1.existsSync(customFileDir))
48 | return utils_1.error(log_1.jsPathError);
49 | jsFilePath = utils_1.join(customFileDir, `${dict_1.urlsRealName}.js`);
50 | }
51 | utils_1.createDir(customFileDir);
52 | utils_1.makeFileSync(jsFilePath, jsContent); //生成一个js文件
53 | let jsonFilePath = utils_1.join2(process.cwd(), dict_1.mockDirName, `${dict_1.urlsRealName}.json`); //生成一个json文件,只有全部url
54 | let jsonContent = utils_1.toStr(this.jsonDeal(urlDatas)); //将要写入文件的内容串
55 | utils_1.makeFileSync(jsonFilePath, jsonContent); //生成一个json文件只有url
56 | resolve();
57 | });
58 | });
59 | }
60 | //根据用户定义的参数,生成指定格式的url聚合文件
61 | customJsTpl(data) {
62 | let tpl = require('./urlTpl'), option = this.option, host = option.realHostName;
63 | return tpl.getTpl(data, option.mockPort, host);
64 | }
65 | //处理json数据
66 | jsonDeal(urls) {
67 | let pathKey = '', obj = {};
68 | for (let key in urls) {
69 | let item = urls[key];
70 | pathKey = item.id;
71 | obj[pathKey] = {
72 | url: item.url,
73 | type: item.type
74 | };
75 | }
76 | return obj;
77 | }
78 | }
79 | exports.File = File;
80 |
--------------------------------------------------------------------------------
/dist/file/urlTpl.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | let urls, port, hostname;
4 | function getTpl(_urls, _port, _hostname) {
5 | urls = _urls;
6 | port = _port;
7 | hostname = _hostname;
8 | let tpl = `
9 | (function (global, factory) {
10 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
11 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
12 | (global = global || self, factory(global.SMOCK = {}));
13 | }(this, (function(exports) { 'use strict';
14 | ${hostTpl()}
15 | ${restfulTpl()}
16 | var url = {
17 | ${urlTpl()}
18 | }
19 | ${moduleTpl()}
20 | })))`;
21 | return tpl;
22 | }
23 | exports.getTpl = getTpl;
24 | //创建host部分
25 | function hostTpl() {
26 | let tpl = `var isDebug = (window.location.href).indexOf('debug') > -1;
27 | var host = isDebug?'//127.0.0.1:${port}':'//${hostname}';`;
28 | return tpl;
29 | }
30 | //创建RESTful函数
31 | function restfulTpl() {
32 | let tpl = `var restfulURL = function(url, param) {
33 | let result = url;
34 | for(var prop in param) {
35 | result = result.replace('{'+prop+'}', param[prop]);
36 | }
37 | return result;
38 | }`;
39 | return tpl;
40 | }
41 | //创建url对象
42 | function urlTpl() {
43 | let urlTpl = '';
44 | for (let key in urls) {
45 | urlTpl += `'${urls[key].id}': {
46 | url: host + '${urls[key].url}',
47 | type: '${urls[key].type}'
48 | },`;
49 | }
50 | return urlTpl.substr(0, urlTpl.length - 1);
51 | }
52 | //创建模块依赖部分
53 | function moduleTpl() {
54 | let moduleTpl = `
55 | exports.isDebug = isDebug;
56 | exports.host = host;
57 | exports.url = url;
58 | exports.restfulURL = restfulURL;
59 |
60 | Object.defineProperty(exports, '__esModule', { value: true });
61 | `;
62 | return moduleTpl;
63 | }
64 |
--------------------------------------------------------------------------------
/dist/html/desc.css:
--------------------------------------------------------------------------------
1 | .w {
2 | width: 990px;
3 | margin: 0 auto; }
4 |
5 | .search input {
6 | height: 40px;
7 | width: 300px;
8 | text-indent: 10px;
9 | outline: none; }
10 |
11 | .tb {
12 | width: 100%;
13 | text-align: center;
14 | border-collapse: collapse; }
15 | .tb th:nth-child(1) {
16 | width: 200px; }
17 | .tb th, .tb tr {
18 | height: 40px; }
19 | .tb th {
20 | background: #f8f8f8; }
21 | .tb td, .tb th {
22 | border-bottom: 1px solid #ccc; }
23 |
--------------------------------------------------------------------------------
/dist/html/temp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 文档参数描述
9 |
10 |
11 |
12 |
13 |
14 |
接口名称:{{API}}
15 |
接口描述:{{DESC}}
16 |
17 | {{CODE}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | const swagger_1 = require("./model/swagger/swagger");
4 | const file_1 = require("./file/file");
5 | const server_1 = require("./server/server");
6 | const utils_1 = require("./utils/utils");
7 | const log_1 = require("./model/log");
8 | class Core {
9 | constructor(opts) {
10 | // let config = Config;
11 | this.options = Object.assign({
12 | type: 'swagger',
13 | docPath: '',
14 | docPort: 80,
15 | path: '/v2/api-docs',
16 | method: 'GET',
17 | realHostName: '',
18 | mockPort: 3000,
19 | customProtocol: 'http',
20 | headers: {},
21 | jsPath: '',
22 | descInclude: [],
23 | override: false
24 | }, opts);
25 | //确保地址存在
26 | if (this.options.docPath == "") {
27 | utils_1.log(log_1.docPathError);
28 | return;
29 | }
30 | //不同类型跳转到不同数据层
31 | switch (this.options.type) {
32 | case 'swagger':
33 | let swagger = new swagger_1.Swagger(this.options);
34 | console.log(swagger, swagger.getData(), 'hello');
35 | // 这里为什么一直是pending状态
36 | this.dataPromise = swagger.getData();
37 | break;
38 | }
39 | this.workflow();
40 | process.on('unhandledRejection', (error) => {
41 | console.error('unhandledRejection', error);
42 | process.exit(1); // To exit with a 'failure' code
43 | });
44 | }
45 | // SMock主流程
46 | workflow() {
47 |
48 | this.dataPromise.then((data) => {
49 | console.log(data, 'hello');
50 |
51 | let process = [];
52 | this.data = data;
53 | //声明变量
54 | var server = new server_1.Server(this.options, this.data);
55 | if (!utils_1.isNew() && !this.options.override) {
56 | }
57 | else {
58 | let file = new file_1.File(this.options, this.data);
59 | //创建文件
60 | let filePromise = file.createJSONFile();
61 | process.push(filePromise);
62 | //创建URL
63 | let urlPromise = file.createUrlFile();
64 | process.push(urlPromise);
65 | }
66 | //插入接口
67 | let apiPromise = server.addAPI();
68 | process.push(apiPromise);
69 | //全部过程执行完毕,执行启动服务
70 | Promise.all(process).then(() => {
71 | server.startServer(() => {
72 | utils_1.log(`【${new Date()}】服务器启动!`);
73 | // log(`http://127.0.0.1:${this.options.mockPort}`);
74 | });
75 | });
76 | });
77 | }
78 | }
79 | exports.Core = Core;
80 |
--------------------------------------------------------------------------------
/dist/model/dataModel.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 |
--------------------------------------------------------------------------------
/dist/model/log.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | let startServerError = '服务器启动错误';
4 | exports.startServerError = startServerError;
5 | let jsPathError = 'jsPath配置有误';
6 | exports.jsPathError = jsPathError;
7 | let docPathError = '文档路径配置错误,请检查docPath是否配置';
8 | exports.docPathError = docPathError;
9 |
--------------------------------------------------------------------------------
/dist/model/swagger/model.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | return new (P || (P = Promise))(function (resolve, reject) {
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
8 | });
9 | };
10 | Object.defineProperty(exports, "__esModule", { value: true });
11 | const mock_1 = require("./../../utils/mock");
12 | //数据查找路径,针对swagger返回数据的特殊处理
13 | function queryData(hash) {
14 | let result = '';
15 | if (hash) {
16 | result = (hash.substring(2, hash.length)).split('/');
17 | }
18 | return result[1] || '';
19 | }
20 | //递归替换
21 | function dealData(def) {
22 | return __awaiter(this, void 0, void 0, function* () {
23 | let result = {};
24 | //保存接口返回参数的描述
25 | let desc = [];
26 | let definition = def.definition;
27 | let type = definition && definition.type ? definition.type : '';
28 | if (type) {
29 | if (type == 'string') {
30 | result = mock_1.setString();
31 | let varDesc = {};
32 | varDesc.key = def.prevKey;
33 | varDesc.desc = definition.description || '暂无定义';
34 | varDesc.type = definition.type;
35 | desc.push(varDesc);
36 | }
37 | if (type == 'integer') {
38 | result = mock_1.setInteger();
39 | let varDesc = {};
40 | varDesc.key = def.prevKey;
41 | varDesc.desc = definition.description || '暂无定义';
42 | varDesc.type = definition.type;
43 | desc.push(varDesc);
44 | }
45 | if (type == 'boolean') {
46 | result = mock_1.setBoolean();
47 | let varDesc = {};
48 | varDesc.key = def.prevKey;
49 | varDesc.desc = definition.description || '暂无定义';
50 | varDesc.type = definition.type;
51 | desc.push(varDesc);
52 | }
53 | if (type == 'object') {
54 | if (definition.properties) {
55 | result = definition.properties;
56 | for (let key in result) {
57 | //防止递归数据造成死循环
58 | if (result[key].type && result[key].type == 'array' && result[key]['$ref'] && (queryData(result[key]['$ref']) == def.prevKey)) {
59 | result[key] = {};
60 | }
61 | else {
62 | dealData({
63 | prevKey: key,
64 | definition: result[key],
65 | definitionMap: def.definitionMap
66 | }).then((data) => {
67 | result[key] = data.data;
68 | desc = desc.concat(data.desc);
69 | });
70 | }
71 | }
72 | }
73 | else {
74 | result = {};
75 | }
76 | }
77 | if (type == 'array') {
78 | let items = def.definition.items;
79 | if (items.type) {
80 | }
81 | else {
82 | let objKey = queryData(items['$ref']);
83 | //防止递归数据造成死循环
84 | if (objKey != def.prevKey) {
85 | dealData({
86 | prevKey: objKey,
87 | definition: def.definitionMap[objKey],
88 | definitionMap: def.definitionMap
89 | }).then((data) => {
90 | result = data.data;
91 | desc = desc.concat(data.desc);
92 | });
93 | }
94 | else {
95 | result = {};
96 | }
97 | }
98 | }
99 | }
100 | else {
101 | let goObject = def.definition && def.definition['$ref'] ? def.definition['$ref'] : '';
102 | if (goObject) {
103 | let objKey = queryData(goObject);
104 | dealData({
105 | prevKey: objKey,
106 | definition: def.definitionMap[objKey],
107 | definitionMap: def.definitionMap
108 | }).then((data) => {
109 | result = Object.assign(result, data.data);
110 | desc = desc.concat(data.desc);
111 | });
112 | }
113 | else {
114 | result = mock_1.setString();
115 | }
116 | }
117 | return {
118 | data: result,
119 | desc: []
120 | };
121 | });
122 | }
123 | exports.dealData = dealData;
124 | //解析API参数
125 | function getParamData(params, definitions) {
126 | let result = [];
127 | for (let i = 0; i < params.length; i++) {
128 | let param = params[i];
129 | let p = {};
130 | if (param.schema) {
131 | p.type = 'object';
132 | p.value = param.name;
133 | if (param.schema['$ref']) {
134 | p.child = getParamSchemaData(param.schema['$ref'], definitions);
135 | }
136 | else {
137 | p.type = param.schema.type;
138 | }
139 | p.required = param.required;
140 | }
141 | else {
142 | p.type = param.type ? param.type : 'string';
143 | p.value = param.name;
144 | p.required = param.required;
145 | }
146 | p.in = param.in;
147 | p.required = param.required;
148 | p.desc = param.description;
149 | result.push(p);
150 | }
151 | return result;
152 | }
153 | exports.getParamData = getParamData;
154 | function getParamSchemaData(key, definitionMap) {
155 | let validResult = [];
156 | let defineKey = queryData(key);
157 | let props = definitionMap[defineKey].properties;
158 | for (let key in props) {
159 | let prop = props[key];
160 | let validItem = {};
161 | if (prop.$ref) {
162 | validItem.type = 'object';
163 | validItem.desc = prop.description;
164 | validItem.param = getParamSchemaData(prop.$ref, definitionMap);
165 | }
166 | else {
167 | validItem.name = key;
168 | validItem.type = prop.type;
169 | validItem.desc = prop.description;
170 | }
171 | validResult.push(validItem);
172 | }
173 | return validResult;
174 | // definitionMap[key];
175 | }
176 | //获取json数据的key
177 | function getJsonDataKey(responses) {
178 | let schema = responses['200'].schema;
179 | let mockJsonKey = schema ? schema['$ref'] : '';
180 | return queryData(mockJsonKey);
181 | }
182 | exports.getJsonDataKey = getJsonDataKey;
183 |
--------------------------------------------------------------------------------
/dist/model/swagger/swagger.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | *
4 | * 使用Swagger时,处理数据的文件
5 | */
6 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7 | return new (P || (P = Promise))(function (resolve, reject) {
8 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
11 | step((generator = generator.apply(thisArg, _arguments || [])).next());
12 | });
13 | };
14 | Object.defineProperty(exports, "__esModule", { value: true });
15 | const server_1 = require("../../server/server");
16 | const utils_1 = require("../../utils/utils");
17 | const model_1 = require("./model");//Swagger处理数据模型
18 | const mock_1 = require("./../../utils/mock");
19 | let clone = require('clone');
20 | class Swagger {
21 | constructor(opts) {
22 | this.config = utils_1.dealConfig(opts);
23 | }
24 | getData() {
25 | return __awaiter(this, void 0, void 0, function* () {
26 | let self = this;
27 | let d;
28 | yield self.getDataFromServer()
29 | .then((data) => {
30 | d = self.convertData(clone(data));
31 | });
32 | return d;
33 | });
34 | }
35 | getDataFromServer() {
36 | return __awaiter(this, void 0, void 0, function* () {
37 | let server = new server_1.Server(this.config);
38 | let result;
39 | let url = `${this.config.customProtocol}://${this.config.docPath}:${this.config.docPort}${this.config.path}`;
40 | console.log(url, 'swagger');
41 |
42 | yield server.fetchData({
43 | url: url
44 | })
45 | .then((data) => {
46 | console.log(data, 'swagger1');
47 | result = data;
48 | });
49 | return result;
50 | });
51 | }
52 | convertData(data) {
53 | console.log(data, 'swagger');
54 |
55 | return __awaiter(this, void 0, void 0, function* () {
56 | return yield new Promise((resolve, reject) => {
57 | let allDealDataPromises = [];
58 | // 格式规划
59 | let apis = data.paths;
60 | let definitions = data.definitions;
61 | let result = [];
62 | for (let prop in apis) {
63 | let d = {};
64 | let item = apis[prop];
65 | d.url = prop;
66 | // if(d.url != '/api/service/{serviceId}') continue;
67 | let dataModelFlag = '';
68 | for (let type in item) {
69 | // let descs:any = [];
70 | d.type = type;
71 | d.id = item[type].operationId;
72 | d.desc = item[type].summary;
73 |
74 | dataModelFlag = model_1.getJsonDataKey(item[type].responses);
75 | if (dataModelFlag) {
76 | let promise = model_1.dealData({
77 | prevKey: dataModelFlag,
78 | definition: definitions[dataModelFlag],
79 | definitionMap: definitions
80 | }).then((data) => {
81 | d.data = data.data;
82 | d.responseDesc = data.desc;
83 | if (!utils_1.keyInData(item[type].operationId, result)) {
84 | result.push(d);
85 | }
86 | }).then((err) => {
87 | console.log(err, 'swagger-err');
88 |
89 | }).catch((err) => {
90 | console.log(err, 'swagger-err');
91 | });
92 | console.log(promise, 'promise');
93 |
94 | allDealDataPromises.push(promise);
95 | }
96 | else {
97 | d.data = mock_1.setString();
98 | if (!utils_1.keyInData(item[type].operationId, result)) {
99 | result.push(d);
100 | }
101 | }
102 | if (item[type].parameters) {
103 | d.params = model_1.getParamData(item[type].parameters, definitions);
104 | }
105 | else {
106 | d.params = null;
107 | }
108 | }
109 | }
110 | Promise.all(allDealDataPromises).then(() => {
111 | resolve(result);
112 | });
113 | });
114 | });
115 | }
116 | }
117 | exports.Swagger = Swagger;
118 |
--------------------------------------------------------------------------------
/dist/server/describe.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | const base_1 = require("../base/base");
4 | const utils_1 = require("./../utils/utils");
5 | const fs_1 = require("fs");
6 | const child_process_1 = require("child_process");
7 | class Describe extends base_1.Base {
8 | constructor(opts, data) {
9 | super(opts, data);
10 | }
11 | getDescribeHtmlUrl(id) {
12 | this.createHtml(id);
13 | return `http://127.0.0.1:${this.option.mockPort}/desc/${id}`;
14 | }
15 | createHtml(id) {
16 | let result;
17 | let data = utils_1.getDataFromArrayById(this.data, id);
18 | let html = '';
19 | if (data.params) {
20 | html += `
21 | 入参
22 |
23 |
24 | 参数名 |
25 | 类型 |
26 | 位置 |
27 | 是否必填 |
28 | 描述 |
29 |
30 | `;
31 | for (let inIndex = 0; inIndex < data.params.length; inIndex++) {
32 | let param = data.params[inIndex];
33 | html += `
34 | ${param.value} |
35 | ${param.type} |
36 | ${param.in} |
37 | ${param.required} |
38 | ${param.desc} |
39 |
`;
40 | if (param.child) {
41 | for (let childIndex = 0; childIndex < param.child.length; childIndex++) {
42 | let childParam = param.child[childIndex];
43 | html += `
44 | ${param.value}.${childParam.name} |
45 | ${childParam.type} |
46 | ${param.in} |
47 | ${param.required} |
48 | ${param.desc} |
49 |
`;
50 | }
51 | }
52 | }
53 | html += `
54 |
55 |
`;
56 | }
57 | if (data.responseDesc && data.responseDesc.length > 0) {
58 | html += `
59 | 出参
60 |
61 |
62 | 参数名 |
63 | 类型 |
64 | 描述 |
65 |
66 | `;
67 | for (let resIndex = 0; resIndex < data.responseDesc.length; resIndex++) {
68 | let desc = data.responseDesc[resIndex];
69 | html += `
70 | ${desc.key} |
71 | ${desc.type} |
72 | ${desc.desc} |
73 |
74 | `;
75 | }
76 | html += `
77 |
78 |
79 | `;
80 | }
81 | let file = fs_1.readFileSync(utils_1.join(__dirname, './../html/temp.html'), 'utf8');
82 | result = file.replace('{{CODE}}', html);
83 | result = result.replace('{{API}}', data.url);
84 | result = result.replace('{{DESC}}', data.desc);
85 | return result;
86 | }
87 | openAPIDesc(descUrl) {
88 | let cmd = '';
89 | if (process.platform == 'win32') {
90 | cmd = 'start';
91 | }
92 | else if (process.platform == 'linux') {
93 | cmd = 'xdg-open';
94 | }
95 | else if (process.platform == 'darwin') {
96 | cmd = 'open';
97 | }
98 | child_process_1.exec(`${cmd} ${descUrl}`);
99 | }
100 | }
101 | exports.Describe = Describe;
102 |
--------------------------------------------------------------------------------
/dist/server/server.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | return new (P || (P = Promise))(function (resolve, reject) {
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
8 | });
9 | };
10 | Object.defineProperty(exports, "__esModule", { value: true });
11 | const base_1 = require("./../base/base");
12 | const utils_1 = require("./../utils/utils");
13 | const dict_1 = require("./../utils/dict");
14 | const describe_1 = require("./describe");
15 | const valid_1 = require("./valid");
16 | let express = require('express');
17 | var bodyParser = require("body-parser");
18 | let axios = require('axios');
19 | let app = express();
20 | app.use(bodyParser.urlencoded({ extended: false }));
21 | class Server extends base_1.Base {
22 | constructor(opts, data) {
23 | super(opts, data);
24 | }
25 | //启动服务
26 | startServer(cal) {
27 | app.listen(this.option.mockPort, () => {
28 | if (cal)
29 | cal(); //启动成功
30 | this.addStatic();
31 | });
32 | }
33 | // 托管静态页面,如接口描述页等
34 | addStatic() {
35 | app.use(express.static(utils_1.join(__dirname, './../html')));
36 | }
37 | // 注入接口
38 | addAPI() {
39 | return __awaiter(this, void 0, void 0, function* () {
40 | let self = this;
41 | let desc = new describe_1.Describe(this.option, this.data);
42 | let data = this.data;
43 | return yield new Promise((resolve, reject) => {
44 | app.get('/desc/:id', function (req, res) {
45 | let id = req.params.id;
46 | res.send(desc.createHtml(id));
47 | });
48 | for (let index = 0; index < data.length; index++) {
49 | const element = data[index];
50 | let realUrl = utils_1.dealUrl(element.url);
51 | app[element.type](realUrl, function (req, res) {
52 | res.header("Access-Control-Allow-Origin", req.headers.origin);
53 | res.header('Access-Control-Allow-Credentials', true); //告诉客户端可以在HTTP请求中带上Cookie
54 | res.header("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, " +
55 | "Last-Modified, Cache-Control, Expires, Content-Type, Content-Language, Cache-Control, X-E4M-With,X_FILENAME");
56 | res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
57 | res.header("X-Powered-By", ' 3.2.1');
58 | res.header("Content-Type", "application/json;charset=utf-8");
59 | //创建接口描述页面
60 | let descUrl = desc.getDescribeHtmlUrl(element.id);
61 | utils_1.log('调用接口的文档链接:' + descUrl);
62 | if (self.isInclude(element.id, self.option.descInclude)) {
63 | desc.openAPIDesc(descUrl);
64 | }
65 | let params = self.getParamByType(req);
66 | let errMsg = valid_1.validParam(params, element);
67 | if (errMsg === '') {
68 | let fileUrl = utils_1.join2(process.cwd(), dict_1.mockDirName, element.id + ".json");
69 | res.send(require(fileUrl));
70 | }
71 | else {
72 | res.send(`
73 | ${errMsg}
74 | 接口描述参考:${descUrl}
75 | `);
76 | }
77 | });
78 | }
79 | resolve();
80 | });
81 | // return 1;
82 | //TODO: 注入SMock的接口服务
83 | });
84 | }
85 | getParamByType(req) {
86 | let params = {};
87 | if (req.params) {
88 | params = Object.assign(params, req.params);
89 | }
90 | if (req.query) {
91 | params = Object.assign(params, req.query);
92 | }
93 | if (req.body) {
94 | params = Object.assign(params, req.body);
95 | }
96 | return params;
97 | }
98 | isInclude(urlId, includes) {
99 | let exist = false;
100 | exist = includes.indexOf(urlId) > -1;
101 | return exist;
102 | }
103 | //获取数据
104 | fetchData(opts) {
105 | return __awaiter(this, void 0, void 0, function* () {
106 | let self = this;
107 | // let swaggerUtl = getHost(opts.url);
108 | return yield new Promise((resolve, reject) => {
109 | let header = {};
110 | for (let prop in self.option.headers) {
111 | header(prop, self.option.headers[prop]);
112 | }
113 | axios({
114 | url: opts.url,
115 | headers: header
116 | })
117 | .then((data) => {
118 | resolve(data.data);
119 | });
120 | });
121 | });
122 | }
123 | }
124 | exports.Server = Server;
125 |
--------------------------------------------------------------------------------
/dist/server/valid.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | function validParam(params, data) {
4 | let result = '';
5 | let errorRequired = validRequired(params, data);
6 | let errorType = validType(params, data);
7 | if (errorRequired.length > 0) {
8 | result += `【${errorRequired.join('、')}】必须传入`;
9 | }
10 | if (errorType.length > 0) {
11 | result += `
12 | 【${errorType.join('、')}】传入类型错误
13 | `;
14 | }
15 | return result;
16 | }
17 | exports.validParam = validParam;
18 | //校验必填
19 | function validRequired(inParams, data) {
20 | let error = [];
21 | if (!data.params)
22 | return error;
23 | for (let idx = 0; idx < data.params.length; idx++) {
24 | let item = data.params[idx];
25 | if (item.required && !inParams[item.value]) {
26 | //检查传参中是不是存在必填项
27 | error.push(item.value);
28 | }
29 | }
30 | return error;
31 | }
32 | //校验入参格式
33 | function validType(inParams, data) {
34 | let error = [];
35 | if (!data.params)
36 | return error;
37 | for (let prop in inParams) {
38 | let param = getParamByName(prop, data.params);
39 | if (!param)
40 | return error;
41 | if (typeof inParams[prop] != param.type) {
42 | //如果类型为int,但url的方式传参会自动转换为字符串,我们要转换
43 | console.log(param.type, inParams[prop], isNaN(parseInt(inParams[prop])));
44 | if (!(param.type == 'integer' && !isNaN(parseInt(inParams[prop])))) {
45 | error.push(param.value);
46 | }
47 | }
48 | }
49 | return error;
50 | }
51 | //获取对应参数的值
52 | function getParamByName(key, params) {
53 | let result = null;
54 | for (let idx = 0; idx < params.length; idx++) {
55 | let param = params[idx];
56 | if (key === param.value) {
57 | result = param;
58 | }
59 | }
60 | return result;
61 | }
62 |
--------------------------------------------------------------------------------
/dist/utils/dict.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.mockDirName = 'mock';
4 | exports.configName = 'SMock.json'; //参数文件名
5 | exports.urlsRealName = 'urlsReal'; //真实路径文件名
6 |
--------------------------------------------------------------------------------
/dist/utils/mock.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | /**
4 | * 模拟数据动态化,引入mockjs.js来处理
5 | * author: liaoyanli
6 | */
7 | let Mock = require('mockjs');
8 | var Random = Mock.Random;
9 | function setString() {
10 | Random.word(3, 8);
11 | return Mock.mock('@word(3, 8)');
12 | }
13 | exports.setString = setString;
14 | function setBoolean() {
15 | Random.boolean();
16 | return Mock.mock('@boolean');
17 | }
18 | exports.setBoolean = setBoolean;
19 | function setInteger() {
20 | Random.integer(1, 100);
21 | return Mock.mock('@integer(1, 100)');
22 | }
23 | exports.setInteger = setInteger;
24 |
--------------------------------------------------------------------------------
/dist/utils/utils.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | let fs = require('fs');
4 | let path = require('path');
5 | const dict_1 = require("./dict");
6 | function dealConfig(c) {
7 | if (c.docPath) {
8 | c.docPath = parseURL(c.docPath);
9 | }
10 | if (c.domain) {
11 | c.headers = {
12 | host: c.domain
13 | };
14 | }
15 | if (c.customProtocol == 'https') {
16 | c.port = 443;
17 | }
18 | //mock文件夹名
19 | // c.mockDirName = `${c.projectName?c.projectName:defaultConfig.projectName}mock`;
20 | return c; // Object.assign(defaultConfig, c);
21 | }
22 | exports.dealConfig = dealConfig;
23 | function parseURL(url) {
24 | var a = url.replace("http://", "").replace("https://", "");
25 | return a.substring(0, a.indexOf("/") > 0 ? a.indexOf("/") : a.length);
26 | }
27 | exports.parseURL = parseURL;
28 | function log(msg) {
29 | console.log(msg);
30 | }
31 | exports.log = log;
32 | //警告打印
33 | function warn(msg) {
34 | console.log(`warn:${msg}`);
35 | }
36 | exports.warn = warn;
37 | function error(msg) {
38 | console.log(`error:${msg}`);
39 | }
40 | exports.error = error;
41 | //将buffer或者字符串转换成json串
42 | function toJson(str) {
43 | return JSON.parse(str);
44 | }
45 | exports.toJson = toJson;
46 | //将对象变成格式化串
47 | function toStr(json) {
48 | return JSON.stringify(json, null, 2);
49 | }
50 | exports.toStr = toStr;
51 | //将含有花括号的url,替换成对应的数据
52 | function dealUrl(url) {
53 | return url.replace(/\{.*?\}/g, function (d) {
54 | let key = d.substring(1, d.length - 1);
55 | return `:${key}`;
56 | }); //此正则很重要
57 | }
58 | exports.dealUrl = dealUrl;
59 | function getParamByType(type, req) {
60 | let params = {};
61 | type = type.toLowerCase();
62 | switch (type) {
63 | case 'get':
64 | params = req.query;
65 | break;
66 | case 'post':
67 | params = req.body;
68 | break;
69 | default:
70 | break;
71 | }
72 | return params;
73 | }
74 | exports.getParamByType = getParamByType;
75 | // Data中获取对应ID的数据
76 | function getDataFromArrayById(arr, id) {
77 | for (let i = 0; i < arr.length; i++) {
78 | let item = arr[i];
79 | if (item.id === id) {
80 | return item;
81 | }
82 | }
83 | return null;
84 | }
85 | exports.getDataFromArrayById = getDataFromArrayById;
86 | //文件操作
87 | function existsSync(url) {
88 | return fs.existsSync(url);
89 | }
90 | exports.existsSync = existsSync;
91 | //读文件
92 | function readFileSync(url) {
93 | return fs.readFileSync(url);
94 | }
95 | exports.readFileSync = readFileSync;
96 | //创建目录
97 | function createDir(dir) {
98 | var stat = fs.existsSync(dir);
99 | if (!stat) {
100 | //为true的话那么存在,如果为false不存在
101 | fs.mkdirSync(dir);
102 | }
103 | }
104 | exports.createDir = createDir;
105 | //创建文件并写入内容(异步)
106 | function makeFile(filePath, content) {
107 | return new Promise((resolve, reject) => {
108 | var stat = existsSync(filePath);
109 | if (stat) {
110 | //为true的话那么存在,如果为false不存在
111 | // utils.log(`${filePath} 已存在,内容已覆盖`);
112 | }
113 | fs.writeFile(filePath, content, (err) => {
114 | if (!err) {
115 | resolve(filePath);
116 | }
117 | else {
118 | reject(err);
119 | }
120 | });
121 | });
122 | }
123 | exports.makeFile = makeFile;
124 | //创建文件并写入内容(同步无回调)
125 | function makeFileSync(filePath, content) {
126 | var stat = existsSync(filePath);
127 | if (stat) {
128 | //为true的话那么存在,如果为false不存在
129 | log(`${filePath} 已存在,内容已覆盖`);
130 | }
131 | // else {
132 | fs.writeFileSync(filePath, content);
133 | }
134 | exports.makeFileSync = makeFileSync;
135 | ////判断是否存在json文件
136 | function isNew() {
137 | return !existsSync(join(process.cwd(), dict_1.mockDirName));
138 | }
139 | exports.isNew = isNew;
140 | //合并
141 | function join(a, b) {
142 | return path.resolve(a, b);
143 | }
144 | exports.join = join;
145 | function join2(a, b, c) {
146 | return path.join(a, b, c);
147 | }
148 | exports.join2 = join2;
149 | // 判断对象中是否存在值
150 | function keyInData(id, arr) {
151 | let result = false;
152 | for (let i = 0; i < arr.length; i++) {
153 | let item = arr[i];
154 | if (item.id == id) {
155 | result = true;
156 | }
157 | }
158 | return result;
159 | }
160 | exports.keyInData = keyInData;
161 | function getHost(url) {
162 | }
163 | exports.getHost = getHost;
164 |
--------------------------------------------------------------------------------
/example/fetch.js:
--------------------------------------------------------------------------------
1 | var axios = require('axios');
2 | var SMOCK = require('./urlsReal');
3 | let apiDoc;
4 | function a() {
5 | console.log(url);
6 | return new Promise((resolve, reject) => {
7 | axios({
8 | url: 'http://10.182.30.155/v2/api-docs'
9 | })
10 | .then((data) => {
11 | // resolve(data.data);
12 | apiDoc = data.data;
13 | resolve(apiDoc);
14 | console.log(apiDoc);
15 | })
16 | })
17 | }
18 | a().then((data) => {
19 | console.log(apiDoc.definitions['ResultResponse«ApplyBooking»']);
20 | })
21 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: In User Settings Edit
3 | * @Author: your name
4 | * @Date: 2019-08-12 11:03:59
5 | * @LastEditTime: 2019-08-12 11:03:59
6 | * @LastEditors: your name
7 | */
8 | var Core = require("./../dist/main.js").Core;
9 | new Core({
10 | docPath: "10.182.52.40",
11 | realHostName: "10.182.52.40",
12 | docPort: "",
13 | mockPort: 3000,
14 | jsPath: "example/",
15 | headers: {
16 | // "host": "kudou-staff-m-fy.jd.com"
17 | },
18 | descInclude: ["getAuthCodeUsingGET", "bindCarUsingPOST"],
19 | override: true
20 | });
21 |
--------------------------------------------------------------------------------
/example/test.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var restfulURL = function(url, param) {
3 | let result = url;
4 | for(var prop in param) {
5 | result = result.replace('{'+prop+'}', param[prop]);
6 | }
7 | return result;
8 | }
9 | var url = '/api/service/{serviceId}';
10 | var newUrl = restfulURL(url, {
11 | serviceId: 1
12 | });
13 | console.log(newUrl);
14 | })()
--------------------------------------------------------------------------------
/example/urlsReal.js:
--------------------------------------------------------------------------------
1 |
2 | (function (global, factory) {
3 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
5 | (factory((global.SMOCK = {})));
6 | }(this, (function(exports) { 'use strict';
7 | var isDebug = (window.location.href).indexOf('debug') > -1;
8 | var host = isDebug?'//127.0.0.1:3000':'//192.168.128.83';
9 | var restfulURL = function(url, param) {
10 | let result = url;
11 | for(var prop in param) {
12 | result = result.replace('{'+prop+'}', param[prop]);
13 | }
14 | return result;
15 | }
16 | var url = {
17 | 'getBannersUsingGET': {
18 | url: host + '/stryview/v1/banner',
19 | type: 'get'
20 | },'getProjectProgressUsingGET': {
21 | url: host + '/stryview/v1/jobProgress',
22 | type: 'get'
23 | },'loginInfoUsingGET': {
24 | url: host + '/stryview/v1/loginInfo',
25 | type: 'get'
26 | },'menusUsingGET': {
27 | url: host + '/stryview/v1/menus',
28 | type: 'get'
29 | },'getMyStrategyUsingGET': {
30 | url: host + '/stryview/v1/myStrategyHouse',
31 | type: 'get'
32 | },'strategyUsingPOST': {
33 | url: host + '/stryview/v1/strategy',
34 | type: 'post'
35 | },'strategy01UsingPOST': {
36 | url: host + '/stryview/v1/strategy01',
37 | type: 'post'
38 | },'strategy02UsingPOST': {
39 | url: host + '/stryview/v1/strategy02',
40 | type: 'post'
41 | },'strategy03UsingPOST': {
42 | url: host + '/stryview/v1/strategy03',
43 | type: 'post'
44 | },'strategy04UsingPOST': {
45 | url: host + '/stryview/v1/strategy04',
46 | type: 'post'
47 | },'strategy05UsingPOST': {
48 | url: host + '/stryview/v1/strategy05',
49 | type: 'post'
50 | },'strategy06UsingPOST': {
51 | url: host + '/stryview/v1/strategy06',
52 | type: 'post'
53 | },'strategy07UsingPOST': {
54 | url: host + '/stryview/v1/strategy07',
55 | type: 'post'
56 | },'getStrategyUsingGET': {
57 | url: host + '/stryview/v1/strategyHouse',
58 | type: 'get'
59 | },'strategyHouseNavUsingGET': {
60 | url: host + '/stryview/v1/strategyHouseNav',
61 | type: 'get'
62 | },'strategyHouseUserUsingGET': {
63 | url: host + '/stryview/v1/strategyHouseUser',
64 | type: 'get'
65 | },'saveStrategyPmoUsingPOST': {
66 | url: host + '/stryview/v1/strategyPmo',
67 | type: 'post'
68 | },'deleteStrategyUserUsingDELETE': {
69 | url: host + '/stryview/v1/strategyUser',
70 | type: 'delete'
71 | },'deleteStrategyUserUsingDELETE': {
72 | url: host + '/stryview/v1/strategyUser',
73 | type: 'delete'
74 | },'getStrategyUserRoleUsingGET': {
75 | url: host + '/stryview/v1/strategyUserRole',
76 | type: 'get'
77 | },'getStrategyWinDataUsingGET': {
78 | url: host + '/stryview/v1/strategyWin',
79 | type: 'get'
80 | },'getStrategyWinNavUsingGET': {
81 | url: host + '/stryview/v1/strategyWinNav',
82 | type: 'get'
83 | },'subDeptUsingGET': {
84 | url: host + '/stryview/v1/subDept',
85 | type: 'get'
86 | },'switchStrategyUsingPOST': {
87 | url: host + '/stryview/v1/switchStrategyHouse',
88 | type: 'post'
89 | },'saveTimeLineUsingPOST': {
90 | url: host + '/stryview/v1/timeLine',
91 | type: 'post'
92 | },'userUsingGET': {
93 | url: host + '/stryview/v1/user',
94 | type: 'get'
95 | },'yesOrNoUsingGET': {
96 | url: host + '/stryview/v1/yesOrNo',
97 | type: 'get'
98 | }
99 | }
100 |
101 | exports.isDebug = isDebug;
102 | exports.host = host;
103 | exports.url = url;
104 | exports.restfulURL = restfulURL;
105 |
106 | Object.defineProperty(exports, '__esModule', { value: true });
107 |
108 | })))
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const { task, watch, series, src, dest } = require('gulp');
2 | const uglify = require('gulp-uglify-es').default;
3 | const ts = require('gulp-typescript');
4 | const sass = require('gulp-sass');
5 | //TS解析
6 | function compilerTypeScript(cb) {
7 | return src('src/**/*.ts')
8 | .pipe(ts({
9 | "module": "CommonJS",
10 | "esModuleInterop": true,
11 | "target": "es6",
12 | "noImplicitAny": true,
13 | "moduleResolution": "node",
14 | "sourceMap": false
15 | })
16 | )
17 | .pipe(dest('./dist'));
18 | }
19 | function jsCompress(cb) {
20 | return src('src/**/*.js')
21 | .pipe(uglify())
22 | .pipe(dest('dist'));
23 | }
24 | //编译sass
25 | function compilerSass(cb) {
26 | return src('src/html/*.scss')
27 | .pipe(sass().on('error', sass.logError))
28 | .pipe(dest('dist/html'));
29 | }
30 |
31 | // 迁移html
32 | function moveHtml(cb) {
33 | return src('src/html/**/*.html')
34 | .pipe(dest('dist/html'));
35 | }
36 |
37 | if(process.env.NODE_ENV === 'development') {
38 | task('default', series(compilerTypeScript, compilerSass, moveHtml));
39 | watch(['src/**/*.ts', 'src/**/*.scss', 'src/html/**/*.html'], series(compilerTypeScript, compilerSass, moveHtml));
40 | } else {
41 | task('default', series(compilerTypeScript, jsCompress, compilerSass, moveHtml));
42 | }
43 |
--------------------------------------------------------------------------------
/jest.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "collectCoverage":true,
3 | "collectCoverageFrom": [
4 | "/src/**/*.{js,ts}"
5 | ],
6 | "transform": {
7 | "^.+\\.js$": "/node_modules/babel-jest",
8 | "^.+\\.(ts)$": "/node_modules/ts-jest/preprocessor.js"
9 | },
10 | "moduleFileExtensions":["js","ts"]
11 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smock-core",
3 | "version": "2.0.5",
4 | "description": "SMock核心源码",
5 | "main": "./dist/main",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/jdf2e/SMock.git"
9 | },
10 | "scripts": {
11 | "test": "jest --config=jest.config.json",
12 | "dev": "cross-env NODE_ENV=development gulp",
13 | "build": "gulp"
14 | },
15 | "keywords": [
16 | "swagger",
17 | "mock",
18 | "swagger-mock",
19 | "node",
20 | "server",
21 | "smock"
22 | ],
23 | "author": "jdc-fe",
24 | "license": "MIT",
25 | "dependencies": {
26 | "@types/axios": "^0.14.0",
27 | "body-parser": "^1.18.3",
28 | "clone": "^2.1.2",
29 | "express": "^4.16.3",
30 | "mockjs": "^1.0.1-beta3"
31 | },
32 | "devDependencies": {
33 | "gulp": "^4.0.0",
34 | "typescript": "^3.2.2",
35 | "gulp-uglify-es": "^1.0.4",
36 | "gulp-typescript": "^5.0.0",
37 | "@types/jest": "^23.3.12",
38 | "@types/request": "^2.48.1",
39 | "@types/request-promise-native": "^1.0.15",
40 | "babel-env": "^2.4.1",
41 | "babel-jest": "^23.6.0",
42 | "child_process": "^1.0.2",
43 | "cross-env": "^5.2.0",
44 | "gulp-babel": "^8.0.0",
45 | "gulp-rename": "^1.4.0",
46 | "gulp-sass": "^4.0.2",
47 | "jest": "^23.6.0",
48 | "node-sass": "^4.11.0",
49 | "regenerator-runtime": "^0.13.1",
50 | "request": "^2.88.0",
51 | "request-promise-native": "^1.0.5",
52 | "ts-jest": "^23.10.5"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/base/base.ts:
--------------------------------------------------------------------------------
1 | import {Data, Config} from './../model/dataModel';
2 | class Base {
3 | // 配置
4 | option: Config;
5 | // 数据
6 | data: Data;
7 | constructor(opts: Config, data: Data) {
8 | this.option = opts;
9 | this.data = data;
10 | }
11 | }
12 | export { Base };
--------------------------------------------------------------------------------
/src/file/file.ts:
--------------------------------------------------------------------------------
1 | import { Base } from './../base/base';
2 | import { mockDirName, urlsRealName } from './../utils/dict';
3 | import { Config, Data } from './../model/dataModel';
4 | import { makeFileSync, join, join2, toStr, createDir, existsSync, error } from './../utils/utils';
5 | import { jsPathError } from './../model/log';
6 |
7 | class File extends Base {
8 | constructor(opts: Config, data: Data) {
9 | super(opts, data);
10 | }
11 | //创建JSON文件
12 | async createJSONFile() {
13 | let filePromise = [];
14 | let customFileDir = join(process.cwd(), mockDirName); //默认mock相关文件目录名
15 | createDir(customFileDir);
16 | for(let fileIndex = 0; fileIndex < this.data.length; fileIndex++) {
17 | let item = this.data[fileIndex];
18 | let data = JSON.stringify(item.data);
19 | let fileUrl = join2(process.cwd(), mockDirName, item.id+".json");
20 | filePromise.push(makeFileSync(fileUrl, data));
21 | }
22 | Promise.all(filePromise).then((data) => {
23 | return;
24 | });
25 | }
26 | // 创建URL文件
27 | async createUrlFile() {
28 | return await new Promise((resolve, reject) => {
29 | let option = this.option,
30 | urlDatas = this.data;
31 | let jsContent = this.customJsTpl(urlDatas);
32 | let customFileDir = join(process.cwd(), mockDirName); //默认mock相关文件目录名
33 | let jsFilePath = join2(process.cwd(), mockDirName, `${urlsRealName}.js`); //默认生成位置,如果用户配置则生成至用户配置的位置
34 | if (option.jsPath) {
35 | //用户如果有自定义文件目录,则需要生成至用户自定义目录
36 | customFileDir = join(process.cwd(), option.jsPath);
37 | if(!existsSync(customFileDir)) return error(jsPathError);
38 | jsFilePath = join(customFileDir, `${urlsRealName}.js`);
39 | }
40 | createDir(customFileDir);
41 | makeFileSync(jsFilePath, jsContent); //生成一个js文件
42 |
43 | let jsonFilePath = join2(process.cwd(), mockDirName, `${urlsRealName}.json`); //生成一个json文件,只有全部url
44 | let jsonContent = toStr(this.jsonDeal(urlDatas)); //将要写入文件的内容串
45 | makeFileSync(jsonFilePath, jsonContent); //生成一个json文件只有url
46 | resolve();
47 | });
48 | }
49 | //根据用户定义的参数,生成指定格式的url聚合文件
50 | customJsTpl(data: any) {
51 | let tpl = require('./urlTpl'),
52 | option = this.option,
53 | host = option.realHostName;
54 | return tpl.getTpl(data, option.mockPort, host);
55 | }
56 |
57 | //处理json数据
58 | jsonDeal(urls: any) {
59 | let pathKey = '',
60 | obj: any = {};
61 | for (let key in urls) {
62 | let item = urls[key];
63 | pathKey = item.id;
64 | obj[pathKey] = {
65 | url: item.url,
66 | type: item.type
67 | };
68 | }
69 | return obj;
70 | }
71 | }
72 |
73 | export { File };
74 |
--------------------------------------------------------------------------------
/src/file/urlTpl.ts:
--------------------------------------------------------------------------------
1 | let urls: any, port: string, hostname: string;
2 |
3 | export function getTpl(_urls: any, _port: string, _hostname: string) {
4 | urls = _urls;
5 | port = _port;
6 | hostname = _hostname;
7 | let tpl = `
8 | (function (global, factory) {
9 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
10 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
11 | (global = global || self, factory(global.SMOCK = {}));
12 | }(this, (function(exports) { 'use strict';
13 | ${hostTpl()}
14 | ${restfulTpl()}
15 | var url = {
16 | ${urlTpl()}
17 | }
18 | ${moduleTpl()}
19 | })))`;
20 | return tpl;
21 | }
22 |
23 | //创建host部分
24 | function hostTpl() {
25 | let tpl = `var isDebug = (window.location.href).indexOf('debug') > -1;
26 | var host = isDebug?'//127.0.0.1:${port}':'//${hostname}';`;
27 | return tpl;
28 | }
29 |
30 | //创建RESTful函数
31 | function restfulTpl() {
32 | let tpl = `var restfulURL = function(url, param) {
33 | let result = url;
34 | for(var prop in param) {
35 | result = result.replace('{'+prop+'}', param[prop]);
36 | }
37 | return result;
38 | }`
39 | return tpl;
40 | }
41 |
42 | //创建url对象
43 | function urlTpl() {
44 | let urlTpl = '';
45 | for (let key in urls) {
46 | urlTpl += `'${urls[key].id}': {
47 | url: host + '${urls[key].url}',
48 | type: '${urls[key].type}'
49 | },`;
50 | }
51 | return urlTpl.substr(0, urlTpl.length - 1);
52 | }
53 |
54 | //创建模块依赖部分
55 | function moduleTpl() {
56 | let moduleTpl = `
57 | exports.isDebug = isDebug;
58 | exports.host = host;
59 | exports.url = url;
60 | exports.restfulURL = restfulURL;
61 |
62 | Object.defineProperty(exports, '__esModule', { value: true });
63 | `;
64 | return moduleTpl;
65 | }
66 |
--------------------------------------------------------------------------------
/src/html/desc.scss:
--------------------------------------------------------------------------------
1 | .w {
2 | width: 990px;
3 | margin: 0 auto;
4 | }
5 | .search {
6 | input {
7 | height: 40px;
8 | width: 300px;
9 | text-indent: 10px;
10 | outline: none;
11 | }
12 | }
13 | .tb {
14 | width: 100%;
15 | text-align: center;
16 | border-collapse:collapse;
17 | th:nth-child(1) {
18 | width: 200px;
19 | }
20 | th, tr {
21 | height: 40px;
22 | }
23 | th {
24 | background: #f8f8f8;
25 | }
26 | td, th {
27 | border-bottom: 1px solid #ccc;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/html/temp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 文档参数描述
9 |
10 |
11 |
12 |
13 |
14 |
接口名称:{{API}}
15 |
接口描述:{{DESC}}
16 |
17 | {{CODE}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { Swagger } from './model/swagger/swagger';
2 | import { Config, Data } from './model/dataModel';
3 | import { File } from './file/file';
4 | import { Server } from './server/server';
5 | import { log, isNew } from './utils/utils';
6 | import { docPathError } from './model/log';
7 | class Core {
8 | // 缓存参数
9 | options: Config;
10 | // 缓存数据
11 | data: Data;
12 | //数据Promise
13 | dataPromise: Promise