jj.js 0.18.0 → 0.20.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/loader.js CHANGED
@@ -1,82 +1,117 @@
1
1
  const pt = require('path');
2
+ /** @type {function} */
3
+ // @ts-ignore
2
4
  const isClass = require('is-class');
3
5
  const {isFileSync, isDirSync} = require('./utils/fs');
4
6
 
5
- const nodeType = {};
7
+ /**
8
+ * @typedef {import('../types').NodeType} NodeType
9
+ * @typedef {import('../types').NodeInfo} NodeInfo
10
+ * @typedef {import('../types').ClassNode} ClassNode
11
+ * @typedef {import('../types').ObjectNode} ObjectNode
12
+ * @typedef {import('../types').Node} Node
13
+ */
6
14
 
7
- function loader(dir='./', ...args) {
8
- // @ts-ignore
9
- dir = pt.isAbsolute(dir) ? dir : pt.join(pt.dirname(module.parent.filename), dir);
15
+ /**
16
+ * @type {Map<string, NodeType>}
17
+ */
18
+ const typeStore = new Map();
19
+
20
+ /**
21
+ * nodejs模块(‌CommonJS)自动加载器
22
+ * @param {string} path 根目录,需为绝对路径,最后不带斜杠
23
+ * @param {...any} args class自动实例化时的构造参数
24
+ * @return {Node}
25
+ */
26
+ function loader(path, ...args) {
27
+ const dir = pt.normalize(path).replace(/[\/\\]+$/, '');
10
28
  const dirPath = pt.join(dir, './');
11
- const dirType = isFileSync(dir + '.js') ? 'file' : 'dir';
12
- const node = dirType == 'file' ? require(dir) : {};
13
- const info = new Map();
14
- info.set(node, {
29
+ /** @type {NodeType} */
30
+ let dirType = isFileSync(dir + '.js') ? 'file' : isFileSync(dir + '.json') ? 'json' : 'dir';
31
+ const node = dirType == 'dir' ? {} : require(dir);
32
+
33
+ if(dirType == 'file' && isClass(node)) {
34
+ dirType = 'class';
35
+ }
36
+ /** @type {Map<object, NodeInfo>} */
37
+ const infoStore = new Map();
38
+ infoStore.set(node, {
15
39
  path: dirPath,
16
- nodeType: dirType,
17
- // @ts-ignore
18
- isClass: isClass(node)
40
+ type: dirType
19
41
  });
20
42
  return creatLoader(node);
21
43
 
44
+ /**
45
+ * 创建代理对象
46
+ * @param {ClassNode & ObjectNode} node - 类型仅为防报错
47
+ * @return {Node} - 节点
48
+ */
22
49
  function creatLoader(node) {
50
+ // @ts-ignore
23
51
  return new Proxy(node, {
24
52
  get: (node, prop, receiver) => {
25
53
  if(prop in node || typeof prop == 'symbol' || prop == 'inspect') {
26
54
  return Reflect.get(node, prop, receiver);
27
55
  }
28
- const nodeInfo = info.get(node);
29
- if(nodeInfo.isClass) {
56
+
57
+ /** @type {NodeInfo} */
58
+ // @ts-ignore
59
+ const nodeInfo = infoStore.get(node);
60
+ if(nodeInfo.type == 'class') {
30
61
  if(!nodeInfo.instance) {
31
62
  nodeInfo.instance = new node(...args);
32
63
  }
33
- return prop in nodeInfo.instance ? nodeInfo.instance[prop] : (prop == '__node' ? nodeInfo : nodeInfo.instance[prop]);
34
- } else if(prop == '__node') {
64
+ // @ts-ignore
65
+ return prop in nodeInfo.instance ? nodeInfo.instance[prop] : prop == '__NODE__' ? nodeInfo : prop == '__ISCLASS__' ? true : nodeInfo.instance[prop];
66
+ } else if(prop == '__NODE__') {
35
67
  return nodeInfo;
68
+ } else if(prop == '__ISCLASS__') {
69
+ return false;
36
70
  }
37
71
 
38
- let _node = {};
39
- const _nodePath = nodeInfo.path + prop + '/';
72
+ const _nodePath = nodeInfo.path + prop + pt.sep;
40
73
  const _nodeFile = nodeInfo.path + prop + '.js';
41
- if(!nodeType[_nodePath]) {
42
- if(isFileSync(_nodeFile)) {
43
- nodeType[_nodePath] = 'file';
44
- } else if(isDirSync(_nodePath)) {
45
- nodeType[_nodePath] = 'dir';
46
- } else {
47
- // nodeType[_nodePath] = 'none';
74
+ const _nodeJson = nodeInfo.path + prop + '.json';
75
+ let _nodeType = typeStore.get(_nodePath);
76
+ if(_nodeType === undefined) {
77
+ _nodeType = isFileSync(_nodeFile) ? 'file' : isFileSync(_nodeJson) ? 'json' : isDirSync(_nodePath) ? 'dir' : '';
78
+ if(_nodeType == 'file' && isClass(require(_nodeFile))) {
79
+ _nodeType = 'class';
48
80
  }
81
+ typeStore.set(_nodePath, _nodeType);
49
82
  }
50
- if(nodeType[_nodePath] == 'file') {
83
+ let _node = {};
84
+ if(_nodeType == '') {
85
+ return undefined; // 直接返回
86
+ } else if(_nodeType == 'file' || _nodeType == 'class') {
51
87
  _node = require(_nodeFile);
52
- } else if(nodeType[_nodePath] != 'dir') {
53
- node[prop] = undefined;
54
- return node[prop];
88
+ } else if(_nodeType == 'json') {
89
+ _node = require(_nodeJson);
55
90
  }
56
- info.set(_node, {
91
+ infoStore.set(_node, {
57
92
  path: _nodePath,
58
- nodeType: nodeType[_nodePath],
59
- // @ts-ignore
60
- isClass: isClass(_node)
93
+ type: _nodeType
61
94
  });
62
- node[prop] = creatLoader(_node);
63
- return node[prop];
95
+ // @ts-ignore
96
+ return node[prop] = creatLoader(_node); // 代理,并缓存
64
97
  },
65
- set: (_node, prop, value) => {
66
- if(prop in node) {
67
- node[prop] = value;
68
- return true;
98
+ set: (node, prop, value, receiver) => {
99
+ if(prop in node || typeof prop == 'symbol' || prop == 'inspect') {
100
+ return Reflect.set(node, prop, value, receiver);
69
101
  }
70
- const nodeInfo = info.get(_node);
71
- if(nodeInfo.isClass) {
102
+
103
+ /** @type {NodeInfo} */
104
+ // @ts-ignore
105
+ const nodeInfo = infoStore.get(node);
106
+ if(nodeInfo.type == 'class') {
72
107
  if(!nodeInfo.instance) {
73
108
  nodeInfo.instance = new node(...args);
74
109
  }
75
- nodeInfo.instance[prop] = value;
76
- return true;
110
+ // @ts-ignore
111
+ return Reflect.set(nodeInfo.instance, prop, value, nodeInfo.instance);
77
112
  }
78
- node[prop] = value;
79
- return true;
113
+
114
+ return Reflect.set(node, prop, value, receiver);
80
115
  }
81
116
  });
82
117
  }
package/lib/logger.js CHANGED
@@ -1,127 +1,125 @@
1
- const {app: cfg_app, log: cfg_log} = require('./config');
2
-
3
- /**
4
- * @typedef {import('../types').LogHandle} LogHandle
5
- */
6
-
7
- class Logger
8
- {
9
- /**
10
- * Creat a new `Logger` class
11
- * @public
12
- * @static
13
- * @param {LogHandle} [handle]
14
- */
15
- constructor(handle) {
16
- if(new.target) {
17
- // @ts-ignore
18
- class ClildLogger extends this.constructor {}
19
- // @ts-ignore
20
- ClildLogger.setHandle(handle);
21
- return ClildLogger;
22
- }
23
- }
24
-
25
- /**
26
- * 输出system日志
27
- * @public
28
- * @static
29
- * @param {...any} args
30
- */
31
- static system(...args) {
32
- this.log('system', ...args);
33
- }
34
-
35
- /**
36
- * 输出error日志
37
- * @public
38
- * @static
39
- * @param {...any} args
40
- */
41
- static error(...args) {
42
- this.log('error', ...args);
43
- }
44
-
45
- /**
46
- * 输出warning日志
47
- * @public
48
- * @static
49
- * @param {...any} args
50
- */
51
- static warning(...args) {
52
- this.log('warning', ...args);
53
- }
54
-
55
- /**
56
- * 输出info日志
57
- * @public
58
- * @static
59
- * @param {...any} args
60
- */
61
- static info(...args) {
62
- this.log('info', ...args);
63
- }
64
-
65
- /**
66
- * 输出debug日志
67
- * @public
68
- * @static
69
- * @param {...any} args
70
- */
71
- static debug(...args) {
72
- this.log('debug', ...args);
73
- }
74
-
75
- /**
76
- * 输出sql日志
77
- * @public
78
- * @static
79
- * @param {...any} args
80
- */
81
- static sql(...args) {
82
- this.log('sql', ...args);
83
- }
84
-
85
- /**
86
- * 输出http日志
87
- * @public
88
- * @static
89
- * @param {...any} args
90
- */
91
- static http(...args) {
92
- this.log('http', ...args);
93
- }
94
-
95
- /**
96
- * 输出error日志
97
- * @public
98
- * @static
99
- * @param {string} level - 日志级别、标识
100
- * @param {...any} args - 日志内容
101
- */
102
- static log(level='info', ...args) {
103
- (cfg_app.app_debug || ~cfg_log.log_level.indexOf(level)) && this.handle(level, ...args);
104
- }
105
-
106
- /**
107
- * 设置日志handle
108
- * @public
109
- * @static
110
- * @param {LogHandle} handle
111
- * @returns {Logger}
112
- */
113
- static setHandle(handle) {
114
- /**
115
- * @type {LogHandle}
116
- */
117
- this.handle = typeof handle == 'function' ? handle : cfg_log.log_handle;
118
- return this;
119
- }
120
- }
121
-
122
- /**
123
- * 设置日志handle
124
- */
125
- Logger.setHandle(cfg_log.log_handle);
126
-
1
+ const {app: cfg_app, log: cfg_log} = require('./config');
2
+
3
+ /**
4
+ * @typedef {import('../types').LogLevel} LogLevel
5
+ * @typedef {import('../types').LogHandle} LogHandle
6
+ */
7
+
8
+ class Logger
9
+ {
10
+ static handle = cfg_log.log_handle;
11
+
12
+ /**
13
+ * Creat a new `Logger` class
14
+ * @public
15
+ * @static
16
+ * @param {LogHandle} [handle]
17
+ */
18
+ constructor(handle) {
19
+ if(new.target) {
20
+ // @ts-ignore
21
+ class ClildLogger extends this.constructor {
22
+ static handle = handle || cfg_log.log_handle;
23
+ }
24
+ return ClildLogger;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * 输出system日志
30
+ * @public
31
+ * @static
32
+ * @param {...any} args
33
+ */
34
+ static system(...args) {
35
+ this.log('system', ...args);
36
+ }
37
+
38
+ /**
39
+ * 输出error日志
40
+ * @public
41
+ * @static
42
+ * @param {...any} args
43
+ */
44
+ static error(...args) {
45
+ this.log('error', ...args);
46
+ }
47
+
48
+ /**
49
+ * 输出warning日志
50
+ * @public
51
+ * @static
52
+ * @param {...any} args
53
+ */
54
+ static warning(...args) {
55
+ this.log('warning', ...args);
56
+ }
57
+
58
+ /**
59
+ * 输出info日志
60
+ * @public
61
+ * @static
62
+ * @param {...any} args
63
+ */
64
+ static info(...args) {
65
+ this.log('info', ...args);
66
+ }
67
+
68
+ /**
69
+ * 输出debug日志
70
+ * @public
71
+ * @static
72
+ * @param {...any} args
73
+ */
74
+ static debug(...args) {
75
+ this.log('debug', ...args);
76
+ }
77
+
78
+ /**
79
+ * 输出sql日志
80
+ * @public
81
+ * @static
82
+ * @param {...any} args
83
+ */
84
+ static sql(...args) {
85
+ this.log('sql', ...args);
86
+ }
87
+
88
+ /**
89
+ * 输出http日志
90
+ * @public
91
+ * @static
92
+ * @param {...any} args
93
+ */
94
+ static http(...args) {
95
+ this.log('http', ...args);
96
+ }
97
+
98
+ /**
99
+ * 输出error日志
100
+ * @public
101
+ * @static
102
+ * @param {LogLevel} level - 日志级别、标识
103
+ * @param {...any} args - 日志内容
104
+ */
105
+ static log(level='info', ...args) {
106
+ (cfg_app.app_debug || ~cfg_log.log_level.indexOf(level)) && this.handle(level, ...args);
107
+ }
108
+
109
+ /**
110
+ * 设置日志handle
111
+ * @public
112
+ * @static
113
+ * @param {LogHandle} handle
114
+ * @returns {Logger}
115
+ */
116
+ static setHandle(handle) {
117
+ if(typeof handle != 'function') {
118
+ throw new Error('handle must be a function');
119
+ }
120
+ this.handle = handle;
121
+ return this;
122
+ }
123
+ }
124
+
127
125
  module.exports = Logger;
package/lib/middleware.js CHANGED
@@ -1,5 +1,11 @@
1
1
  const Context = require('./context');
2
2
 
3
+ /**
4
+ * @typedef {import('../types').KoaCtx} KoaCtx
5
+ * @typedef {import('../types').AsyncNext} AsyncNext
6
+ * @typedef {import('../types').ResponseInstance} ResponseInstance
7
+ */
8
+
3
9
  /**
4
10
  * @extends Context
5
11
  */
@@ -8,8 +14,8 @@ class Middleware extends Context
8
14
  /**
9
15
  * Initialize a new `Middleware`
10
16
  * @public
11
- * @param {import('../types').KoaCtx} ctx
12
- * @param {import('../types').AsyncNext} [next]
17
+ * @param {KoaCtx} ctx
18
+ * @param {AsyncNext} [next]
13
19
  */
14
20
  constructor(ctx, next) {
15
21
  super(ctx);
@@ -22,7 +28,7 @@ class Middleware extends Context
22
28
  * @param {*} data
23
29
  */
24
30
  $show(data) {
25
- this.$response.show(data);
31
+ this._$response.show(data);
26
32
  }
27
33
 
28
34
  /**
@@ -32,7 +38,7 @@ class Middleware extends Context
32
38
  * @param {number} [status]
33
39
  */
34
40
  $redirect(url, status) {
35
- this.$response.redirect(url, status);
41
+ this._$response.redirect(url, status);
36
42
  }
37
43
 
38
44
  /**
@@ -42,7 +48,7 @@ class Middleware extends Context
42
48
  * @param {(string|object)} [url]
43
49
  */
44
50
  $success(msg, url) {
45
- this.$response.success(msg, url);
51
+ this._$response.success(msg, url);
46
52
  }
47
53
 
48
54
  /**
@@ -52,7 +58,34 @@ class Middleware extends Context
52
58
  * @param {(string|object)} [url]
53
59
  */
54
60
  $error(msg, url) {
55
- this.$response.error(msg, url);
61
+ this._$response.error(msg, url);
62
+ }
63
+
64
+ /**
65
+ * @type {ResponseInstance} Response实例
66
+ * @private
67
+ */
68
+ // @ts-ignore
69
+ __response = null;
70
+
71
+ /**
72
+ * @type {ResponseInstance} Response实例
73
+ */
74
+ get _$response() {
75
+ if(this.__response === null) {
76
+ if(this.$response && this.$response.__ISCLASS__) {
77
+ this.__response = this.$response;
78
+ } else if(this.$ && this.$.response) {
79
+ this.__response = this.$.response;
80
+ } else {
81
+ this.__response = new (require('./response'))(this.ctx);
82
+ }
83
+ }
84
+ return this.__response;
85
+ }
86
+
87
+ set _$response(response) {
88
+ this.__response = response;
56
89
  }
57
90
  }
58
91
 
package/lib/model.js CHANGED
@@ -2,9 +2,14 @@ const Context = require('./context');
2
2
  const {toLine} = require('./utils/str');
3
3
 
4
4
  /**
5
+ * @typedef {import('../types').DbConfigItem} DbConfigItem
6
+ * @typedef {import('../types').DbInstance} DbInstance
5
7
  * @typedef {import('../types').OkPacket} OkPacket
6
8
  * @typedef {import('../types').RowData} RowData
7
9
  * @typedef {import('../types').ListData} ListData
10
+ * @typedef {import('../types').Where} Where
11
+ * @typedef {import('../types').DbData} DbData
12
+ * @typedef {import('../types').KoaCtx} KoaCtx
8
13
  */
9
14
 
10
15
  /**
@@ -15,10 +20,14 @@ class Model extends Context
15
20
  /**
16
21
  * Initialize a new `Model`
17
22
  * @public
18
- * @param {import('../types').KoaCtx} ctx
23
+ * @param {KoaCtx} ctx
19
24
  */
20
25
  constructor(ctx) {
21
26
  super(ctx);
27
+ /**
28
+ * @type {DbConfigItem}
29
+ */
30
+ // @ts-ignore
22
31
  this.connection = null;
23
32
  this.table = toLine(this.constructor.name);
24
33
  this.pk = 'id';
@@ -28,7 +37,7 @@ class Model extends Context
28
37
  /**
29
38
  * 插入一条数据
30
39
  * @public
31
- * @param {object} data - 待插入数据
40
+ * @param {DbData} data - 待插入数据
32
41
  * @returns {Promise<OkPacket>}
33
42
  */
34
43
  async add(data) {
@@ -38,12 +47,12 @@ class Model extends Context
38
47
  /**
39
48
  * 更新或插入一条数据
40
49
  * @public
41
- * @param {object} data - 更新或插入数据
42
- * @param {object} [condition] - 更新条件,不为空或data包含主键则更新数据,否则插入数据
50
+ * @param {DbData} data - 更新或插入数据
51
+ * @param {Where} [condition] - 更新条件,不为空或data包含主键则更新数据,否则插入数据
43
52
  * @returns {Promise<OkPacket>}
44
53
  */
45
54
  async save(data, condition = {}) {
46
- if(data[this.pk] || Object.keys(condition).length) {
55
+ if(data[this.pk] || (condition && Object.keys(condition).length)) {
47
56
  if(data[this.pk]) {
48
57
  condition[this.pk] = data[this.pk];
49
58
  delete data[this.pk];
@@ -58,17 +67,20 @@ class Model extends Context
58
67
  /**
59
68
  * 删除数据
60
69
  * @public
61
- * @param {object} condition - 删除条件
70
+ * @param {Where} condition - 删除条件
62
71
  * @returns {Promise<OkPacket>}
63
72
  */
64
73
  async del(condition) {
74
+ if(!condition || Object.keys(condition).length === 0) {
75
+ throw new Error('condition is empty');
76
+ }
65
77
  return await this.db.delete(condition);
66
78
  }
67
79
 
68
80
  /**
69
81
  * 查询一条数据
70
82
  * @public
71
- * @param {object} condition - 查询条件
83
+ * @param {Where} [condition] - 查询条件
72
84
  * @returns {Promise<(RowData|null)>}
73
85
  */
74
86
  async get(condition) {
@@ -78,7 +90,7 @@ class Model extends Context
78
90
  /**
79
91
  * 查询多条数据
80
92
  * @public
81
- * @param {object} condition - 查询条件
93
+ * @param {Where} [condition] - 查询条件
82
94
  * @returns {Promise<(ListData)>}
83
95
  */
84
96
  async all(condition) {
@@ -87,7 +99,9 @@ class Model extends Context
87
99
 
88
100
  /**
89
101
  * 数据库实例
90
- * @type {import('../types').DbInstance}
102
+ * @type {DbInstance}
103
+ * @public
104
+ * @returns {DbInstance}
91
105
  */
92
106
  get db() {
93
107
  if(!this._db){