jj.js 0.10.0 → 0.12.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/CHANGELOG.md +7 -0
- package/README.md +17 -92
- package/jj.js +1 -1
- package/lib/app.js +8 -0
- package/lib/ctx.js +37 -35
- package/lib/db.js +1 -3
- package/lib/run.js +25 -21
- package/lib/storage.js +5 -0
- package/package.json +2 -4
- package/types.js +4 -2
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -6,15 +6,15 @@ A super simple lightweight NodeJS MVC framework(一个超级简单轻量的Nod
|
|
|
6
6
|
|
|
7
7
|
## 项目介绍
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
无论什么语言什么框架的程序,类库的使用都离不开require、import、include等导入模块,不用时,还得删除。而本框架基于proxy实现了类库自动加载、懒加载和Class自动实例化及单例化技术,所有的类库,想用直接调用,系统会自动导入。
|
|
10
10
|
|
|
11
11
|
### 项目特性
|
|
12
12
|
|
|
13
|
-
1.
|
|
14
|
-
2.
|
|
13
|
+
1. 系统架构为经典的MVC模式,模仿Thinkphp5,很容易上手
|
|
14
|
+
2. 系统类库、用户类库都支持自动加载、懒加载、Class自动生成单实例
|
|
15
15
|
3. 支持应用级、路由级、控制器级三级中间件,方便插件及二次开发
|
|
16
16
|
4. 支持单应用和多应用两种运行模式
|
|
17
|
-
5. 基于jsdoc
|
|
17
|
+
5. 基于jsdoc,提供完整的代码提示,自动生成应用端types类型文件
|
|
18
18
|
|
|
19
19
|
### 项目地址
|
|
20
20
|
|
|
@@ -230,17 +230,6 @@ const app = {
|
|
|
230
230
|
}
|
|
231
231
|
module.exports = app;
|
|
232
232
|
```
|
|
233
|
-
- 模板配置`./config/view.js`:
|
|
234
|
-
```javascript
|
|
235
|
-
const view = {
|
|
236
|
-
view_folder: 'view', // 模板目录名
|
|
237
|
-
view_depr: '/', // 模版文件名分割符,'/'代表二级目录
|
|
238
|
-
view_ext: '.htm', // 模版文件后缀
|
|
239
|
-
view_engine: 'art-template', // 默认模版引擎,字符串或引擎类,咱不支持更换
|
|
240
|
-
view_filter: {}, // 模版函数,配置注入模板的函数,默认会自动注入url函数
|
|
241
|
-
}
|
|
242
|
-
module.exports = view;
|
|
243
|
-
```
|
|
244
233
|
- 数据库配置`./config/db.js`:可以配置多个,方便程序里切换使用。
|
|
245
234
|
```javascript
|
|
246
235
|
const db = {
|
|
@@ -257,67 +246,7 @@ const db = {
|
|
|
257
246
|
}
|
|
258
247
|
module.exports = db;
|
|
259
248
|
```
|
|
260
|
-
|
|
261
|
-
```javascript
|
|
262
|
-
const log = {
|
|
263
|
-
log_level: [], // [error, warning, info, debug, http, sql]
|
|
264
|
-
log_handle: function(msg, level) {console.log(`[${format('YY-mm-dd HH:ii:ss')}] [${level}] ${typeof msg == 'String' ? msg : JSON.stringify(msg)}`);} //function(msg, level) {}
|
|
265
|
-
}
|
|
266
|
-
module.exports = log;
|
|
267
|
-
```
|
|
268
|
-
- 缓存配置`./config/cache.js`:
|
|
269
|
-
```javascript
|
|
270
|
-
const cache = {
|
|
271
|
-
cache_time: 60 * 60 * 24, // 默认缓存时间(1天),为空或false则为10年
|
|
272
|
-
clear_time: undefined // (undefined: 一天清理一次, 0: 关闭自动清理, >0: 为自动清理周期)
|
|
273
|
-
}
|
|
274
|
-
module.exports = cache;
|
|
275
|
-
```
|
|
276
|
-
- 分页配置`./config/page.js`:
|
|
277
|
-
```javascript
|
|
278
|
-
const page = {
|
|
279
|
-
page_key : 'page', // 默认分页标识
|
|
280
|
-
key_origin : 'query', // query 或 params
|
|
281
|
-
page_size : 10, // 默认分页大小
|
|
282
|
-
page_length : 5, // 默认分页长度,数字页码链接数量
|
|
283
|
-
|
|
284
|
-
//网址规则,可为空,可为路由名字,可用参数:页码${page}
|
|
285
|
-
//样例:':name'
|
|
286
|
-
//样例:'/list_${page}.html'
|
|
287
|
-
url_page : '',
|
|
288
|
-
url_index : '',
|
|
289
|
-
|
|
290
|
-
//模块样式 可用参数:网址${url},页码${page},总数${total_page},总页数${total_page}
|
|
291
|
-
index_tpl : '<li class="index"><a href="${url}">首页</a></li>',
|
|
292
|
-
end_tpl : '<li class="end"><a href="${url}">末页</a></li>',
|
|
293
|
-
prev_tpl : '<li class="prev"><a href="${url}">上一页</a></li>',
|
|
294
|
-
next_tpl : '<li class="next"><a href="${url}">下一页</a></li>',
|
|
295
|
-
list_tpl : '<li><a href="${url}">${page}</a></li>',
|
|
296
|
-
active_tpl : '<li class="active"><a href="${url}">${page}</a></li>',
|
|
297
|
-
info_tpl : '<span class="info">共${total_page}页,${total}条记录</span>',
|
|
298
|
-
|
|
299
|
-
//渲染模版
|
|
300
|
-
template : '<div class="pagination"><ul class="page">${index}${prev}${list}${next}${end}</ul>${info}</div>'
|
|
301
|
-
}
|
|
302
|
-
module.exports = page;
|
|
303
|
-
```
|
|
304
|
-
- 跳转模板配置`./config/tpl.js`:模板可以配置为自定义的
|
|
305
|
-
```javascript
|
|
306
|
-
const tpl = {
|
|
307
|
-
jump: require('./tpl/jump'), // 跳转模板
|
|
308
|
-
exception: require('./tpl/exception') // 异常页面模板
|
|
309
|
-
}
|
|
310
|
-
module.exports = tpl;
|
|
311
|
-
```
|
|
312
|
-
- 自定义配置`./config/self.js`:自定义配置同样可以直接通过`this.$config.self`使用。
|
|
313
|
-
```javascript
|
|
314
|
-
const self = {
|
|
315
|
-
option1: ''
|
|
316
|
-
option2: ''
|
|
317
|
-
...
|
|
318
|
-
}
|
|
319
|
-
module.exports = self;
|
|
320
|
-
```
|
|
249
|
+
|
|
321
250
|
- 路由配置`./config/routes.js`:
|
|
322
251
|
路由功能基于`@koa/router`开发,关于url匹配规则可以参考官方文档:[文档地址](https://www.npmjs.com/package/@koa/router)
|
|
323
252
|
|
|
@@ -338,26 +267,22 @@ module.exports = routes;
|
|
|
338
267
|
```
|
|
339
268
|
> 注意:本路由配置示例前两条规则为常规用法,后面的非常规用法,不建议使用。如果是单应用模式,可以去掉path参数里的app。
|
|
340
269
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
应用入口文件放在项目的根目录,名字可以任意改。
|
|
344
|
-
|
|
345
|
-
示例文件 `./server.js`
|
|
270
|
+
- 自定义配置`./config/self.js`:自定义配置同样可以直接通过`this.$config.self`使用。
|
|
346
271
|
```javascript
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
272
|
+
const self = {
|
|
273
|
+
option1: ''
|
|
274
|
+
option2: ''
|
|
275
|
+
...
|
|
276
|
+
}
|
|
277
|
+
module.exports = self;
|
|
352
278
|
```
|
|
353
|
-
|
|
279
|
+
- 其他配置项,请参考系统配置文件`jj.js/lib/config.js`
|
|
280
|
+
|
|
281
|
+
### 编码命名规范
|
|
354
282
|
|
|
355
|
-
|
|
283
|
+
类名使用大驼峰,方法名使用小驼峰,私有方法使用下划线前缀。
|
|
284
|
+
控制器文件名使用小写下划线。
|
|
356
285
|
|
|
357
|
-
通过以上文档,可以看到:
|
|
358
|
-
1. jj.js是一个轻量的mvc框架,几乎所有文件不使用就不会调用。
|
|
359
|
-
2. 同时也是个功能强大的框架,支持应用级、路由级、控制器级三级中间件。
|
|
360
|
-
3. 类库自动加载,只要是继承自`Context`的类库,都可以在方法内使用包含`$`前缀的属性自动加载其他资源。
|
|
361
286
|
|
|
362
287
|
## 应用案例
|
|
363
288
|
|
package/jj.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* jj.js核心库<br/>
|
|
3
|
-
* {App, Cache, Context, Controller, Cookie, Ctx, Db, Logger, Middleware, Model, Pagination, Response, Upload, Url, View, utils}
|
|
3
|
+
* {App, Cache, Context, Controller, Cookie, Ctx, Db, Logger, Middleware, Model, Pagination, Response, Upload, Url, View, utils, config}
|
|
4
4
|
* @module core
|
|
5
5
|
* @type {import('./types').Core}
|
|
6
6
|
*/
|
package/lib/app.js
CHANGED
|
@@ -4,6 +4,7 @@ const {app: cfg_app} = require('./config');
|
|
|
4
4
|
const Logger = require('./logger');
|
|
5
5
|
const Response = require('./response');
|
|
6
6
|
const router = require('./router');
|
|
7
|
+
const storage = require('./storage');
|
|
7
8
|
const pjson = require('../package.json');
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -16,6 +17,13 @@ class App extends Koa
|
|
|
16
17
|
* @param {...any} args - listen(port, ip, callback(err){})
|
|
17
18
|
*/
|
|
18
19
|
listen(...args) {
|
|
20
|
+
// storage
|
|
21
|
+
this.use(async (ctx, next) => {
|
|
22
|
+
await storage.run({}, async() => {
|
|
23
|
+
await next();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
19
27
|
// exception
|
|
20
28
|
this.use(async (ctx, next) => {
|
|
21
29
|
ctx.APP_TIME = Date.now();
|
package/lib/ctx.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
const
|
|
2
|
+
const storage = require('./storage');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 开发jj.js库本身时,可以设置为import('../types')
|
|
@@ -8,46 +8,48 @@ const loader = require('./loader');
|
|
|
8
8
|
const Ctx = new Proxy(class {}, {
|
|
9
9
|
construct() {
|
|
10
10
|
return new Proxy({__proto__: arguments[2].prototype}, {
|
|
11
|
-
get: (target, prop, receiver) => {
|
|
12
|
-
if(prop in target || typeof prop == 'symbol' || prop == 'inspect') {
|
|
13
|
-
return Reflect.get(target, prop, receiver);
|
|
11
|
+
get: (target, $prop, receiver) => {
|
|
12
|
+
if($prop in target || typeof $prop == 'symbol' || $prop == 'inspect') {
|
|
13
|
+
return Reflect.get(target, $prop, receiver);
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
const store = storage.getStore();
|
|
17
|
+
const $ = store.$;
|
|
18
|
+
const _ = store._;
|
|
19
|
+
if($prop == '$' || $prop == '_') {
|
|
20
|
+
return store[$prop];
|
|
19
21
|
}
|
|
20
|
-
if(prop.slice(0, 1) != '$') {
|
|
22
|
+
if($prop.slice(0, 1) != '$') {
|
|
21
23
|
return undefined;
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
|
|
26
|
+
const prop = $prop.slice(1);
|
|
27
|
+
const APP = store.APP;
|
|
28
|
+
const COMMON = store.COMMON;
|
|
29
|
+
|
|
30
|
+
// 缓存
|
|
31
|
+
if(_[APP][$prop] === undefined) {
|
|
32
|
+
if(_[APP][prop] && _[COMMON] && _[COMMON][prop]) {
|
|
33
|
+
_[APP][$prop] = new Proxy({}, {
|
|
34
|
+
get: (...args) => {
|
|
35
|
+
return _[APP][prop][args[1]] || _[COMMON][prop][args[1]];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
} else if(_[APP][prop]) {
|
|
39
|
+
_[APP][$prop] = _[APP][prop];
|
|
40
|
+
} else if(_[COMMON] && _[COMMON][prop]) {
|
|
41
|
+
_[APP][$prop] = _[COMMON][prop];
|
|
42
|
+
} else {
|
|
43
|
+
_[APP][$prop] = null;
|
|
44
|
+
}
|
|
45
|
+
// lib调用,防止覆盖
|
|
46
|
+
if(['logger', 'pagination', 'response', 'url', 'view'].includes(prop) && _[APP][$prop] && _[APP][$prop].__node && !_[APP][$prop].__node.isClass && $[prop]) {
|
|
47
|
+
_[APP][$prop] = $[prop];
|
|
46
48
|
}
|
|
47
|
-
return _[APP][prop] || _[pp] || (ctx.$ && ctx.$[pp]) || undefined;
|
|
48
|
-
} else {
|
|
49
|
-
return (target.$ || (target.$ = loader('../'))) && target.$[pp];
|
|
50
49
|
}
|
|
50
|
+
|
|
51
|
+
// 屏蔽部分lib
|
|
52
|
+
return _[APP][$prop] || _[prop] || (!['app', 'loader', 'router', 'run', 'storage', 'types'].includes(prop) && $[prop]) || undefined;
|
|
51
53
|
}
|
|
52
54
|
});
|
|
53
55
|
}
|
package/lib/db.js
CHANGED
|
@@ -699,9 +699,7 @@ class Db extends Context
|
|
|
699
699
|
async pagination({page, page_size, pagination} = {}) {
|
|
700
700
|
!page && (page = this._options.page.page);
|
|
701
701
|
!page_size && (page_size = this._options.page.pageSize);
|
|
702
|
-
|
|
703
|
-
pagination = this.$pagination.__node && this.$pagination.__node.isClass ? this.$pagination : this.$.pagination;
|
|
704
|
-
}
|
|
702
|
+
!pagination && (pagination = this.$pagination);
|
|
705
703
|
|
|
706
704
|
const options = {...this._options}; // 暂存options
|
|
707
705
|
const total = await this.count();
|
package/lib/run.js
CHANGED
|
@@ -2,38 +2,42 @@ const path = require('path');
|
|
|
2
2
|
const loader = require('./loader');
|
|
3
3
|
const {readFile} = require('fs').promises;
|
|
4
4
|
const {toHump} = require('./utils/str');
|
|
5
|
-
const
|
|
5
|
+
const config = require('./config');
|
|
6
|
+
const {app: cfg_app, view: cfg_view} = config;
|
|
6
7
|
const compose = require('koa-compose');
|
|
7
8
|
const Logger = require('./logger');
|
|
9
|
+
const storage = require('./storage');
|
|
8
10
|
|
|
9
11
|
async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
10
12
|
if(cfg_app.app_debug) {
|
|
11
13
|
Logger.http('Request:', ctx.request);
|
|
12
|
-
Logger.http(
|
|
14
|
+
Logger.http({Router: control_type, APP: ctx.APP, CONTROLLER: ctx.CONTROLLER, ACTION: ctx.ACTION});
|
|
13
15
|
Object.keys(ctx.params).length && Logger.http('Params:', ctx.params);
|
|
14
16
|
Object.keys(ctx.query).length && Logger.http('Get:', ctx.query);
|
|
15
17
|
Object.keys(ctx.request.body || {}).length && Logger.http('Post:', ctx.request.body);
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
// 设置store
|
|
21
|
+
const store = storage.getStore();
|
|
22
|
+
store.APP = ctx.APP;
|
|
23
|
+
store.CONTROLLER = ctx.CONTROLLER;
|
|
24
|
+
store.ACTION = ctx.ACTION;
|
|
25
|
+
store.COMMON = cfg_app.common_app;
|
|
18
26
|
// 设置根加载器
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
ctx._.config.log = log;
|
|
27
|
-
ctx._.config.cache = cache;
|
|
28
|
-
ctx._.config.cookie = cookie;
|
|
29
|
-
ctx._.config.tpl = tpl;
|
|
27
|
+
store.$ = loader('./', ctx);
|
|
28
|
+
store._ = loader(cfg_app.base_dir, ctx);
|
|
29
|
+
// 配置特殊处理
|
|
30
|
+
store._.config === undefined && (store._.config = {});
|
|
31
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
32
|
+
store._.config[key] = value;
|
|
33
|
+
});
|
|
30
34
|
|
|
31
35
|
// 应用、控制器、方法名字验证
|
|
32
36
|
if(~ctx.APP.indexOf('.') || ~ctx.CONTROLLER.indexOf('.') || ~ctx.ACTION.indexOf('.')) {
|
|
33
37
|
throw new Error(`RunError: 应用、控制器或方法名字不合法!`);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
if(ctx.APP[0] == '_' || ctx.APP[0] == '$' || !
|
|
40
|
+
if(ctx.APP[0] == '_' || ctx.APP[0] == '$' || !store._[ctx.APP]) {
|
|
37
41
|
if(cfg_app.app_debug) {
|
|
38
42
|
throw new Error(`RunError: 应用:${ctx.APP}不存在!`);
|
|
39
43
|
} else {
|
|
@@ -41,7 +45,7 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
if(!
|
|
48
|
+
if(!store._[ctx.APP][control_type]) {
|
|
45
49
|
if(cfg_app.app_debug) {
|
|
46
50
|
throw new Error(`RunError: 目录:${ctx.APP}/${control_type}不存在!`);
|
|
47
51
|
} else {
|
|
@@ -51,7 +55,7 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
51
55
|
|
|
52
56
|
// 模版文件内容直接输出
|
|
53
57
|
if(control_type == cfg_view.view_folder) {
|
|
54
|
-
const content = await readFile(path.join(
|
|
58
|
+
const content = await readFile(path.join(cfg_app.base_dir, `${ctx.APP}/${control_type}`, ctx.CONTROLLER + cfg_view.view_depr + ctx.ACTION + cfg_view.view_ext));
|
|
55
59
|
if(!content) {
|
|
56
60
|
throw new Error(`RunError: 模板文件:${ctx.APP}/${control_type}/${ctx.CONTROLLER + cfg_view.view_depr + ctx.ACTION + cfg_view.view_ext}不存在!`);
|
|
57
61
|
}
|
|
@@ -60,7 +64,7 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
// 控制器
|
|
63
|
-
const Controller =
|
|
67
|
+
const Controller = store._[ctx.APP][control_type][ctx.CONTROLLER] || store._[ctx.APP][control_type]['_empty'];
|
|
64
68
|
|
|
65
69
|
if(ctx.CONTROLLER[0] == '_' || ctx.CONTROLLER[0] == '$' || typeof Controller != 'function') {
|
|
66
70
|
if(cfg_app.app_debug) {
|
|
@@ -73,7 +77,7 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
73
77
|
// 控制器实例
|
|
74
78
|
const $controller = new Controller(ctx, next);
|
|
75
79
|
const humpAction = toHump(ctx.ACTION);
|
|
76
|
-
const action = typeof $controller[humpAction] == 'function' ? humpAction : '
|
|
80
|
+
const action = typeof $controller[humpAction] == 'function' ? humpAction : '_empty';
|
|
77
81
|
|
|
78
82
|
if(ctx.ACTION[0] == '_' || ctx.ACTION[0] == '$' || typeof $controller[action] != 'function') {
|
|
79
83
|
if(cfg_app.app_debug) {
|
|
@@ -96,13 +100,13 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
96
100
|
}
|
|
97
101
|
return stack.concat(async (ctx, next) => {
|
|
98
102
|
const [METHOD = action, MIDDLEWARE = ctx.CONTROLLER, APP = ctx.APP] = middle.middleware.split('/').reverse();
|
|
99
|
-
if(!
|
|
103
|
+
if(!store._[APP]) {
|
|
100
104
|
throw new Error(`RunError: 中间件应用:${APP}不存在!`);
|
|
101
105
|
}
|
|
102
|
-
if(!
|
|
106
|
+
if(!store._[APP]['middleware']) {
|
|
103
107
|
throw new Error(`RunError: 中间件目录:${APP}/middleware不存在!`);
|
|
104
108
|
}
|
|
105
|
-
const Middleware =
|
|
109
|
+
const Middleware = store._[APP]['middleware'][MIDDLEWARE];
|
|
106
110
|
if(!Middleware || typeof Middleware != 'function') {
|
|
107
111
|
throw new Error(`RunError: 中间件文件:${APP}/middleware/${MIDDLEWARE}不存在!`);
|
|
108
112
|
}
|
package/lib/storage.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jj.js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "A super simple lightweight NodeJS MVC framework(一个超级简单轻量的NodeJS MVC框架)",
|
|
5
5
|
"main": "jj.js",
|
|
6
6
|
"scripts": {},
|
|
@@ -27,9 +27,7 @@
|
|
|
27
27
|
"koa": "^2.15.0",
|
|
28
28
|
"koa-body": "^5.0.0",
|
|
29
29
|
"koa-static": "^5.0.0",
|
|
30
|
-
"mysql": "^2.18.1"
|
|
31
|
-
},
|
|
32
|
-
"devDependencies": {
|
|
30
|
+
"mysql": "^2.18.1",
|
|
33
31
|
"watch": "^1.0.2"
|
|
34
32
|
},
|
|
35
33
|
"engines": {
|
package/types.js
CHANGED
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
* @typedef {typeof import('./lib/model')} Model
|
|
12
12
|
* @typedef {typeof import('./lib/pagination')} Pagination
|
|
13
13
|
* @typedef {typeof import('./lib/response')} Response
|
|
14
|
+
* @typedef {typeof import('./lib/storage')} Storage
|
|
14
15
|
* @typedef {typeof import('./lib/upload')} Upload
|
|
15
16
|
* @typedef {typeof import('./lib/url')} Url
|
|
16
17
|
* @typedef {typeof import('./lib/view')} View
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
|
-
* @typedef {typeof import('./lib/app').prototype} AppInstance
|
|
21
21
|
* @typedef {typeof import('./lib/context').prototype} ContextInstance
|
|
22
22
|
* @typedef {typeof import('./lib/controller').prototype} ControllerInstance
|
|
23
23
|
* @typedef {typeof import('./lib/cookie').prototype} CookieInstance
|
|
@@ -50,12 +50,14 @@
|
|
|
50
50
|
* @property {Url} Url
|
|
51
51
|
* @property {View} View
|
|
52
52
|
* @property {Utils} utils
|
|
53
|
+
* @property {Config} config
|
|
54
|
+
* @property {Storage} storage
|
|
53
55
|
*/
|
|
54
56
|
|
|
55
57
|
/**
|
|
56
58
|
* @typedef {Object} $
|
|
57
|
-
* @property {(App & AppInstance)} app
|
|
58
59
|
* @property {Cache} cache
|
|
60
|
+
* @property {Config} config
|
|
59
61
|
* @property {ContextInstance} context
|
|
60
62
|
* @property {ControllerInstance} controller
|
|
61
63
|
* @property {CookieInstance} cookie
|