jj.js 0.7.3 → 0.7.6
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/controller.js +34 -41
- package/lib/ctx.js +50 -44
- package/lib/db.js +12 -1
- package/lib/loader.js +79 -79
- package/lib/model.js +2 -1
- package/lib/response.js +1 -0
- package/lib/upload.js +10 -11
- package/package.json +34 -34
package/lib/controller.js
CHANGED
|
@@ -1,42 +1,35 @@
|
|
|
1
|
-
const Middleware = require('./middleware');
|
|
2
|
-
|
|
3
|
-
class Controller extends Middleware
|
|
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
|
-
async $fetch(template) {
|
|
37
|
-
const content = await this.$view.fetch(template);
|
|
38
|
-
this.$show(content);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
1
|
+
const Middleware = require('./middleware');
|
|
2
|
+
|
|
3
|
+
class Controller extends Middleware
|
|
4
|
+
{
|
|
5
|
+
// 赋值模版数据
|
|
6
|
+
$assign(name, value) {
|
|
7
|
+
this.$view.assign(name, value);
|
|
8
|
+
return this;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 获取模版数据
|
|
12
|
+
$data(name) {
|
|
13
|
+
return this.$view.data(name);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 直接文件输出
|
|
17
|
+
async $load(template) {
|
|
18
|
+
const content = await this.$view.load(template);
|
|
19
|
+
this.$show(content);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 渲染内容输出
|
|
23
|
+
async $render(data) {
|
|
24
|
+
const content = await this.$view.render(data);
|
|
25
|
+
this.$show(content);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 渲染文件输出
|
|
29
|
+
async $fetch(template) {
|
|
30
|
+
const content = await this.$view.fetch(template);
|
|
31
|
+
this.$show(content);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
42
35
|
module.exports = Controller;
|
package/lib/ctx.js
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
|
-
const loader = require('./loader');
|
|
2
|
-
|
|
3
|
-
const Ctx = new Proxy(class {}, {
|
|
4
|
-
construct() {
|
|
5
|
-
return new Proxy({__proto__: arguments[2].prototype}, {
|
|
6
|
-
get: (target, prop) => {
|
|
7
|
-
if(prop in target || typeof prop == 'symbol' || prop == 'inspect') {
|
|
8
|
-
return target
|
|
9
|
-
}
|
|
10
|
-
if(prop == '$' || prop == '_') {
|
|
11
|
-
return target.ctx && target.ctx[prop]
|
|
12
|
-
|| prop == '$' && (target.$ || (target.$ = loader('../'))) && target.$
|
|
13
|
-
|| undefined;
|
|
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
|
-
|
|
1
|
+
const loader = require('./loader');
|
|
2
|
+
|
|
3
|
+
const Ctx = new Proxy(class {}, {
|
|
4
|
+
construct() {
|
|
5
|
+
return new Proxy({__proto__: arguments[2].prototype}, {
|
|
6
|
+
get: (target, prop, receiver) => {
|
|
7
|
+
if(prop in target || typeof prop == 'symbol' || prop == 'inspect') {
|
|
8
|
+
return Reflect.get(target, prop, receiver);
|
|
9
|
+
}
|
|
10
|
+
if(prop == '$' || prop == '_') {
|
|
11
|
+
return target.ctx && target.ctx[prop]
|
|
12
|
+
|| prop == '$' && (target.$ || (target.$ = loader('../'))) && target.$
|
|
13
|
+
|| undefined;
|
|
14
|
+
}
|
|
15
|
+
if(prop.slice(0, 1) != '$') {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const pp = prop.slice(1);
|
|
19
|
+
const ctx = target.ctx;
|
|
20
|
+
if(ctx && ctx._) {
|
|
21
|
+
const _ = ctx._;
|
|
22
|
+
const APP = ctx.APP;
|
|
23
|
+
const COMMON = _.config.app.common_app;
|
|
24
|
+
if(_[APP][prop] === undefined) {
|
|
25
|
+
if(_[APP][pp] && _[COMMON] && _[COMMON][pp]) {
|
|
26
|
+
_[APP][prop] = new Proxy({}, {
|
|
27
|
+
get: (...args) => {
|
|
28
|
+
return _[APP][pp][args[1]] || _[COMMON][pp][args[1]];
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
} else if(_[APP][pp]) {
|
|
32
|
+
_[APP][prop] = _[APP][pp];
|
|
33
|
+
} else if(_[COMMON] && _[COMMON][pp]) {
|
|
34
|
+
_[APP][prop] = _[COMMON][pp];
|
|
35
|
+
} else {
|
|
36
|
+
_[APP][prop] = null;
|
|
37
|
+
}
|
|
38
|
+
if(~['view', 'response'].indexOf(pp) && _[APP][prop] && _[APP][prop].__node && !_[APP][prop].__node.isClass && ctx.$ && ctx.$[pp]) {
|
|
39
|
+
_[APP][prop] = ctx.$[pp];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return _[APP][prop] || _[pp] || (ctx.$ && ctx.$[pp]) || undefined;
|
|
43
|
+
} else {
|
|
44
|
+
return (target.$ || (target.$ = loader('../'))) && target.$[pp];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
45
51
|
module.exports = Ctx;
|
package/lib/db.js
CHANGED
|
@@ -560,6 +560,17 @@ class Db extends Context
|
|
|
560
560
|
this._options.getSql = false;
|
|
561
561
|
return this.format(this._queryStr, params);
|
|
562
562
|
}
|
|
563
|
+
|
|
564
|
+
if(this._options.cache_time) {
|
|
565
|
+
const cache_time = this._options.cache_time;
|
|
566
|
+
const cache_key = md5(this.format(this._queryStr, params));
|
|
567
|
+
if(this.getCache(cache_key)) {
|
|
568
|
+
return this.getCache(cache_key);
|
|
569
|
+
}
|
|
570
|
+
const result = await this.query(this._queryStr, params);
|
|
571
|
+
this.setCache(cache_key, result, cache_time);
|
|
572
|
+
return result;
|
|
573
|
+
}
|
|
563
574
|
return await this.query(this._queryStr, params, reset);
|
|
564
575
|
}
|
|
565
576
|
|
|
@@ -741,7 +752,7 @@ class Db extends Context
|
|
|
741
752
|
Db.cache.set(key, data, cache_time);
|
|
742
753
|
}
|
|
743
754
|
|
|
744
|
-
deleteCache(key) {
|
|
755
|
+
deleteCache(key) {
|
|
745
756
|
Db.cache.delete(key);
|
|
746
757
|
}
|
|
747
758
|
}
|
package/lib/loader.js
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const pt = require('path');
|
|
3
|
-
const isClass = require('is-class');
|
|
4
|
-
const {isFileSync, isDirSync} = require('./utils/fs');
|
|
5
|
-
|
|
6
|
-
const nodeType = {};
|
|
7
|
-
|
|
8
|
-
function loader(dir='./', ...args) {
|
|
9
|
-
const node = {};
|
|
10
|
-
const info = new Map();
|
|
11
|
-
info.set(node, {
|
|
12
|
-
path: pt.isAbsolute(dir) ? pt.join(dir, './') : pt.join(pt.dirname(module.parent.filename), dir, './'),
|
|
13
|
-
nodeType: 'dir',
|
|
14
|
-
isClass: false
|
|
15
|
-
});
|
|
16
|
-
return creatLoader(node);
|
|
17
|
-
|
|
18
|
-
function creatLoader(node) {
|
|
19
|
-
return new Proxy(node, {
|
|
20
|
-
get: (node, prop) => {
|
|
21
|
-
if(prop in node || typeof prop == 'symbol' || prop == 'inspect') {
|
|
22
|
-
return node
|
|
23
|
-
}
|
|
24
|
-
const nodeInfo = info.get(node);
|
|
25
|
-
if(nodeInfo.isClass) {
|
|
26
|
-
if(!nodeInfo.instance) {
|
|
27
|
-
nodeInfo.instance = new node(...args);
|
|
28
|
-
}
|
|
29
|
-
return prop in nodeInfo.instance ? nodeInfo.instance[prop] : (prop == '__node' ? nodeInfo : nodeInfo.instance[prop]);
|
|
30
|
-
} else if(prop == '__node') {
|
|
31
|
-
return nodeInfo;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let _node = {};
|
|
35
|
-
const _nodePath = nodeInfo.path + prop + '/';
|
|
36
|
-
const _nodeFile = nodeInfo.path + prop + '.js';
|
|
37
|
-
if(!nodeType[_nodePath]) {
|
|
38
|
-
if(isFileSync(_nodeFile)) {
|
|
39
|
-
nodeType[_nodePath] = 'file';
|
|
40
|
-
} else if(isDirSync(_nodePath)) {
|
|
41
|
-
nodeType[_nodePath] = 'dir';
|
|
42
|
-
} else{
|
|
43
|
-
nodeType[_nodePath] = 'none';
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if(nodeType[_nodePath] == 'file') {
|
|
47
|
-
_node = require(_nodeFile);
|
|
48
|
-
} else if(nodeType[_nodePath] != 'dir') {
|
|
49
|
-
node[prop] = undefined;
|
|
50
|
-
return node[prop];
|
|
51
|
-
}
|
|
52
|
-
info.set(_node, {
|
|
53
|
-
path: _nodePath,
|
|
54
|
-
nodeType: nodeType[_nodePath],
|
|
55
|
-
isClass: isClass(_node)
|
|
56
|
-
});
|
|
57
|
-
node[prop] = creatLoader(_node);
|
|
58
|
-
return node[prop];
|
|
59
|
-
},
|
|
60
|
-
set: (_node, prop, value) => {
|
|
61
|
-
if(prop in node) {
|
|
62
|
-
node[prop] = value;
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
const nodeInfo = info.get(_node);
|
|
66
|
-
if(nodeInfo.isClass) {
|
|
67
|
-
if(!nodeInfo.instance) {
|
|
68
|
-
nodeInfo.instance = new node(...args);
|
|
69
|
-
}
|
|
70
|
-
nodeInfo.instance[prop] = value;
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
node[prop] = value;
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const pt = require('path');
|
|
3
|
+
const isClass = require('is-class');
|
|
4
|
+
const {isFileSync, isDirSync} = require('./utils/fs');
|
|
5
|
+
|
|
6
|
+
const nodeType = {};
|
|
7
|
+
|
|
8
|
+
function loader(dir='./', ...args) {
|
|
9
|
+
const node = {};
|
|
10
|
+
const info = new Map();
|
|
11
|
+
info.set(node, {
|
|
12
|
+
path: pt.isAbsolute(dir) ? pt.join(dir, './') : pt.join(pt.dirname(module.parent.filename), dir, './'),
|
|
13
|
+
nodeType: 'dir',
|
|
14
|
+
isClass: false
|
|
15
|
+
});
|
|
16
|
+
return creatLoader(node);
|
|
17
|
+
|
|
18
|
+
function creatLoader(node) {
|
|
19
|
+
return new Proxy(node, {
|
|
20
|
+
get: (node, prop, receiver) => {
|
|
21
|
+
if(prop in node || typeof prop == 'symbol' || prop == 'inspect') {
|
|
22
|
+
return Reflect.get(node, prop, receiver);
|
|
23
|
+
}
|
|
24
|
+
const nodeInfo = info.get(node);
|
|
25
|
+
if(nodeInfo.isClass) {
|
|
26
|
+
if(!nodeInfo.instance) {
|
|
27
|
+
nodeInfo.instance = new node(...args);
|
|
28
|
+
}
|
|
29
|
+
return prop in nodeInfo.instance ? nodeInfo.instance[prop] : (prop == '__node' ? nodeInfo : nodeInfo.instance[prop]);
|
|
30
|
+
} else if(prop == '__node') {
|
|
31
|
+
return nodeInfo;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let _node = {};
|
|
35
|
+
const _nodePath = nodeInfo.path + prop + '/';
|
|
36
|
+
const _nodeFile = nodeInfo.path + prop + '.js';
|
|
37
|
+
if(!nodeType[_nodePath]) {
|
|
38
|
+
if(isFileSync(_nodeFile)) {
|
|
39
|
+
nodeType[_nodePath] = 'file';
|
|
40
|
+
} else if(isDirSync(_nodePath)) {
|
|
41
|
+
nodeType[_nodePath] = 'dir';
|
|
42
|
+
} else{
|
|
43
|
+
nodeType[_nodePath] = 'none';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if(nodeType[_nodePath] == 'file') {
|
|
47
|
+
_node = require(_nodeFile);
|
|
48
|
+
} else if(nodeType[_nodePath] != 'dir') {
|
|
49
|
+
node[prop] = undefined;
|
|
50
|
+
return node[prop];
|
|
51
|
+
}
|
|
52
|
+
info.set(_node, {
|
|
53
|
+
path: _nodePath,
|
|
54
|
+
nodeType: nodeType[_nodePath],
|
|
55
|
+
isClass: isClass(_node)
|
|
56
|
+
});
|
|
57
|
+
node[prop] = creatLoader(_node);
|
|
58
|
+
return node[prop];
|
|
59
|
+
},
|
|
60
|
+
set: (_node, prop, value) => {
|
|
61
|
+
if(prop in node) {
|
|
62
|
+
node[prop] = value;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
const nodeInfo = info.get(_node);
|
|
66
|
+
if(nodeInfo.isClass) {
|
|
67
|
+
if(!nodeInfo.instance) {
|
|
68
|
+
nodeInfo.instance = new node(...args);
|
|
69
|
+
}
|
|
70
|
+
nodeInfo.instance[prop] = value;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
node[prop] = value;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
80
|
module.exports = loader;
|
package/lib/model.js
CHANGED
|
@@ -16,8 +16,9 @@ class Model extends Context
|
|
|
16
16
|
|
|
17
17
|
async save(data, condition = {}) {
|
|
18
18
|
if(data[this.pk] || Object.keys(condition).length) {
|
|
19
|
-
if(data[this.pk]
|
|
19
|
+
if(data[this.pk]) {
|
|
20
20
|
condition[this.pk] = data[this.pk];
|
|
21
|
+
delete data[this.pk];
|
|
21
22
|
}
|
|
22
23
|
return await this.db.allowField().update(data, condition);
|
|
23
24
|
}
|
package/lib/response.js
CHANGED
|
@@ -57,6 +57,7 @@ class Response extends Context
|
|
|
57
57
|
|
|
58
58
|
isAjax() {
|
|
59
59
|
return this.ctx.headers['x-requested-with'] && this.ctx.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest'
|
|
60
|
+
|| this.ctx.request.type.toLowerCase() == 'application/json'
|
|
60
61
|
|| this.ctx.query.is_ajax
|
|
61
62
|
|| this.ctx.request.body && this.ctx.request.body.is_ajax
|
|
62
63
|
? true : false;
|
package/lib/upload.js
CHANGED
|
@@ -32,13 +32,13 @@ class Upload extends Context
|
|
|
32
32
|
savename = utils.date.format('YYYY/mmdd/') + utils.md5(new Date().getTime() + Math.random().toString(36).substr(2));
|
|
33
33
|
}
|
|
34
34
|
if(!pt.extname(savename)) {
|
|
35
|
-
savename += pt.extname(this._file.
|
|
35
|
+
savename += pt.extname(this._file.originalFilename);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
39
|
const filePath = pt.join(this.$config.app.base_dir, dir, savename);
|
|
40
40
|
await utils.fs.mkdirs(pt.dirname(filePath));
|
|
41
|
-
const reader = fs.createReadStream(this._file.
|
|
41
|
+
const reader = fs.createReadStream(this._file.filepath);
|
|
42
42
|
const writer = fs.createWriteStream(filePath);
|
|
43
43
|
reader.pipe(writer);
|
|
44
44
|
await new Promise((resolve, reject) => {
|
|
@@ -54,9 +54,9 @@ class Upload extends Context
|
|
|
54
54
|
extname: pt.extname(savename).slice(1),
|
|
55
55
|
savename,
|
|
56
56
|
filepath: filePath,
|
|
57
|
-
name: this._file.
|
|
57
|
+
name: this._file.originalFilename,
|
|
58
58
|
size: this._file.size,
|
|
59
|
-
|
|
59
|
+
mimetype: this._file.mimetype,
|
|
60
60
|
hash: this._file.hash
|
|
61
61
|
};
|
|
62
62
|
} catch(e) {
|
|
@@ -108,7 +108,7 @@ class Upload extends Context
|
|
|
108
108
|
if(typeof ext == 'string') {
|
|
109
109
|
ext = ext.split(',');
|
|
110
110
|
}
|
|
111
|
-
if(!~ext.indexOf(pt.extname(this._file.
|
|
111
|
+
if(!~ext.indexOf(pt.extname(this._file.originalFilename).slice(1).toLowerCase())) {
|
|
112
112
|
return false;
|
|
113
113
|
}
|
|
114
114
|
return true;
|
|
@@ -118,18 +118,17 @@ class Upload extends Context
|
|
|
118
118
|
if(typeof type == 'string') {
|
|
119
119
|
type = type.split(',');
|
|
120
120
|
}
|
|
121
|
-
if(!~type.indexOf(this._file.
|
|
121
|
+
if(!~type.indexOf(this._file.mimetype.toLowerCase())) {
|
|
122
122
|
return false;
|
|
123
123
|
}
|
|
124
124
|
return true;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
// 此判断方法无效
|
|
128
127
|
checkImg() {
|
|
129
|
-
const fileExt = pt.extname(this._file.
|
|
130
|
-
const fileType = this._file.
|
|
131
|
-
const exts = ['gif', 'png', 'jpeg', 'webp', 'ico', 'bmp', 'svg', 'jpg'];
|
|
132
|
-
const mimes = ['gif', 'png', 'jpeg', 'webp', 'x-icon', 'bmp', 'svg+xml'];
|
|
128
|
+
const fileExt = pt.extname(this._file.originalFilename).slice(1).toLowerCase();
|
|
129
|
+
const fileType = this._file.mimetype.toLowerCase().split('/');
|
|
130
|
+
const exts = ['gif', 'png', 'jpeg', 'webp', 'ico', 'bmp', 'svg', 'jpg', 'tiff'];
|
|
131
|
+
const mimes = ['gif', 'png', 'jpeg', 'webp', 'x-icon', 'bmp', 'svg+xml', 'tiff'];
|
|
133
132
|
if(~exts.indexOf(fileExt) && (fileType[0] != 'image' || !~mimes.indexOf(fileType[1]))) {
|
|
134
133
|
return false;
|
|
135
134
|
}
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "jj.js",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "A simple and lightweight MVC framework built on nodejs+koa2",
|
|
5
|
-
"main": "jj.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "node test/test.js"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/yafoo/jj.js.git"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"mvc",
|
|
15
|
-
"koa",
|
|
16
|
-
"node"
|
|
17
|
-
],
|
|
18
|
-
"author": "yafoo",
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"bugs": {
|
|
21
|
-
"url": "https://github.com/yafoo/jj.js/issues"
|
|
22
|
-
},
|
|
23
|
-
"homepage": "https://github.com/yafoo/jj.js#readme",
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"@koa/router": "^10.1.
|
|
26
|
-
"art-template": "^4.13.2",
|
|
27
|
-
"escape-html": "^1.0.3",
|
|
28
|
-
"is-class": "0.0.9",
|
|
29
|
-
"koa": "^2.13.
|
|
30
|
-
"koa-body": "^
|
|
31
|
-
"koa-static": "^5.0.0",
|
|
32
|
-
"mysql": "^2.18.1"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "jj.js",
|
|
3
|
+
"version": "0.7.6",
|
|
4
|
+
"description": "A simple and lightweight MVC framework built on nodejs+koa2",
|
|
5
|
+
"main": "jj.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test/test.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/yafoo/jj.js.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mvc",
|
|
15
|
+
"koa",
|
|
16
|
+
"node"
|
|
17
|
+
],
|
|
18
|
+
"author": "yafoo",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/yafoo/jj.js/issues"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/yafoo/jj.js#readme",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@koa/router": "^10.1.1",
|
|
26
|
+
"art-template": "^4.13.2",
|
|
27
|
+
"escape-html": "^1.0.3",
|
|
28
|
+
"is-class": "0.0.9",
|
|
29
|
+
"koa": "^2.13.4",
|
|
30
|
+
"koa-body": "^5.0.0",
|
|
31
|
+
"koa-static": "^5.0.0",
|
|
32
|
+
"mysql": "^2.18.1"
|
|
33
|
+
}
|
|
34
|
+
}
|