jj.js 0.8.8 → 0.9.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/utils/date.js CHANGED
@@ -1,40 +1,51 @@
1
- function format(fmt, date) {
2
- (typeof date === 'string' || typeof date === 'number') && (date = new Date(parseInt(date + '000')));
3
- date = date || new Date();
4
- let ret;
5
- let opt = {
6
- "Y+": date.getFullYear().toString(), // 年
7
- "y+": date.getFullYear().toString().slice(2),//
8
- "m+": (date.getMonth() + 1).toString(), // 月
9
- "d+": date.getDate().toString(), // 日
10
- "H+": date.getHours().toString(), // 时
11
- "h+": (date.getHours() > 12 ? date.getHours() - 12 : date.getHours()).toString(),// 时
12
- "i+": date.getMinutes().toString(), //
13
- "s+": date.getSeconds().toString() //
14
- };
15
- for (let k in opt) {
16
- ret = new RegExp("(" + k + ")").exec(fmt);
17
- if (ret) {
18
- fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
19
- };
20
- };
21
- return fmt;
22
- }
23
-
24
- function before(time) {
25
- time -= 0;
26
- let difTime = new Date().getTime() / 1000 - time;
27
- let { h, m } = { h: parseInt(difTime / 3600), m: parseInt(difTime / 60) };
28
- let msg = "";
29
- if (h < 1) {
30
- msg = `${m}分钟前`;
31
- } else if (h >= 1 && h <= 24) {
32
- msg = `${h}小时前`;
33
- } else if (h > 24) {
34
- h = parseInt(h / 24)
35
- msg = `${h}天前`;
36
- }
37
- return msg;
38
- }
39
-
1
+ /**
2
+ * @function
3
+ * @param {string} fmt - 格式化模板
4
+ * @param {(number|Date)} [date] - 时间戳或Date实例
5
+ * @returns {string} - 格式化后时间
6
+ */
7
+ function format(fmt, date) {
8
+ (typeof date === 'string' || typeof date === 'number') && (date = new Date(parseInt(date + '000')));
9
+ date = date || new Date();
10
+ let ret;
11
+ let opt = {
12
+ "Y+": date.getFullYear().toString(), //
13
+ "y+": date.getFullYear().toString().slice(2),//
14
+ "m+": (date.getMonth() + 1).toString(), // 月
15
+ "d+": date.getDate().toString(), //
16
+ "H+": date.getHours().toString(), // 时
17
+ "h+": (date.getHours() > 12 ? date.getHours() - 12 : date.getHours()).toString(),// 时
18
+ "i+": date.getMinutes().toString(), //
19
+ "s+": date.getSeconds().toString() // 秒
20
+ };
21
+ for (let k in opt) {
22
+ ret = new RegExp("(" + k + ")").exec(fmt);
23
+ if (ret) {
24
+ fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
25
+ };
26
+ };
27
+ return fmt;
28
+ }
29
+
30
+ /**
31
+ * @function - 获取多长时间前
32
+ * @param {number} time - 时间戳
33
+ * @returns {string} - 例如5分钟前
34
+ */
35
+ function before(time) {
36
+ time -= 0;
37
+ let difTime = Date.now() / 1000 - time;
38
+ let { h, m } = { h: difTime / 3600, m: difTime / 60 };
39
+ let msg = "";
40
+ if (h < 1) {
41
+ msg = `${m}分钟前`;
42
+ } else if (h >= 1 && h <= 24) {
43
+ msg = `${h}小时前`;
44
+ } else if (h > 24) {
45
+ h = h / 24
46
+ msg = `${h}天前`;
47
+ }
48
+ return msg;
49
+ }
50
+
40
51
  module.exports = {format, before};
@@ -1,5 +1,10 @@
1
1
  const fs = require('./fs.js');
2
2
 
