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/lib/types.js CHANGED
@@ -1,286 +1,236 @@
1
- //------------------系统核心库------------------
2
- /**
3
- * @typedef {Object} Core
4
- * @property {typeof import('./app')} App
5
- * @property {typeof import('./cache')} Cache
6
- * @property {typeof import('./context')} Context
7
- * @property {typeof import('./controller')} Controller
8
- * @property {typeof import('./cookie')} Cookie
9
- * @property {typeof import('./db')} Db
10
- * @property {typeof import('./logger')} Logger
11
- * @property {typeof import('./middleware')} Middleware
12
- * @property {typeof import('./model')} Model
13
- * @property {typeof import('./pagination')} Pagination
14
- * @property {typeof import('./response')} Response
15
- * @property {typeof import('./upload')} Upload
16
- * @property {typeof import('./url')} Url
17
- * @property {typeof import('./view')} View
18
- * @property {Utils} utils
19
- */
20
-
21
-
22
- //------------------系统App配置---------------------
23
- /**
24
- * @typedef {Object} AppConfig - 系统配置
25
- * @property {boolean} [app_debug=true] - 调试模式
26
- * @property {boolean} [app_multi=false] - 是否开启多应用
27
- * @property {string} [default_app=app] - 默认应用
28
- * @property {string} [default_controller=index] - 默认控制器
29
- * @property {string} [default_action=index] - 默认方法
30
- * @property {string} [common_app=common] - 公共应用,存放公共模型及逻辑
31
- * @property {string} [controller_folder=controller] - 控制器目录名
32
- * @property {(string|boolean)} [static_dir=''] - 静态文件目录,相对于应用根目录,为空或false时,关闭静态访问
33
- * @property {(string|boolean|null|object)} [koa_body=null] - koa-body配置参数,为''、null、false时,关闭koa-body
34
- * @property {string} [base_dir] - 应用根目录(会自动计算)
35
- */
36
-
37
- /**
38
- * @typedef {Object} ViewConfig - 模板配置
39
- * @property {string} [view_folder=view] - 模板目录名
40
- * @property {string} [view_depr='/'] - 模版文件名分割符,'/'代表二级目录
41
- * @property {string} [view_ext='.htm'] - 模版文件后缀
42
- * @property {string} [view_engine=art-template] - 默认模版引擎,字符串或引擎类
43
- * @property {object} [view_filte={}] - 模版函数
44
- */
45
-
46
- /**
47
- * @typedef {Object} DbConfigItem - 数据库参数
48
- * @property {string} [type=mysql] - 数据库类型
49
- * @property {string} [host='127.0.0.1'] - 服务器地址
50
- * @property {string} [database=jj] - 数据库名
51
- * @property {string} [user=root] - 数据库用户名
52
- * @property {string} [password=''] - 数据库密码
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
- * @typedef {import('koa').Context} Context
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
- //------------------Ctx系统基类--------------------
203
- class Ctx {
204
- constructor() {
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
- * @type {typeof import('./controller').prototype}
218
- */
219
- this.$controller;
75
+ const node_list = await getNodeList('.', ignore);
76
+ calcNodeList(node_list, this._APP);
220
77
 
221
- /**
222
- * @type {typeof import('./cookie').prototype}
223
- */
224
- this.$cookie;
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
- * @type {typeof import('./db').prototype}
228
- */
229
- this.$db;
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
- * @type {typeof import('./logger')}
233
- */
234
- this.$logger;
112
+ return types;
113
+ }
235
114
 
236
- /**
237
- * @type {typeof import('./middleware').prototype}
238
- */
239
- this.$middleware;
115
+ // 生成智能属性
116
+ function createProps(node_list) {
117
+ let props = '';
240
118
 
241
- /**
242
- * @type {typeof import('./model').prototype}
243
- */
244
- this.$model;
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
- * @type {typeof import('./pagination').prototype}
248
- */
249
- this.$pagination;
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
- * @type {typeof import('./response').prototype}
253
- */
254
- this.$response;
132
+ return props;
133
+ }
255
134
 
256
- /**
257
- * @type {typeof import('./upload').prototype}
258
- */
259
- this.$upload;
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
- * @type {typeof import('./url').prototype}
263
- */
264
- this.$url;
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
- * @type {typeof import('./view').prototype}
268
- */
269
- this.$view;
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
- * @type {Utils}
273
- */
274
- this.$utils;
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
- * @type {import('./config')}
278
- */
279
- this.$config;
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('./types').UploadData} UploadData
11
- * @typedef {import('./types').ValidateRule} ValidateRule
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
- ['mkdir', 'rmdir', 'readdir', 'readFile', 'copyFile', 'unlink', 'exists', 'stat'].forEach(function (item) {
7
- fsFun[item] = function (pathname, copypath) {
8
- return new Promise(function (resolve, reject) {
9
- let arg = [function (err, data) {
10
- if (item === 'exists') {
11
- return resolve(err);
12
- }
13
- if (err) {
14
- return reject(err);
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
- ['writeFile', 'appendFile'].forEach(function (item) {
27
- fsFun[item] = function (pathname, content, charset='utf8') {
28
- if (typeof content !== 'string') {
29
- content = JSON.stringify(content)
30
- };
31
- return new Promise(function (resolve, reject) {
32
- fs[item](pathname, content, charset, function(err, data){
33
- if (err) {
34
- return reject(err);
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
- fsFun.isFileSync = (path) => {return fs.existsSync(path) && fs.statSync(path).isFile();}
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
- ['isFile', 'isDir'].forEach(function (item) {
47
- fsFun[item] = function (pathname) {
48
- return new Promise(function (resolve, reject) {
49
- fsFun.exists(pathname).then((result) => {
50
- if (!result) {
51
- resolve(result);
52
- } else {
53
- fsFun.stat(pathname).then((result) => {
54
- resolve(item === 'isFile' ? result.isFile() : result.isDirectory());
55
- }).catch((error) => {
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
- fsFun.mkdirs = async function (dirname) {
68
- if(await fsFun.isDir(dirname)) {
50
+ // 生成多级目录
51
+ const mkdirs = async function (dirname) {
52
+ if(await isDir(dirname)) {
69
53
  return true;
70
54
  } else {
71
- if(await fsFun.mkdirs(pt.dirname(dirname))) {
72
- await fsFun.mkdir(dirname);
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 = fsFun;
62
+ module.exports = {
63
+ exists,
64
+ isFile,
65
+ isFileSync,
66
+ isDir,
67
+ isDirSync,
68
+ mkdirs
69
+ };
@@ -2,7 +2,7 @@
2
2
  * jj.js内置工具集<br/>
3
3
  * {date, error, fs, md5, str}
4
4
  * @module utils
5
- * @type {import('../types').Utils}
5
+ * @type {import('../../types').Utils}
6
6
  */
7
7
  module.exports = new Proxy({}, {
8
8
  get: (target, prop) => {