jj.js 0.8.8 → 0.10.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,69 @@
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
- module.exports = fsFun;
1
+ const fs = require('fs');
2
+ const fsPromises = require('fs').promises;
3
+ const pt = require('path');
4
+
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;
15
+ }
16
+ }
17
+
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;
28
+ }
29
+ }
30
+ const isFileSync = path => {
31
+ return fs.existsSync(path) && fs.statSync(path).isFile();
32
+ }
33
+
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;
44
+ }
45
+ }
46
+ const isDirSync = path => {
47
+ return fs.existsSync(path) && fs.statSync(path).isDirectory();
48
+ }
49
+
50
+ // 生成多级目录
51
+ const mkdirs = async function (dirname) {
52
+ if(await isDir(dirname)) {
53
+ return true;
54
+ } else {
55
+ if(await mkdirs(pt.dirname(dirname))) {
56
+ await fsPromises.mkdir(dirname);
57
+ return true;
58
+ }
59
+ }
60
+ }
61
+
62
+ module.exports = {
63
+ exists,
64
+ isFile,
65
+ isFileSync,
66
+ isDir,
67
+ isDirSync,
68
+ mkdirs
69
+ };
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
@@ -1,35 +1,65 @@
1
1
  const path = require('path');
2
- const {readFile, isFileSync} = require('./utils/fs');
2
+ const {isFileSync} = require('./utils/fs');
3
+ const {readFile} = require('fs').promises;
3
4
  const {app: cfg_app, view: cfg_view} = require('./config');
4
5
  const {toLine} = require('./utils/str');
5
6
  const Context = require('./context');
6
7
 
8
+ /**
9
+ * @extends Context
10
+ */
7
11
  class View extends Context
8
12
  {
13
+ /**
14
+ * Initialize a new `View`
15
+ * @public
16
+ * @param {import('../types').KoaCtx} ctx
17
+ */
9
18
  constructor(ctx) {
10
19
  super(ctx);
11
20
  this._data = {};
12
21
  this.setEngine(cfg_view.view_engine);
13
22
  }
14
23
 
15
- // 加载文件
24
+ /**
25
+ * 获取文件内容
26
+ * @public
27
+ * @param {string} [template]
28
+ * @returns {Promise<string>}
29
+ */
16
30
  async load(template) {
17
31
  const file_name = this.parseTplName(template);
18
- return await readFile(file_name);
32
+ return (await readFile(file_name)).toString();
19
33
  }
20
34
 
21
- // 渲染内容
35
+ /**
36
+ * 渲染(解析数据)内容
37
+ * @public
38
+ * @param {string} content
39
+ * @returns {Promise<string>}
40
+ */
22
41
  async render(content) {
23
42
  return this._engine.render(content, this._data);
24
43
  }
25
44
 
26
- // 渲染文件
45
+ /**
46
+ * 渲染(解析数据)文件
47
+ * @public
48
+ * @param {string} [template]
49
+ * @returns {Promise<string>}
50
+ */
27
51
  async fetch(template) {
28
52
  const file_name = this.parseTplName(template);
29
53
  return await this._engine(file_name, this._data || {});
30
54
  }
31
55
 
32
- //赋值模版数据
56
+ /**
57
+ * 模版数据赋值
58
+ * @public
59
+ * @param {(string|object)} name
60
+ * @param {*} [value]
61
+ * @returns {this}
62
+ */
33
63
  assign(name, value) {
34
64
  if(typeof name == 'string') {
35
65
  this._data[name] = value;
@@ -39,13 +69,25 @@ class View extends Context
39
69
  return this;
40
70
  }
41
71
 
42
- //获取模版数据
72
+ /**
73
+ * 获取模版数据
74
+ * @public
75
+ * @param {string} [name]
76
+ * @returns {object}
77
+ */
43
78
  data(name) {
44
79
  if(name) return this._data[name];
45
80
  else return this._data;
46
81
  }
47
82
 
48
- //解析模板地址
83
+ /**
84
+ * 解析模板地址
85
+ * @public
86
+ * @param {string} [template] - 默认当前请求方法名,支持智能解析
87
+ * @param {string} [view_folder] - 模板文件夹名字
88
+ * @param {string} [view_depr] - 模板文件分隔符
89
+ * @returns {string}
90
+ */
49
91
  parsePath(template=this.ctx.ACTION, view_folder, view_depr) {
50
92
  !view_folder && (view_folder = cfg_view.view_folder);
51
93
  !view_depr && (view_depr = cfg_view.view_depr);
@@ -58,10 +100,15 @@ class View extends Context
58
100
  }
59
101
  }
60
102
  path.extname(view_file) || (view_file += cfg_view.view_ext);
61
- return path.join(this.$config.app.base_dir, view_file);
103
+ return path.join(cfg_app.base_dir, view_file);
62
104
  }
63
105
 
64
- //解析模板名字
106
+ /**
107
+ * 解析模板名字
108
+ * @public
109
+ * @param {string} [template] - 默认当前请求方法名,支持智能解析
110
+ * @returns {string}
111
+ */
65
112
  parseTplName(template) {
66
113
  let file_name = this.parsePath(template, this._folder, this._depr);
67
114
  let is_file = isFileSync(file_name);
@@ -76,7 +123,12 @@ class View extends Context
76
123
  return file_name;
77
124
  }
78
125
 
79
- // 设置模版引擎
126
+ /**
127
+ * 设置模版引擎
128
+ * @public
129
+ * @param {(string|object)} engine
130
+ * @returns {this}
131
+ */
80
132
  setEngine(engine) {
81
133
  this._engine = typeof engine == 'string' ? require(engine) : engine;
82
134
  this._engine.defaults.debug = cfg_app.app_debug;
@@ -87,7 +139,13 @@ class View extends Context
87
139
  return this;
88
140
  }
89
141
 
90
- //设置模版函数
142
+ /**
143
+ * 设置模版函数
144
+ * @public
145
+ * @param {(string|object)} fun_obj - 函数名字或者包含多个函数的对象
146
+ * @param {*} [fun] - 函数
147
+ * @returns {this}
148
+ */
91
149
  setFilter(fun_obj, fun) {
92
150
  if(typeof fun_obj === 'string') {
93
151
  fun_obj = {[fun_obj]: fun};
@@ -99,13 +157,23 @@ class View extends Context
99
157
  return this;
100
158
  }
101
159
 
102
- //设置模版目录
160
+ /**
161
+ * 设置模板目录
162
+ * @public
163
+ * @param {string} view_folder - 文件夹名字
164
+ * @returns {this}
165
+ */
103
166
  setFolder(view_folder) {
104
167
  this._folder = view_folder;
105
168
  return this;
106
169
  }
107
170
 
108
- //设置文件分割符
171
+ /**
172
+ * 设置文件分割符
173
+ * @public
174
+ * @param {string} view_depr - 文件分隔符(默认'/',不分二级目录,可以设置为'_'或其他)
175
+ * @returns {this}
176
+ */
109
177
  setDepr(view_depr) {
110
178
  this._depr = view_depr;
111
179
  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.10.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,19 @@
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
+ "devDependencies": {
33
+ "watch": "^1.0.2"
34
+ },
35
+ "engines": {
36
+ "node": ">= 12.17.0"
32
37
  }
33
38
  }