3
+ /**
4
+ * @function - 解析Error数据
5
+ * @param {Error} err - 错误对象
6
+ * @returns {object} - 解析后数据
7
+ */
3
8
  function parseError(err) {
4
9
  let msg = err.message;
5
10
  let stack = err.stack.replace(/(\r\n)/g, "\n").split("\n");
@@ -18,7 +23,7 @@ function parseError(err) {
18
23
  let begin = row - 10;
19
24
  let end = row + 10;
20
25
  let nth = 0;
21
- let code = '';
26
+ let code = [];
22
27
  if(begin < 0) {
23
28
  end -= begin;
24
29
  begin = 0;
@@ -26,8 +31,7 @@ function parseError(err) {
26
31
  if(file_path == 'anonymous' || !file_path || !fs.isFileSync(file_path)) {
27
32
  code = stack;
28
33
  } else {
29
- code = require('fs').readFileSync(file_path);
30
- code = code.toString().replace(/(\r\n)/g, "\n").split("\n");
34
+ code = require('fs').readFileSync(file_path).toString().replace(/(\r\n)/g, "\n").split("\n");
31
35
  if(begin < 0) {
32
36
  end -= begin;
33
37
  begin = 0;
@@ -43,7 +47,7 @@ function parseError(err) {
43
47
  nth = row - begin;
44
48
  }
45
49
 
46
- return data = {
50
+ return {
47
51
  msg,
48
52
  code,
49
53
  stack,
package/lib/utils/fs.js CHANGED
@@ -1,78 +1,78 @@
1
- const fs = require('fs');
2
- const pt = require('path');
3
- const fsFun = {};
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
- });
22
- }
23
- });
24
-
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
- });
39
- }
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();}
45
-
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
- });
63
- }
64
- });
65
-
66
- //(多级目录生成)
67
- fsFun.mkdirs = async function (dirname) {
68
- if(await fsFun.isDir(dirname)) {
69
- return true;
70
- } else {
71
- if(await fsFun.mkdirs(pt.dirname(dirname))) {
72
- await fsFun.mkdir(dirname);
73
- return true;
74
- }
75
- }
76
- }
77
-
1
+ const fs = require('fs');
2
+ const pt = require('path');
3
+ const fsFun = {};
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
+ });
22
+ }
23
+ });
24
+
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
+ });
39
+ }
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();}
45
+
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
+ });
63
+ }
64
+ });
65
+
66
+ //(多级目录生成)
67
+ fsFun.mkdirs = async function (dirname) {
68
+ if(await fsFun.isDir(dirname)) {
69
+ return true;
70
+ } else {
71
+ if(await fsFun.mkdirs(pt.dirname(dirname))) {
72
+ await fsFun.mkdir(dirname);
73
+ return true;
74
+ }
75
+ }
76
+ }
77
+
78
78
  module.exports = fsFun;
package/lib/utils/md5.js CHANGED
@@ -1,7 +1,9 @@
1
- let crypto;
2
- module.exports = (str) => {
3
- if(!crypto) {
4
- crypto = require('crypto');
5
- }
6
- return crypto.createHash('md5').update(str).digest('hex');
7
- }
1
+ /**
2
+ * @function - md5
3
+ * @param {string} str
4
+ * @returns {string}
5
+ */
6
+ function md5(str) {
7
+ return require('crypto').createHash('md5').update(str).digest('hex');
8
+ }
9
+ module.exports = md5;
package/lib/utils/str.js CHANGED
@@ -1,11 +1,21 @@
1
- function toHump(name) {
2
- return name.replace(/\_(\w)/g, function(all, letter){
3
- return letter.toUpperCase();
4
- });
5
- }
6
-
7
- function toLine(name) {
8
- return name.replace(/(?!^)([A-Z])/g, "_$1").toLowerCase();
9
- }
10
-
1
+ /**
2
+ * @function - 转为驼峰
3
+ * @param {string} name
4
+ * @returns {string}
5
+ */
6
+ function toHump(name) {
7
+ return name.replace(/\_(\w)/g, function(all, letter){
8
+ return letter.toUpperCase();
9
+ });
10
+ }
11
+
12
+ /**
13
+ * @function - 转为下划线
14
+ * @param {string} name
15
+ * @returns {string}
16
+ */
17
+ function toLine(name) {
18
+ return name.replace(/(?!^)([A-Z])/g, "_$1").toLowerCase();
19
+ }
20
+
11
21
  module.exports = {toHump, toLine};
