jj.js 0.9.0 → 0.11.0
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 +10 -0
- package/README.md +17 -92
- package/jj.js +3 -3
- package/lib/app.js +16 -0
- package/lib/config.js +4 -4
- package/lib/context.js +5 -1
- package/lib/ctx.js +39 -41
- package/lib/db.js +33 -37
- package/lib/logger.js +11 -1
- package/lib/middleware.js +2 -2
- package/lib/model.js +5 -9
- package/lib/pagination.js +3 -3
- package/lib/response.js +1 -1
- package/lib/run.js +30 -26
- package/lib/storage.js +5 -0
- package/lib/tpl/types.js +22 -0
- package/lib/types.js +215 -265
- package/lib/upload.js +2 -2
- package/lib/utils/fs.js +53 -62
- package/lib/utils/utils.js +1 -1
- package/lib/view.js +4 -3
- package/package.json +4 -1
- package/types.js +308 -0
package/lib/types.js
CHANGED
|
@@ -1,286 +1,236 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* @property {string} [port=''] - 数据库连接端口
|
|
54
|
-
* @property {string} [charset=utf8] - 数据库编码默认采用utf8
|
|
55
|
-
* @property {string} [prefix=jj_] - 数据库表前缀
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @typedef {object} DbConfig - 数据库配置
|
|
60
|
-
* @property {DbConfigItem} default - 数据库参数
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @callback LogHandle - 日志驱动
|
|
65
|
-
* @param {string} level - 日志级别
|
|
66
|
-
* @param {array} args - 日志数据,支持多个,支持对象
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @typedef {object} LogConfig - 日志配置
|
|
71
|
-
* @property {array} [log_level] - 允许输出的日志级别
|
|
72
|
-
* @property {LogHandle} [log_handle] - 日志驱动
|
|
73
|
-
*/
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @typedef {Object} CacheConfig - 缓存配置
|
|
77
|
-
* @property {number} [cache_time='60 * 60 * 24'] - 缓存时间,默认1天,为空或false则为10年
|
|
78
|
-
* @property {number} [clear_time=undefined] - 缓存自动清理周期,undefined: 清理一次, 0: 关闭自动清理, >0: 为周期时间,单位秒
|
|
79
|
-
*/
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* @typedef {Object} PageConfig - 分页配置
|
|
83
|
-
* @property {string} [page_key=page] - 分页标识
|
|
84
|
-
* @property {string} [key_origin=query] - page_key来源
|
|
85
|
-
* @property {number} [page_size=10] - page_key来源
|
|
86
|
-
* @property {number} [page_length=5] - page_key来源
|
|
87
|
-
* @property {string} [url_page] - page_key来源
|
|
88
|
-
* @property {string} [url_index] - page_key来源
|
|
89
|
-
* @property {string} [index_tpl] - 首页模板
|
|
90
|
-
* @property {string} [end_tpl] - 末页模板
|
|
91
|
-
* @property {string} [prev_tpl] - 上一页模板
|
|
92
|
-
* @property {string} [next_tpl] - 下一页模板
|
|
93
|
-
* @property {string} [list_tpl] - 数字页模板
|
|
94
|
-
* @property {string} [active_tpl] - 当前页模板
|
|
95
|
-
* @property {string} [info_tpl] - 分页信息模板
|
|
96
|
-
* @property {string} [template] - 渲染模板
|
|
97
|
-
*/
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* @typedef {Object} RouteConfigItem - 路由配置
|
|
101
|
-
* @property {string} [method=all] - 请求方法,支持['all', 'get', 'put', 'post', 'patch', 'delete', 'del']
|
|
102
|
-
* @property {string} url - 请求url,支持变量正则,详细参考@koa/router
|
|
103
|
-
* @property {(string|Middleware)} path - 响应地址(支持智能解析)或中间件函数,如果为中间件函数,则不会再执行后续代码
|
|
104
|
-
* @property {string} [type='AppConfig.controller_folder'] - 响应类型,即path对应的类型,支持controller、middleware、view(ViewConfig.view_folder)
|
|
105
|
-
* @property {string} [name] - 路由命名,命一个名字后,可以使用Url类反向编译路由url
|
|
106
|
-
*/
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* @typedef {RouteConfigItem[]} RouteConfig - 路由配置
|
|
110
|
-
*/
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* @typedef {import('cookies').SetOption} CookieConfig - Cookie配置,一般不用设置
|
|
114
|
-
*/
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* @typedef {Object} TplConfig - 跳转、调试模板配置
|
|
118
|
-
* @property {string} [jump] - 跳转模板,默认require('./tpl/jump')
|
|
119
|
-
* @property {string} [exception] - 调试异常输出模板,默认require('./tpl/exception')
|
|
120
|
-
*/
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* @typedef {Object} Config - 系统配置
|
|
124
|
-
* @property {AppConfig} [app]
|
|
125
|
-
* @property {ViewConfig} [view]
|
|
126
|
-
* @property {DbConfig} [db]
|
|
127
|
-
* @property {LogConfig} [log]
|
|
128
|
-
* @property {CacheConfig} [cache]
|
|
129
|
-
* @property {PageConfig} [page]
|
|
130
|
-
* @property {RouteConfig} [routes]
|
|
131
|
-
* @property {CookieConfig} [cookie]
|
|
132
|
-
* @property {TplConfig} [tpl]
|
|
133
|
-
*/
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
//------------------分页类--------------------
|
|
137
|
-
/**
|
|
138
|
-
* @typedef {typeof import('./pagination')} Pagination - 分页类
|
|
139
|
-
* @typedef {typeof import('./pagination').prototype} PaginationInstance - 分页类实例
|
|
140
|
-
*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//------------------数据库类--------------------
|
|
144
|
-
/**
|
|
145
|
-
* @typedef {import('mysql').Pool} Pool - 连接池
|
|
146
|
-
* @typedef {import('mysql').PoolConfig} PoolConfig - 连接池配置
|
|
147
|
-
* @typedef {import('mysql').PoolConnection} PoolConnection - 连接池连接
|
|
148
|
-
* @typedef {import('mysql').QueryOptions} QueryOptions - 查询参数
|
|
149
|
-
* @typedef {import('mysql').OkPacket} OkPacket - 数据库查询结果
|
|
150
|
-
* @typedef {Object} RowData - 单条数据
|
|
151
|
-
* @typedef {Array<RowData>} ListData - 多条数据
|
|
152
|
-
* @typedef {Object} FieldInfo - 字段信息
|
|
153
|
-
* @property {string} Field
|
|
154
|
-
* @property {string} Type
|
|
155
|
-
* @property {string} Null
|
|
156
|
-
* @property {string} Key
|
|
157
|
-
* @property {string} Default
|
|
158
|
-
* @property {string} Extra
|
|
159
|
-
* @typedef {Map<Pool>} PoolMap
|
|
160
|
-
*/
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
//------------------上传类--------------------
|
|
164
|
-
/**
|
|
165
|
-
* @typedef {Object} UploadData
|
|
166
|
-
* @property {string} [filename]
|
|
167
|
-
* @property {string} [extname]
|
|
168
|
-
* @property {string} [savename]
|
|
169
|
-
* @property {string} [filepath]
|
|
170
|
-
* @property {string} [name]
|
|
171
|
-
* @property {number} [size]
|
|
172
|
-
* @property {string} [mimetype]
|
|
173
|
-
* @property {string} [hash]
|
|
174
|
-
* /
|
|
175
|
-
*
|
|
176
|
-
/**
|
|
177
|
-
* @typedef {Object} ValidateRule
|
|
178
|
-
* @property {number} [size] - 文件大小
|
|
179
|
-
* @property {string} [ext] - 文件名后缀,多个用','隔开
|
|
180
|
-
* @property {string} [type] - 文件mimetype,多个用','隔开
|
|
181
|
-
*/
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
//------------------系统工具--------------------
|
|
185
|
-
/**
|
|
186
|
-
* @typedef {Object} Utils
|
|
187
|
-
* @property {typeof import('./utils/date')} date
|
|
188
|
-
* @property {typeof import('./utils/error')} error
|
|
189
|
-
* @property {typeof import('./utils/fs')} fs
|
|
190
|
-
* @property {typeof import('./utils/md5')} md5
|
|
191
|
-
* @property {typeof import('./utils/str')} str
|
|
192
|
-
*/
|
|
193
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fsPromises = require('fs').promises;
|
|
3
|
+
const {app: cfg_app} = require('./config');
|
|
4
|
+
const toHump = require('./utils/str').toHump;
|
|
5
|
+
const Logger = require('./logger');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* watch
|
|
9
|
+
*/
|
|
10
|
+
function start() {
|
|
11
|
+
const watch = require('watch');
|
|
12
|
+
const filter = function(f, stat) {
|
|
13
|
+
const static_dir = cfg_app.static_dir ? path.join(cfg_app.base_dir, cfg_app.static_dir) : '';
|
|
14
|
+
return (!~f.indexOf('.') || /\.js(on)?$/.test(f)) && !~f.indexOf('types.js') && (static_dir && !~f.indexOf(static_dir));
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let prevFile = {file: null,action: null,stat: null};
|
|
18
|
+
watch.watchTree(cfg_app.base_dir, {ignoreDotFiles: true, ignoreDirectoryPattern: /node_modules/, filter}, (f, curr, prev) => {
|
|
19
|
+
if(typeof f == "object" && prev === null && curr === null) {
|
|
20
|
+
// Finished walking the tree
|
|
21
|
+
Object.keys(f).forEach(file => {
|
|
22
|
+
Logger.system("wacth:", file);
|
|
23
|
+
});
|
|
24
|
+
} else if(prev === null) {
|
|
25
|
+
// f is a new file
|
|
26
|
+
if(prevFile.file != f || prevFile.action != "created") {
|
|
27
|
+
prevFile = {file: f, action: "created", stat: curr};
|
|
28
|
+
createFile(f);
|
|
29
|
+
}
|
|
30
|
+
} else if(curr.nlink === 0) {
|
|
31
|
+
// f was removed
|
|
32
|
+
if(prevFile.file != f || prevFile.action != "removed") {
|
|
33
|
+
prevFile = { file: f, action: "removed", stat: curr };
|
|
34
|
+
createFile(f);
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
// f was changed
|
|
38
|
+
if(prevFile.file === null) {
|
|
39
|
+
createFile(f);
|
|
40
|
+
} else {
|
|
41
|
+
// stat might return null, so catch errors
|
|
42
|
+
try {
|
|
43
|
+
if (prevFile.stat.mtime.getTime() !== curr.mtime.getTime()) {
|
|
44
|
+
createFile(f);
|
|
45
|
+
}
|
|
46
|
+
} catch(e) {
|
|
47
|
+
createFile(f);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
194
53
|
|
|
195
|
-
//------------------系统Context--------------------
|
|
196
54
|
/**
|
|
197
|
-
*
|
|
198
|
-
* @typedef {import('koa').Middleware} Middleware
|
|
55
|
+
* createTypesFile
|
|
199
56
|
*/
|
|
57
|
+
async function createFile(f) {
|
|
58
|
+
if(this._f == f) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if(this._f) {
|
|
62
|
+
delete require.cache[require.resolve(this._f)];
|
|
63
|
+
}
|
|
64
|
+
this._f = f;
|
|
200
65
|
|
|
66
|
+
const f_info = f.replace(cfg_app.base_dir + path.sep, '').split(path.sep);
|
|
67
|
+
if(f_info[0] && f_info[0] != cfg_app.common_app && !~f_info[0].indexOf('.')) {
|
|
68
|
+
this._APP = f_info[0];
|
|
69
|
+
}
|
|
201
70
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* @desc 系统缓存类
|
|
207
|
-
* @type {typeof import('./cache')}
|
|
208
|
-
*/
|
|
209
|
-
this.$cache;
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* @type {typeof import('./context').prototype}
|
|
213
|
-
*/
|
|
214
|
-
this.$context;
|
|
71
|
+
const ignore = ['node_modules', 'docker', 'package-lock.json', 'types.js', '.git', '.gitignore'];
|
|
72
|
+
ignore.push(path.basename(module.parent.parent.parent.filename));
|
|
73
|
+
cfg_app.static_dir && ignore.push(path.join(cfg_app.base_dir, cfg_app.static_dir));
|
|
215
74
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
*/
|
|
219
|
-
this.$controller;
|
|
75
|
+
const node_list = await getNodeList('.', ignore);
|
|
76
|
+
calcNodeList(node_list, this._APP);
|
|
220
77
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
78
|
+
const types_tpl = require('./tpl/types');
|
|
79
|
+
const types_str = types_tpl.replace('__TYPES__', createTypes(node_list)).replace('__PROPERTY__', createProps(node_list));
|
|
80
|
+
fsPromises.writeFile('types.js', types_str).then(_ => {
|
|
81
|
+
Logger.system('createTypes success:', path.join(cfg_app.base_dir, 'types.js'));
|
|
82
|
+
}).catch(err => {
|
|
83
|
+
Logger.system('createTypes error:', err);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
225
86
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
87
|
+
// 生成类型定义
|
|
88
|
+
function createTypes(node_list, base_type = '') {
|
|
89
|
+
let types = '';
|
|
90
|
+
let props = '';
|
|
91
|
+
Object.entries(node_list).forEach(([path, node]) => {
|
|
92
|
+
const type_name = toHump(base_type + '_' + node.node_name);
|
|
93
|
+
if(node.file_type == 'dir') {
|
|
94
|
+
types += createTypes(node.children, type_name);
|
|
95
|
+
} else {
|
|
96
|
+
if(!node.is_class) {
|
|
97
|
+
types += `/**\n * @typedef {typeof import('${path}')} ${type_name}\n */\n\n`;
|
|
98
|
+
} else {
|
|
99
|
+
types += `/**\n * @typedef {typeof import('${path}')} ${type_name}Class\n`;
|
|
100
|
+
types += ` * @typedef {typeof import('${path}').prototype} ${type_name}Instance\n`;
|
|
101
|
+
types += ` * @typedef {(${type_name}Class & ${type_name}Instance)} ${type_name}\n */\n\n`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
props += ` * @property {${type_name}} ${node.node_name} - ${path}\n`;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if(base_type) {
|
|
109
|
+
types += `/**\n * @typedef {object} ${base_type}\n${props} */\n\n`;
|
|
110
|
+
}
|
|
230
111
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
*/
|
|
234
|
-
this.$logger;
|
|
112
|
+
return types;
|
|
113
|
+
}
|
|
235
114
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.$middleware;
|
|
115
|
+
// 生成智能属性
|
|
116
|
+
function createProps(node_list) {
|
|
117
|
+
let props = '';
|
|
240
118
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
119
|
+
Object.entries(node_list).forEach(([path, node]) => {
|
|
120
|
+
const type_name = toHump('_' + node.node_name);
|
|
121
|
+
if(type_name != 'Config') {
|
|
122
|
+
props += `\n /** @type {${type_name}} */\n $${node.node_name}\n`;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
245
125
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
126
|
+
let type_config = 'JJConfig';
|
|
127
|
+
if(node_list['./config']) {
|
|
128
|
+
type_config = '(JJConfig & Config)';
|
|
129
|
+
}
|
|
130
|
+
props += `\n /** @type {${type_config}} */\n $config\n`;
|
|
250
131
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
*/
|
|
254
|
-
this.$response;
|
|
132
|
+
return props;
|
|
133
|
+
}
|
|
255
134
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
135
|
+
// 获取节点对象
|
|
136
|
+
async function getNodeList(dir, ignore=['node_modules', 'docker', 'package-lock.json', '.git', '.gitignore']) {
|
|
137
|
+
const isClass = require('is-class');
|
|
138
|
+
const files = await fsPromises.readdir(path.join(cfg_app.base_dir, dir), {withFileTypes: true});
|
|
139
|
+
const type_list = {};
|
|
140
|
+
for(const dirent of files) {
|
|
141
|
+
const file_name = dirent.name;
|
|
142
|
+
const file_path = dir + '/' + file_name;
|
|
143
|
+
const node_name = path.parse(file_name).name;
|
|
144
|
+
const abs_path = path.join(cfg_app.base_dir, file_path);
|
|
145
|
+
if(ignore.filter(n => abs_path.includes(n)).length) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const file_type = dirent.isFile() ? 'file' : dirent.isDirectory() ? 'dir' : '';
|
|
150
|
+
const regFile = /.+\.js(on)?$/.test(file_name);
|
|
151
|
+
const regDir = !file_name.includes('.');
|
|
152
|
+
if(file_type == 'file' && !regFile) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if(file_type == 'dir' && !regDir) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if(file_type == 'file') {
|
|
160
|
+
try {
|
|
161
|
+
// @ts-ignore
|
|
162
|
+
type_list[file_path] = {node_name, file_name, file_type, is_class: isClass(require(abs_path))};
|
|
163
|
+
} catch(e) {
|
|
164
|
+
// 包含语法错误时,require会出错
|
|
165
|
+
}
|
|
166
|
+
} else if(file_type == 'dir') {
|
|
167
|
+
type_list[file_path] = {node_name, file_name, file_type, children: await getNodeList(file_path, ignore)};;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
};
|
|
171
|
+
return type_list;
|
|
172
|
+
}
|
|
260
173
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
174
|
+
// 复制子节点
|
|
175
|
+
function copyNodeList(node_list) {
|
|
176
|
+
const copy_node_list = {};
|
|
177
|
+
Object.entries(node_list).forEach(([path, node]) => {
|
|
178
|
+
copy_node_list[path] = {...node};
|
|
179
|
+
if(node.children) {
|
|
180
|
+
copy_node_list[path].children = copyNodeList(node.children);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return copy_node_list;
|
|
184
|
+
}
|
|
265
185
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
186
|
+
// 处理common库
|
|
187
|
+
function calcNodeList(node_list, _APP) {
|
|
188
|
+
// 处理common
|
|
189
|
+
const node_common = './' + cfg_app.common_app;
|
|
190
|
+
if(cfg_app.common_app && node_list[node_common] && node_list[node_common].children) {
|
|
191
|
+
const children = copyNodeList(node_list[node_common].children);
|
|
192
|
+
Object.entries(children).forEach(([path, node]) => {
|
|
193
|
+
node_list[path] = node;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
270
196
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
197
|
+
// 处理app
|
|
198
|
+
const node_app = './' + _APP;
|
|
199
|
+
if(_APP && node_list[node_app] && node_list[node_app].children) {
|
|
200
|
+
Object.entries(node_list[node_app].children).forEach(([path, node]) => {
|
|
201
|
+
const path_common = path.replace(node_app, node_common);
|
|
202
|
+
if(!node_list[path_common]) {
|
|
203
|
+
node_list[path] = node;
|
|
204
|
+
} else if(node_list[path_common].file_type == 'file') {
|
|
205
|
+
delete node_list[path_common];
|
|
206
|
+
node_list[path] = node;
|
|
207
|
+
} else if(node.children) {
|
|
208
|
+
Object.entries(node.children).forEach(([p, n]) => {
|
|
209
|
+
const p_commmon = p.replace(node_app, node_common);
|
|
210
|
+
node_list[path_common].children[p_commmon] && delete node_list[path_common].children[p_commmon];
|
|
211
|
+
node_list[path_common].children[p] = n;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
275
216
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
217
|
+
// 特殊处理view和response
|
|
218
|
+
const node_view = './' + _APP + '/view';
|
|
219
|
+
const common_view = './' + cfg_app.common_app + '/view';
|
|
220
|
+
if(node_list[node_view] && !node_list[node_view].is_class) {
|
|
221
|
+
delete node_list[node_view];
|
|
222
|
+
}
|
|
223
|
+
if(node_list[common_view] && !node_list[common_view].is_class) {
|
|
224
|
+
delete node_list[common_view];
|
|
225
|
+
}
|
|
226
|
+
const node_response = './' + _APP + '/response';
|
|
227
|
+
const common_response = './' + cfg_app.common_app + '/response';
|
|
228
|
+
if(node_list[node_response] && !node_list[node_response].is_class) {
|
|
229
|
+
delete node_list[node_response];
|
|
230
|
+
}
|
|
231
|
+
if(node_list[common_response] && !node_list[common_response].is_class) {
|
|
232
|
+
delete node_list[common_response];
|
|
280
233
|
}
|
|
281
234
|
}
|
|
282
235
|
|
|
283
|
-
|
|
284
|
-
* @module Types
|
|
285
|
-
*/
|
|
286
|
-
module.exports = Ctx;
|
|
236
|
+
module.exports = start;
|
package/lib/upload.js
CHANGED
|
@@ -7,8 +7,8 @@ const {app: cfg_app} = require('./config');
|
|
|
7
7
|
/**
|
|
8
8
|
* @typedef {import('formidable').Files} Files
|
|
9
9
|
* @typedef {import('formidable').File} File
|
|
10
|
-
* @typedef {import('
|
|
11
|
-
* @typedef {import('
|
|
10
|
+
* @typedef {import('../types').UploadData} UploadData
|
|
11
|
+
* @typedef {import('../types').ValidateRule} ValidateRule
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
package/lib/utils/fs.js
CHANGED
|
@@ -1,78 +1,69 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const fsPromises = require('fs').promises;
|
|
2
3
|
const pt = require('path');
|
|
3
|
-
const fsFun = {};
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
resolve(data || true);
|
|
17
|
-
}];
|
|
18
|
-
item === 'readFile' ? arg.unshift(copypath || 'utf8') : null;
|
|
19
|
-
item === 'copyFile' ? arg.unshift(copypath || '') : null;
|
|
20
|
-
fs[item](pathname, ...arg)
|
|
21
|
-
});
|
|
5
|
+
// 是否存在
|
|
6
|
+
const exists = async path => {
|
|
7
|
+
try {
|
|
8
|
+
await fsPromises.stat(path);
|
|
9
|
+
return true;
|
|
10
|
+
} catch(err) {
|
|
11
|
+
if(err.code === 'ENOENT') {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
throw err;
|
|
22
15
|
}
|
|
23
|
-
}
|
|
16
|
+
}
|
|
24
17
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
resolve(data || '');
|
|
37
|
-
});
|
|
38
|
-
});
|
|
18
|
+
// 是否文件
|
|
19
|
+
const isFile = async path => {
|
|
20
|
+
try {
|
|
21
|
+
const stats = await fsPromises.stat(path);
|
|
22
|
+
return stats.isFile();
|
|
23
|
+
} catch(err) {
|
|
24
|
+
if(err.code === 'ENOENT') {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
throw err;
|
|
39
28
|
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
fsFun.isDirSync = (path) => {return fs.existsSync(path) && fs.statSync(path).isDirectory();}
|
|
29
|
+
}
|
|
30
|
+
const isFileSync = path => {
|
|
31
|
+
return fs.existsSync(path) && fs.statSync(path).isFile();
|
|
32
|
+
}
|
|
45
33
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
reject(error);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}).catch((error) => {
|
|
60
|
-
reject(error);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
34
|
+
// 是否目录
|
|
35
|
+
const isDir = async path => {
|
|
36
|
+
try {
|
|
37
|
+
const stats = await fsPromises.stat(path);
|
|
38
|
+
return stats.isDirectory();
|
|
39
|
+
} catch(err) {
|
|
40
|
+
if(err.code === 'ENOENT') {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
throw err;
|
|
63
44
|
}
|
|
64
|
-
}
|
|
45
|
+
}
|
|
46
|
+
const isDirSync = path => {
|
|
47
|
+
return fs.existsSync(path) && fs.statSync(path).isDirectory();
|
|
48
|
+
}
|
|
65
49
|
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
if(await
|
|
50
|
+
// 生成多级目录
|
|
51
|
+
const mkdirs = async function (dirname) {
|
|
52
|
+
if(await isDir(dirname)) {
|
|
69
53
|
return true;
|
|
70
54
|
} else {
|
|
71
|
-
if(await
|
|
72
|
-
await
|
|
55
|
+
if(await mkdirs(pt.dirname(dirname))) {
|
|
56
|
+
await fsPromises.mkdir(dirname);
|
|
73
57
|
return true;
|
|
74
58
|
}
|
|
75
59
|
}
|
|
76
60
|
}
|
|
77
61
|
|
|
78
|
-
module.exports =
|
|
62
|
+
module.exports = {
|
|
63
|
+
exists,
|
|
64
|
+
isFile,
|
|
65
|
+
isFileSync,
|
|
66
|
+
isDir,
|
|
67
|
+
isDirSync,
|
|
68
|
+
mkdirs
|
|
69
|
+
};
|