mock-service-cli 2.0.5 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [2.3.1](https://github.com/chandq/mock-service-cli/compare/v2.2.0...v2.3.1) (2022-01-01)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * issue of execute unit test case failed ([69f4609](https://github.com/chandq/mock-service-cli/commit/69f46099ed5b26de5d4cca523c56afcbf4db5f2c))
11
+
12
+ ## [2.2.0](https://github.com/chandq/mock-service-cli/compare/v2.1.1...v2.2.0) (2021-12-31)
13
+
14
+
15
+ ### Features
16
+
17
+ * 丰富日志工具函数 ([4dcd69c](https://github.com/chandq/mock-service-cli/commit/4dcd69c6400f65aaf77ea4a2923c9900d5954d09))
18
+ * 监听文件变化和写文件互斥执行 ([cfeab8e](https://github.com/chandq/mock-service-cli/commit/cfeab8ede05573974125a9fa91f1db6afa8a898d))
19
+ * record operation log ([42b74d8](https://github.com/chandq/mock-service-cli/commit/42b74d8be0e694600c999490d3fe93bfb3620051))
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * issue of write large file failed ([d1c470d](https://github.com/chandq/mock-service-cli/commit/d1c470daf9829916016b73993b114fc5ffe3c985))
25
+
26
+ ### [2.1.1](https://github.com/chandq/mock-service-cli/compare/v2.1.0...v2.1.1) (2021-12-30)
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * issue of friendly show error tip ([e9822c2](https://github.com/chandq/mock-service-cli/commit/e9822c2038ad411d91a170af33e7541e266ca8e6))
32
+ * issue of empty file content ([3949e00](https://github.com/chandq/mock-service-cli/commit/3949e00a46b4555bc08ec8564221cc230c780dcb))
33
+
34
+ ## [2.1.0](https://github.com/chandq/mock-service-cli/compare/v2.0.5...v2.1.0) (2021-12-30)
35
+
36
+
37
+ ### Features
38
+
39
+ * 根据命令行参数决定是否 打印api统计信息 ([0e838db](https://github.com/chandq/mock-service-cli/commit/0e838db7820fd096163d14eb87abbd9b852b6a0e))
40
+ * add arguments description ([097b373](https://github.com/chandq/mock-service-cli/commit/097b3733a1da0b43dae6b50080d270323b92f0d2))
41
+
42
+
43
+ ### Bug Fixes
44
+
45
+ * issue of comment typo ([85297a5](https://github.com/chandq/mock-service-cli/commit/85297a5895fd7c0446ee8b90a58ebed90a02e9e7))
46
+ * issue of maybe write content to file failed ([8ed910b](https://github.com/chandq/mock-service-cli/commit/8ed910b1e9687cae46ad6bdab641db0c305c83fb))
47
+ * socket connection show datetime ([c6db3b4](https://github.com/chandq/mock-service-cli/commit/c6db3b47a2370dc1c9aba5495dbb6606c20eb0c9))
48
+
5
49
  ### [2.0.5](https://github.com/chandq/mock-service-cli/compare/v2.0.4...v2.0.5) (2021-12-28)
6
50
 
7
51
 
package/README.md CHANGED
@@ -45,15 +45,17 @@ This will install `mock-service-cli` globally so that it may be run from the com
45
45
 
46
46
  `[path]` defaults to `./mock` .
47
47
 
48
- | Command | Description | Defaults |
49
- | ------------------- | -------------------------------------------------------------------------------------------------------------- | -------- |
50
- | `-p` or `--port` | Port to use. Use `-p 0` to look for an open port, starting at 8090. It will also read from `process.env.PORT`. | 8090 |
51
- | `-d` | Specify mock directory | ./mock |
52
- | `-f` | Specify mock file | |
53
- | `-s` or `--silent` | Suppress log messages from output | |
54
- | `-h` or `--help` | Print this list and exit. | |
55
- | `-v` or `--version` | Print the version and exit. | |
56
- | `--ss` | Start socket server which used to save api response data for future mock. | false |
48
+ | Command | Description | Defaults |
49
+ | ------------------------- | -------------------------------------------------------------------------------------------------------------- | -------- |
50
+ | `-p` or `--port` | Port to use. Use `-p 0` to look for an open port, starting at 8090. It will also read from `process.env.PORT`. | 8090 |
51
+ | `-d` | Specify mock directory | ./mock |
52
+ | `-f` | Specify mock file | |
53
+ | `-s` or `--silent` | Suppress log messages from output | |
54
+ | `-h` or `--help` | Print this list and exit. | |
55
+ | `-v` or `--version` | Print the version and exit. | |
56
+ | `-S` or `--socket-server` | Start socket server which used to save api response data for future mock. | false |
57
+ | `-a` or `--api-stat` | Whether print api url and file path info or not, default false. | false |
58
+ | `-l` or `--log` | Whether record operation info by write file, default false. | false |
57
59
 
58
60
  ## Example
59
61
 
@@ -71,7 +73,7 @@ This will install `mock-service-cli` globally so that it may be run from the com
71
73
 
72
74
  4. Start socket server for used to save api response data.
73
75
 
74
- `mock-service-cli --ss`
76
+ `mock-service-cli -S`
75
77
 
76
78
  ### 编写 Mock 文件
77
79
 
@@ -124,6 +126,8 @@ module.exports = {
124
126
 
125
127
  ### 借助 socket.io 保留接口数据
126
128
 
129
+ > `save-data` 和 `mock-dir-stat` 事件会自动生成 `mock-list.json` 文件(维护接口`<url, [method]>`的关系映射),方便查阅接口统计信息
130
+
127
131
  ```js
128
132
  // 连接SocketServer
129
133
  import { io } from 'socket.io-client';
@@ -6,6 +6,8 @@ const colors = require('colors/safe'),
6
6
  nodemon = require('nodemon');
7
7
  const argv = require('minimist')(process.argv.slice(2));
8
8
  const { logger } = require('../lib/utils');
9
+ const spawn = require('child_process').spawn;
10
+ const node = process.execPath;
9
11
  process.title = 'mock-service-cli';
10
12
 
11
13
  if (argv.h || argv.help) {
@@ -20,7 +22,9 @@ if (argv.h || argv.help) {
20
22
  ' -f --file Specify the input data source, support javascript ',
21
23
  ' The priority is over the directory watches',
22
24
  ' -s --silent Suppress log messages from output',
23
- ' --ss Whether start socket server or not, default false.',
25
+ ' -S --socket-server Whether start socket server or not, default false.',
26
+ ' -a --api-stat Whether print api url and file path or not, default false.',
27
+ ' -l --log Whether record operation info by write file, default false.',
24
28
  '',
25
29
  ' -h --help Print this list and exit.',
26
30
  ' -v --version Print the version and exit.'
@@ -29,11 +33,14 @@ if (argv.h || argv.help) {
29
33
  process.exit();
30
34
  }
31
35
 
36
+ // 保留命令行参数
37
+ process.env.ARGV = JSON.stringify(argv);
38
+
32
39
  var port = argv.p || argv.port,
33
40
  watchDir = argv.d,
34
41
  specifiedFile = argv.f || argv.file,
35
42
  version = argv.v || argv.version,
36
- isStartSocketServer = argv.ss || false,
43
+ isStartSocketServer = argv.S || false,
37
44
  log = null;
38
45
 
39
46
  if (!argv.s && !argv.silent) {
@@ -44,7 +51,7 @@ if (!argv.s && !argv.silent) {
44
51
  }
45
52
 
46
53
  if (isStartSocketServer) {
47
- process.env.SOCKETSERVER = true;
54
+ process.env.SOCKET_SERVER = true;
48
55
  }
49
56
 
50
57
  if (version) {
@@ -90,16 +97,34 @@ const watchMockFiles = function (watchDir) {
90
97
  );
91
98
  });
92
99
  };
100
+ // Node子进程启动MockServer
101
+ const startMockServer = function () {
102
+ spawn(node, [path.resolve(__dirname, '../lib/mockServer.js')], {
103
+ stdio: 'inherit'
104
+ });
105
+ };
93
106
 
94
107
  if (specifiedFile) {
95
108
  process.env.SPECIFIED_FILE = path.resolve(process.cwd(), specifiedFile);
96
- watchMockFiles(process.env.SPECIFIED_FILE);
109
+ if (isStartSocketServer) {
110
+ startMockServer();
111
+ } else {
112
+ watchMockFiles(process.env.SPECIFIED_FILE);
113
+ }
97
114
  } else if (watchDir) {
98
115
  process.env.SPECIFIED_DIR = path.resolve(process.cwd(), watchDir);
99
116
  // log.info('SPECIFIED_DIR::', process.env.SPECIFIED_DIR);
100
- watchMockFiles(process.env.SPECIFIED_DIR);
117
+ if (isStartSocketServer) {
118
+ startMockServer();
119
+ } else {
120
+ watchMockFiles(process.env.SPECIFIED_DIR);
121
+ }
101
122
  } else {
102
123
  watchDir = process.env.SPECIFIED_DIR = path.resolve(process.cwd(), './mock');
103
124
  // log.info('SPECIFIED_DIR::', process.env.SPECIFIED_DIR);
104
- watchMockFiles(watchDir);
125
+ if (isStartSocketServer) {
126
+ startMockServer();
127
+ } else {
128
+ watchMockFiles(watchDir);
129
+ }
105
130
  }
@@ -2,7 +2,7 @@
2
2
  * @description: 生成Mock文件、获取mock数据统计
3
3
  * @Date: 2021-12-22 16:57:08
4
4
  * @LastEditors: chendq
5
- * @LastEditTime: 2021-12-28 16:23:43
5
+ * @LastEditTime: 2022-01-01 10:51:12
6
6
  * @Author: chendq
7
7
  */
8
8
  const fsa = require('fs-extra'),
@@ -10,12 +10,22 @@ const fsa = require('fs-extra'),
10
10
  path = require('path'),
11
11
  _ = require('lodash'),
12
12
  colors = require('colors/safe');
13
- const { getFileLatestContent, SupportMethods, filePath2ApiUrl, logger } = require('./utils');
13
+ const {
14
+ getFileLatestContent,
15
+ SupportMethods,
16
+ filePath2ApiUrl,
17
+ logger,
18
+ getDataType,
19
+ getLogger,
20
+ writeStream
21
+ } = require('./utils');
14
22
  const log = logger(process.env.SILENT);
23
+ const processArgv = process.env.ARGV ? JSON.parse(process.env.ARGV) : {};
24
+ let LOGGER = getLogger();
15
25
 
16
26
  const methodRegExp = new RegExp(`(${SupportMethods.join('|')}) +(.*)`, 'i');
17
27
  /**
18
- * @description: 生成mock文件
28
+ * @description: 生成mock文件(自动生成mock-list.json文件,并维护<url, [method]>的关系映射)
19
29
  * @param {string} apiUrl 请求url
20
30
  * @param {string} method 请求方法
21
31
  * @param {object} resJsonData 响应数据
@@ -24,13 +34,26 @@ const methodRegExp = new RegExp(`(${SupportMethods.join('|')}) +(.*)`, 'i');
24
34
  *
25
35
  */
26
36
  const genMockFiles = function ({ url: apiUrl, method, data: resJsonData, dir: mockDir }) {
37
+ const type = getDataType(resJsonData);
27
38
  if (!apiUrl || !method || !resJsonData || !mockDir) {
28
39
  log.info(
29
- colors.red(`参数: apiUrl: ${apiUrl}, method: ${method}, resJsonData: ${resJsonData}, mockDir: ${mockDir}无效`)
40
+ colors.red([`参数: apiUrl: ${apiUrl}, method: ${method}, mockDir: ${mockDir} `, `必须是有效值`].join(','))
41
+ );
42
+ return;
43
+ } else if (
44
+ !['object', 'array'].includes(type) ||
45
+ (type === 'object' && Object.keys(resJsonData).length === 0) ||
46
+ (type === 'array' && resJsonData.length === 0)
47
+ ) {
48
+ log.info(
49
+ `参数: apiUrl: ${apiUrl}, method: ${method}, resJsonData:`,
50
+ resJsonData,
51
+ colors.red(', 参数字段resJsonData必须是非空的数组或对象!')
30
52
  );
31
53
  return;
32
54
  }
33
55
  apiUrl = apiUrl.trim().split('?')[0];
56
+ LOGGER = getLogger(mockDir);
34
57
  const normalizeApiUrl = filePath2ApiUrl(path.normalize(apiUrl));
35
58
  const mockListFilePath = path.resolve(process.cwd(), `${mockDir}/mock-list.json`);
36
59
  const mockFilePath = path.resolve(process.cwd(), `${mockDir}/${encodeURIComponent(path.normalize(apiUrl))}.json`);
@@ -51,7 +74,7 @@ const genMockFiles = function ({ url: apiUrl, method, data: resJsonData, dir: mo
51
74
  }
52
75
  if (!oldMockListContent || !_.isEqual(oldMockListContent, newMockListContent)) {
53
76
  Object.keys(newMockListContent).length > 0 &&
54
- fsa.writeFileSync(mockListFilePath, JSON.stringify(newMockListContent, null, 2));
77
+ writeStream(mockListFilePath, JSON.stringify(newMockListContent, null, 2));
55
78
  }
56
79
 
57
80
  // mock文件存在
@@ -65,19 +88,24 @@ const genMockFiles = function ({ url: apiUrl, method, data: resJsonData, dir: mo
65
88
  // );
66
89
  return;
67
90
  }
68
- mockFileContent[method] = resJsonData ? resJsonData : {};
69
- Object.keys(mockFileContent).length > 0 &&
70
- fsa.writeFileSync(mockFilePath, JSON.stringify(mockFileContent, null, 2));
91
+ mockFileContent[method] = resJsonData;
92
+ writeStream(mockFilePath, JSON.stringify(mockFileContent, null, 2));
93
+ if (processArgv.l || processArgv.log) {
94
+ LOGGER.log(`Update file: ${method} ${apiUrl} ${mockFilePath}`);
95
+ }
71
96
  } else {
72
97
  // fsa.ensureFileSync(mockFilePath);
73
- Object.keys(mockFilePath).length > 0 &&
74
- fsa.writeFileSync(mockFilePath, JSON.stringify({ [method]: resJsonData ? resJsonData : {} }, null, 2));
98
+
99
+ writeStream(mockFilePath, JSON.stringify({ [method]: resJsonData }, null, 2));
100
+ if (processArgv.l || processArgv.log) {
101
+ LOGGER.log(`Write new file: ${method} ${apiUrl} ${mockFilePath}`);
102
+ }
75
103
  }
76
104
  // console.debug('file::', `${mockDir}/${apiUrl}`, newMockListContent);
77
105
  };
78
106
  /**
79
107
  * @description: 从js文件中收集mock数据
80
- * @param {map} mockDataMap
108
+ * @param {object} mockDataMap
81
109
  * @param {string} filePath
82
110
  * @return {*} void
83
111
  */
@@ -103,7 +131,7 @@ const collectMockDataFromJsFile = function (mockDataMap, filePath) {
103
131
 
104
132
  /**
105
133
  * @description: 递归收集mock数据
106
- * @param {map} mockDataMap mock数据集
134
+ * @param {object} mockDataMap mock数据集
107
135
  * @param {string} specialDir 目录
108
136
  * @return {*} void
109
137
  */
@@ -136,27 +164,47 @@ const deepCollectMockData = function (mockDataMap, specialDir = '../mock') {
136
164
  }
137
165
  };
138
166
  /**
139
- * @description: 从文件目录中获取mock数据统计
167
+ * @description: 从文件目录中获取mock数据统计(若mock-list.json文件不存在则自动生成)
140
168
  * @param {string} dirPath
141
- * @return {map} mock数据统计
169
+ * @return {object} mock数据统计
142
170
  */
143
171
  const getMockStatFromDir = dirPath => {
144
172
  if (!fsa.pathExistsSync(dirPath)) {
145
- throw new Error(`如参无效,${dirPath} 目录不存在`);
173
+ throw new Error(`入参无效,${dirPath} 目录不存在`);
146
174
  }
147
175
  const mockDataMap = {};
148
176
  deepCollectMockData(mockDataMap, dirPath);
177
+
178
+ const mockListFilePath = path.resolve(process.cwd(), `${dirPath}/mock-list.json`);
179
+ // 若不存在mock-list.json文件,则根据现有mock文件重新生成<api, [method]>映射关系
180
+ if (Object.keys(mockDataMap).length > 0 && !fsa.pathExistsSync(mockListFilePath)) {
181
+ fsa.ensureFileSync(mockListFilePath);
182
+ const reverseMockList = {};
183
+ Object.keys(mockDataMap).forEach(it => {
184
+ if (methodRegExp.exec(it)) {
185
+ const [, method, url] = methodRegExp.exec(it);
186
+ if (url.trim() && method.trim()) {
187
+ if (reverseMockList.hasOwnProperty(url)) {
188
+ reverseMockList[url].push(method);
189
+ } else {
190
+ reverseMockList[url] = [method];
191
+ }
192
+ }
193
+ }
194
+ });
195
+ writeStream(mockListFilePath, JSON.stringify(reverseMockList, null, 2));
196
+ }
149
197
  return mockDataMap;
150
198
  };
151
199
 
152
200
  /**
153
201
  * @description: 从js文件中获取mock数据统计
154
202
  * @param {string} filePath
155
- * @return {map} mock数据统计
203
+ * @return {object} mock数据统计
156
204
  */
157
205
  const getMockStatFromFile = filePath => {
158
206
  if (!fsa.pathExistsSync(filePath)) {
159
- throw new Error(`如参无效,${filePath} 文件不存在`);
207
+ throw new Error(`入参无效,${filePath} 文件不存在`);
160
208
  }
161
209
  const mockDataMap = {};
162
210
  collectMockDataFromJsFile(mockDataMap, filePath);
@@ -171,7 +219,7 @@ const getMockStatFromFile = filePath => {
171
219
  */
172
220
  const hasMockApi = function (mockDataMap, apiUrl, method) {
173
221
  if (!apiUrl || !method || !mockDataMap || !(mockDataMap instanceof Object)) {
174
- throw new Error(`如参无效,${mockDataMap} 必须是 mock数据的Object对象`);
222
+ throw new Error(`入参无效,${mockDataMap} 必须是 mock数据的Object对象`);
175
223
  }
176
224
  return mockDataMap.hasOwnProperty(`${method.toLocaleLowerCase()} ${path.normalize(apiUrl)}`);
177
225
  };
package/lib/mockServer.js CHANGED
@@ -14,6 +14,7 @@ const methodRegExp = new RegExp(`(${SupportMethods.join('|')}) +(.*)`, 'i');
14
14
 
15
15
  const app = express();
16
16
  const log = logger(process.env.SILENT);
17
+ const argv = JSON.parse(process.env.ARGV);
17
18
  let socketServer = null; // Socket server instance
18
19
 
19
20
  let count = 0,
@@ -64,7 +65,7 @@ const composeRouteFromJsFile = function (file) {
64
65
  // 先删除require之前导入的缓存文件,否则获取到的文件内容还是旧内容
65
66
  const fileObject = getFileLatestContent(file);
66
67
 
67
- log.info(colors.green(`Mockfile ${++fileCount}: `), file, colors.yellow('all API URL is follows: '));
68
+ argv.a && log.info(colors.green(`Mockfile ${++fileCount}: `), file, colors.yellow('all API URL is follows: '));
68
69
  Object.keys(fileObject).forEach(item => {
69
70
  let reqMethod = 'get',
70
71
  reqUrl = item;
@@ -74,7 +75,7 @@ const composeRouteFromJsFile = function (file) {
74
75
  reqMethod = method.toLowerCase();
75
76
  reqUrl = url;
76
77
  }
77
- log.info(colors.yellow(`path ${++count}: `), item, colors.blue(typeof fileObject[item]));
78
+ argv.a && log.info(colors.yellow(`path ${++count}: `), item, colors.blue(typeof fileObject[item]));
78
79
  log.assert(typeof app[reqMethod] === 'function', colors.red(`${file}, ${reqMethod}`));
79
80
  if (typeof fileObject[item] === 'function') {
80
81
  app[reqMethod](reqUrl, fileObject[item]);
@@ -103,12 +104,14 @@ const parseMockFiles = function (specialDir = '../mock') {
103
104
 
104
105
  // 处理存放mock数据的json文件
105
106
  if (el.name.endsWith('.json') && el.name !== 'mock-list.json') {
106
- log.info(colors.green(`Mockfile ${++fileCount}: `), filePath, colors.yellow('all API URL is follows: '));
107
+ argv.a &&
108
+ log.info(colors.green(`Mockfile ${++fileCount}: `), filePath, colors.yellow('all API URL is follows: '));
107
109
  const fileObject = getFileLatestContent(filePath);
108
110
  // eslint-disable-next-line no-loop-func
109
111
  Object.keys(fileObject).forEach(method => {
110
112
  const apiUrl = filePath2ApiUrl(decodeURIComponent(el.name.split('.')[0]));
111
- log.info(colors.yellow(`path ${++count}: `), `${method} ${apiUrl}`, colors.blue(typeof fileObject[method]));
113
+ argv.a &&
114
+ log.info(colors.yellow(`path ${++count}: `), `${method} ${apiUrl}`, colors.blue(typeof fileObject[method]));
112
115
  log.assert(typeof app[method] === 'function', colors.red(`${filePath}, ${method}`));
113
116
  app[method](apiUrl, function (req, res) {
114
117
  res.json(fileObject[method]);
@@ -130,15 +133,17 @@ if (process.env.SPECIFIED_FILE) {
130
133
  } else {
131
134
  parseMockFiles(process.env.SPECIFIED_DIR);
132
135
  }
133
- log.info(chalk.hex('#ce5b34bd')(`${fileCount} mock file are parsed in total.`));
136
+ argv.a && log.info(chalk.hex('#ce5b34bd')(`${fileCount} mock file are parsed in total.`));
134
137
  const http = require('http').createServer(app);
135
- if (process.env.SOCKETSERVER) {
138
+ if (process.env.SOCKET_SERVER) {
136
139
  socketServer = new Server(http, { path: '/ws/mock-service' });
137
140
  log.info(colors.bgBlue(`Socket server has started. path: /ws/mock-service, `));
138
141
  socketServer.of('/mock-data').on('connection', function (socket) {
139
142
  const { headers, address } = socket.handshake;
140
143
  const clientIp = headers.hasOwnProperty('x-forwarded-for') ? headers['x-forwarded-for'] : address;
141
- log.info(colors.green(`Socket client ${clientIp} has connected.`));
144
+ log.info(
145
+ colors.green(`Socket client ${clientIp} has connected. --- ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`)
146
+ );
142
147
  socket.on('mock-dir-stat', function (dir) {
143
148
  socket.emit('mock-dir-stat', getMockStatFromDir(dir));
144
149
  });
@@ -151,7 +156,11 @@ if (process.env.SOCKETSERVER) {
151
156
  });
152
157
 
153
158
  socket.on('disconnect', function () {
154
- log.info(colors.gray(`Socket client ${clientIp} has disconnected.`));
159
+ log.info(
160
+ colors.gray(
161
+ `Socket client ${clientIp} has disconnected. --- ${dateFormat('YYYY-mm-dd HH:MM:SS', new Date())}`
162
+ )
163
+ );
155
164
  });
156
165
  });
157
166
  }
package/lib/utils.js CHANGED
@@ -1,27 +1,40 @@
1
1
  /*
2
- * @description:
2
+ * @description: 工具函数库
3
3
  * @Date: 2021-12-25 17:52:48
4
4
  * @LastEditors: chendq
5
- * @LastEditTime: 2021-12-27 13:12:16
5
+ * @LastEditTime: 2021-12-31 23:10:02
6
6
  * @Author: chendq
7
7
  */
8
+ const fs = require('fs');
9
+ const path = require('path');
8
10
  /**
9
11
  * @description: 输出和错误输出写入不同文件
10
- * @param {*}
11
- * @return {*}
12
+ * @param {string} logFileDirPath
13
+ * @return {object}
12
14
  */
13
- const path = require('path');
14
- const getLogger = function () {
15
- const fs = require('fs');
16
- const output = fs.createWriteStream('./stdout.log');
17
- const errorOutput = fs.createWriteStream('./stderr.log');
15
+ const getLogger = function (logFileDirPath) {
16
+ const options = {
17
+ flags: 'a', // append模式
18
+ encoding: 'utf8' // utf8编码
19
+ };
20
+ const output = fs.createWriteStream(
21
+ path.resolve(logFileDirPath ? logFileDirPath : process.cwd(), './stdout.log'),
22
+ options
23
+ );
24
+ const errorOutput = fs.createWriteStream(
25
+ path.resolve(logFileDirPath ? logFileDirPath : process.cwd(), './stderr.log'),
26
+ options
27
+ );
18
28
  // 自定义日志打印
19
29
  const logger = new console.Console(output, errorOutput);
20
30
 
21
- logger.log('向 stdout 中写入数据');
22
- logger.error('向 stderr 中写入数据');
31
+ // logger.log('向 stdout 中写入数据');
32
+ // logger.error('向 stderr 中写入数据');
23
33
 
24
- return logger;
34
+ return {
35
+ log: (...args) => logger.log.call(null, `[${dateFormat('YYYY-mm-dd HH:MM:SS:fff')}] - `, ...args),
36
+ error: (...args) => logger.error.call(null, `[${dateFormat('YYYY-mm-dd HH:MM:SS:fff')}] - `, ...args)
37
+ };
25
38
  };
26
39
  /**
27
40
  * @description: 格式化时间日期
@@ -29,7 +42,7 @@ const getLogger = function () {
29
42
  * @param {*} date
30
43
  * @returns {*}
31
44
  */
32
- function dateFormat(fmt, date) {
45
+ function dateFormat(fmt, date = new Date()) {
33
46
  let ret;
34
47
  const opt = {
35
48
  'Y+': date.getFullYear().toString(), // 年
@@ -37,7 +50,8 @@ function dateFormat(fmt, date) {
37
50
  'd+': date.getDate().toString(), // 日
38
51
  'H+': date.getHours().toString(), // 时
39
52
  'M+': date.getMinutes().toString(), // 分
40
- 'S+': date.getSeconds().toString() // 秒
53
+ 'S+': date.getSeconds().toString(), // 秒
54
+ 'f+': date.getMilliseconds().toString() // 毫秒
41
55
  // 有其他格式化字符需求可以继续添加,必须转化成字符串
42
56
  };
43
57
  // eslint-disable-next-line guard-for-in
@@ -93,6 +107,59 @@ const getFileLatestContent = function (filePath) {
93
107
  const filePath2ApiUrl = function (filePath) {
94
108
  return filePath.split(path.sep).join('/');
95
109
  };
110
+ /**
111
+ * @description: 获取数据类型
112
+ * @param {any} data 数据值
113
+ * @return {string} 数据类型
114
+ */
115
+ const getDataType = function (data) {
116
+ return Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
117
+ };
118
+ /**
119
+ * @description: 流方式写文件(适合写超大文件)
120
+ * @param {string} filePath
121
+ * @param {object} data
122
+ * @return {*}
123
+ */
124
+ const writeStream = function (filePath, data) {
125
+ // 创建一个可写流 也会创建一个test1.txt文件
126
+ const writerStream = fs.createWriteStream(filePath);
127
+ // 将数据写入流
128
+ writerStream.write(data, 'utf-8');
129
+ // 标记文件的结束
130
+ writerStream.end();
131
+ writerStream.on('finish', () => {
132
+ // console.log('写入完成');
133
+ });
134
+ writerStream.on('error', () => {
135
+ console.error(`${filePath} 写入失败`);
136
+ });
137
+ };
138
+ /**
139
+ * @description: 流方式读文件(适合写超大文件)
140
+ * @param {string} filePath
141
+ * @return {*}
142
+ */
143
+ const readeStream = function (filePath) {
144
+ let data = '';
145
+ // 创建可读流
146
+ return new Promise((resovle, reject) => {
147
+ const readerStream = fs.createReadStream(filePath);
148
+ // 设置编码为 utf8。
149
+ readerStream.setEncoding('UTF8');
150
+ // 处理流事件 --> data, end, and error
151
+ readerStream.on('data', function (chunk) {
152
+ data += chunk;
153
+ });
154
+ readerStream.on('end', function () {
155
+ resovle(data);
156
+ });
157
+ readerStream.on('error', function (err) {
158
+ reject(err);
159
+ console.log(err.stack);
160
+ });
161
+ });
162
+ };
96
163
 
97
164
  module.exports = {
98
165
  getLogger,
@@ -101,5 +168,8 @@ module.exports = {
101
168
  SupportMethods,
102
169
  isValidMethod,
103
170
  getFileLatestContent,
104
- filePath2ApiUrl
171
+ filePath2ApiUrl,
172
+ getDataType,
173
+ writeStream,
174
+ readeStream
105
175
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mock-service-cli",
3
- "version": "2.0.5",
3
+ "version": "2.3.1",
4
4
  "description": "🦅 Local mock server",
5
5
  "main": "./lib/mockServer.js",
6
6
  "bin": {