@@ -1,11 +1,17 @@
1
- module.exports = new Proxy({}, {
2
- get: (target, prop) => {
3
- if(prop in target || typeof prop == 'symbol' || prop == 'inspect') {
4
- return target[prop];
5
- }
6
- if(prop == 'type') {
7
- return para => Object.prototype.toString.call(para).slice(8,-1);
8
- }
9
- return require('./' + prop);
10
- }
1
+ /**
2
+ * jj.js内置工具集<br/>
3
+ * {date, error, fs, md5, str}
4
+ * @module utils
5
+ * @type {import('../types').Utils}
6
+ */
7
+ module.exports = new Proxy({}, {
8
+ get: (target, prop) => {
9
+ if(prop in target || typeof prop == 'symbol' || prop == 'inspect') {
10
+ return target[prop];
11
+ }
12
+ if(prop == 'type') {
13
+ return para => Object.prototype.toString.call(para).slice(8, -1);
14
+ }
15
+ return require('./' + prop);
16
+ }
11
17
  });
package/lib/view.js CHANGED
@@ -4,32 +4,61 @@ const {app: cfg_app, view: cfg_view} = require('./config');
4
4
  const {toLine} = require('./utils/str');
5
5
  const Context = require('./context');
6
6
 
7
+ /**
8
+ * @extends Context
9
+ */
7
10
  class View extends Context
8
11
  {
12
+ /**
13
+ * Initialize a new `View`
14
+ * @public
15
+ * @param {import('./types').Context} ctx
16
+ */
9
17
  constructor(ctx) {
10
18
  super(ctx);
11
19
  this._data = {};
12
20
  this.setEngine(cfg_view.view_engine);
13
21
  }
14
22
 
15
- // 加载文件
23
+ /**
24
+ * 获取文件内容
25
+ * @public
26
+ * @param {string} [template]
27
+ * @returns {Promise<string>}
28
+ */
16
29
  async load(template) {
17
30
  const file_name = this.parseTplName(template);
18
31
  return await readFile(file_name);
19
32
  }
20
33
 
21
- // 渲染内容
34
+ /**
35
+ * 渲染(解析数据)内容
36
+ * @public
37
+ * @param {string} content
38
+ * @returns {Promise<string>}
39
+ */
22
40
  async render(content) {
23
41
  return this._engine.render(content, this._data);
24
42
  }
25
43
 
26
- // 渲染文件
44
+ /**
45
+ * 渲染(解析数据)文件
46
+ * @public
47
+ * @param {string} [template]
48
+ * @returns {Promise<string>}
49
+ */
27
50
  async fetch(template) {
28
51
  const file_name = this.parseTplName(template);
29
52
  return await this._engine(file_name, this._data || {});
30
53
  }
31
54
 
32
- //赋值模版数据
55
+ /**
56
+ * 模版数据赋值
57
+ * @public
58
+ * @param {(string|object)} name
59
+ * @param {*} [value]
60
+ * @returns {this}
61
+ */
33
62
  assign(name, value) {
34
63
  if(typeof name == 'string') {
35
64
  this._data[name] = value;
@@ -39,13 +68,25 @@ class View extends Context
39
68
  return this;
40
69
  }
41
70
 
42
- //获取模版数据
71
+ /**
72
+ * 获取模版数据
73
+ * @public
74
+ * @param {string} [name]
75
+ * @returns {object}
76
+ */
43
77
  data(name) {
44
78
  if(name) return this._data[name];
45
79
  else return this._data;
46
80
  }
47
81
 
48
- //解析模板地址
82
+ /**
83
+ * 解析模板地址
84
+ * @public
85
+ * @param {string} [template] - 默认当前请求方法名,支持智能解析
86
+ * @param {string} [view_folder] - 模板文件夹名字
87
+ * @param {string} [view_depr] - 模板文件分隔符
88
+ * @returns {string}
89
+ */
49
90
  parsePath(template=this.ctx.ACTION, view_folder, view_depr) {
50
91
  !view_folder && (view_folder = cfg_view.view_folder);
51
92
  !view_depr && (view_depr = cfg_view.view_depr);
@@ -58,10 +99,15 @@ class View extends Context
58
99
  }
59
100
  }
60
101
  path.extname(view_file) || (view_file += cfg_view.view_ext);
61
- return path.join(this.$config.app.base_dir, view_file);
102
+ return path.join(cfg_app.base_dir, view_file);
62
103
  }
63
104
 
64
- //解析模板名字
105
+ /**
106
+ * 解析模板名字
107
+ * @public
108
+ * @param {string} [template] - 默认当前请求方法名,支持智能解析
109
+ * @returns {string}
110
+ */
65
111
  parseTplName(template) {
66
112
  let file_name = this.parsePath(template, this._folder, this._depr);
67
113
  let is_file = isFileSync(file_name);
@@ -76,7 +122,12 @@ class View extends Context
76
122
  return file_name;
77
123
  }
78
124
 
79
- // 设置模版引擎
125
+ /**
126
+ * 设置模版引擎
127
+ * @public
128
+ * @param {(string|object)} engine
129
+ * @returns {this}
130
+ */
80
131
  setEngine(engine) {
81
132
  this._engine = typeof engine == 'string' ? require(engine) : engine;
82
133
  this._engine.defaults.debug = cfg_app.app_debug;
@@ -87,7 +138,13 @@ class View extends Context
87
138
  return this;
88
139
  }
89
140
 
90
- //设置模版函数
141
+ /**
142
+ * 设置模版函数
143
+ * @public
144
+ * @param {(string|object)} fun_obj - 函数名字或者包含多个函数的对象
145
+ * @param {*} [fun] - 函数
146
+ * @returns {this}
147
+ */
91
148
  setFilter(fun_obj, fun) {
92
149
  if(typeof fun_obj === 'string') {
93
150
  fun_obj = {[fun_obj]: fun};
@@ -99,13 +156,23 @@ class View extends Context
99
156
  return this;
100
157
  }
101
158
 
102
- //设置模版目录
159
+ /**
160
+ * 设置模板目录
161
+ * @public
162
+ * @param {string} view_folder - 文件夹名字
163
+ * @returns {this}
164
+ */
103
165
  setFolder(view_folder) {
104
166
  this._folder = view_folder;
105
167
  return this;
106
168
  }
107
169
 
108
- //设置文件分割符
170
+ /**
171
+ * 设置文件分割符
172
+ * @public
173
+ * @param {string} view_depr - 文件分隔符(默认'/',不分二级目录,可以设置为'_'或其他)
174
+ * @returns {this}
175
+ */
109
176
  setDepr(view_depr) {
110
177
  this._depr = view_depr;
111
178
  return this;
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "jj.js",
3
- "version": "0.8.8",
4
- "description": "A simple and lightweight MVC framework built on nodejs+koa2",
3
+ "version": "0.9.0",
4
+ "description": "A super simple lightweight NodeJS MVC framework(一个超级简单轻量的NodeJS MVC框架)",
5
5
  "main": "jj.js",
6
- "scripts": {
7
- },
6
+ "scripts": {},
8
7
  "repository": {
9
8
  "type": "git",
10
9
  "url": "git+https://github.com/yafoo/jj.js.git"
@@ -21,13 +20,16 @@
21
20
  },
22
21
  "homepage": "https://github.com/yafoo/jj.js#readme",
23
22
  "dependencies": {
24
- "@koa/router": "^10.1.1",
23
+ "@koa/router": "^12.0.1",
25
24
  "art-template": "^4.13.2",
26
25
  "escape-html": "^1.0.3",
27
26
  "is-class": "0.0.9",
28
- "koa": "^2.13.4",
27
+ "koa": "^2.15.0",
29
28
  "koa-body": "^5.0.0",
30
29
  "koa-static": "^5.0.0",
31
30
  "mysql": "^2.18.1"
31
+ },
32
+ "engines": {
33
+ "node": ">= 12.17.0"
32
34
  }
33
35
  }