mm_hook_func 0.0.0-stage → 1.0.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/index.js +24 -0
- package/lib/hook_func.js +143 -0
- package/package.json +28 -4
- package/test.js +22 -0
- package/README.md +0 -3
package/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { HookFunc } = require('./lib/hook_func.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 钩子函数单例
|
|
5
|
+
* @type {HookFunc|null}
|
|
6
|
+
*/
|
|
7
|
+
let hook_func = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 获取钩子函数单例
|
|
11
|
+
* @param {object} config 配置选项
|
|
12
|
+
* @returns {HookFunc} 钩子函数实例
|
|
13
|
+
*/
|
|
14
|
+
function getHookFunc(config) {
|
|
15
|
+
if (!hook_func) {
|
|
16
|
+
hook_func = new HookFunc(config);
|
|
17
|
+
}
|
|
18
|
+
return hook_func;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
HookFunc,
|
|
23
|
+
getHookFunc
|
|
24
|
+
};
|
package/lib/hook_func.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Base } = require('mm_corejs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 钩子函数类
|
|
7
|
+
*
|
|
8
|
+
* 维护一个「函数名 → 函数体」的注册表,供业务按名调用可替换的函数;
|
|
9
|
+
* 同时可作为插件通过 bind(web) 向 web 请求管道的 render 阶段注册钩子,
|
|
10
|
+
* 在渲染阶段对字符串结果按配置的函数名做统一处理。
|
|
11
|
+
*/
|
|
12
|
+
class HookFunc extends Base {
|
|
13
|
+
/**
|
|
14
|
+
* 模块默认配置
|
|
15
|
+
*/
|
|
16
|
+
static config = {
|
|
17
|
+
name: 'hook_func',
|
|
18
|
+
title: '钩子函数模块',
|
|
19
|
+
description: '函数名值注册表,并向 web 管道注册 render 钩子',
|
|
20
|
+
render_name: 'html_filter'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 函数注册表
|
|
25
|
+
* @type {Object<string, Function>}
|
|
26
|
+
*/
|
|
27
|
+
#funcs = {};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 已挂载的 web 服务器实例
|
|
31
|
+
* @type {Object|null}
|
|
32
|
+
*/
|
|
33
|
+
#web = null;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 添加函数
|
|
37
|
+
* @param {string} name 函数名称
|
|
38
|
+
* @param {Function} func 函数体
|
|
39
|
+
* @returns {HookFunc} 当前实例
|
|
40
|
+
* @throws {TypeError} 名称非法或函数体非函数时
|
|
41
|
+
*/
|
|
42
|
+
addFunc(name, func) {
|
|
43
|
+
if (typeof name !== 'string' || name === '') {
|
|
44
|
+
throw new TypeError(`${this._label()} name must be a non-empty string`);
|
|
45
|
+
}
|
|
46
|
+
if (typeof func !== 'function') {
|
|
47
|
+
throw new TypeError(`${this._label()} func must be a function`);
|
|
48
|
+
}
|
|
49
|
+
this.#funcs[name] = func;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 删除函数
|
|
55
|
+
* @param {string} name 函数名称
|
|
56
|
+
* @returns {boolean} 是否删除成功
|
|
57
|
+
*/
|
|
58
|
+
delFunc(name) {
|
|
59
|
+
if (!this.hasFunc(name)) return false;
|
|
60
|
+
delete this.#funcs[name];
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 获取函数
|
|
66
|
+
* @param {string} name 函数名称
|
|
67
|
+
* @returns {Function|undefined} 函数体,未注册时为 undefined
|
|
68
|
+
*/
|
|
69
|
+
getFunc(name) {
|
|
70
|
+
return this.#funcs[name];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 判断函数是否存在
|
|
75
|
+
* @param {string} name 函数名称
|
|
76
|
+
* @returns {boolean} 是否存在
|
|
77
|
+
*/
|
|
78
|
+
hasFunc(name) {
|
|
79
|
+
return typeof this.#funcs[name] === 'function';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 列出所有函数名称
|
|
84
|
+
* @returns {Array<string>} 函数名称列表
|
|
85
|
+
*/
|
|
86
|
+
listFuncs() {
|
|
87
|
+
return Object.keys(this.#funcs);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 清空函数注册表
|
|
92
|
+
* @returns {HookFunc} 当前实例
|
|
93
|
+
*/
|
|
94
|
+
clear() {
|
|
95
|
+
this.#funcs = {};
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 运行函数
|
|
101
|
+
* @param {string} name 函数名称
|
|
102
|
+
* @param {...*} args 函数参数
|
|
103
|
+
* @returns {Promise<*>} 函数返回值;未注册时原样返回最后一个参数
|
|
104
|
+
*/
|
|
105
|
+
async runFunc(name, ...args) {
|
|
106
|
+
const func = this.getFunc(name);
|
|
107
|
+
if (!func) {
|
|
108
|
+
return args.length > 0 ? args[args.length - 1] : undefined;
|
|
109
|
+
}
|
|
110
|
+
return await func(...args);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 绑定 web 服务器:向其请求管道的 render 阶段注册渲染钩子
|
|
115
|
+
* @param {Object} web web 服务器实例,需提供 getHandle() 方法
|
|
116
|
+
* @returns {HookFunc} 当前实例
|
|
117
|
+
* @throws {TypeError} web 不具备 getHandle 方法时
|
|
118
|
+
*/
|
|
119
|
+
bind(web) {
|
|
120
|
+
if (!web || typeof web.getHandle !== 'function') {
|
|
121
|
+
throw new TypeError(`${this._label()} web must provide getHandle()`);
|
|
122
|
+
}
|
|
123
|
+
this.#web = web;
|
|
124
|
+
web.getHandle().on('render', (params, ctx, options) => this._runRender(params, ctx, options), 100, 'hook_func');
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 执行 render 钩子:对字符串结果调用配置的渲染函数
|
|
130
|
+
* @param {Object} ctx 上下文对象
|
|
131
|
+
* @param {Object} params 请求参数
|
|
132
|
+
* @returns {Promise<*>} 渲染后的结果;结果非字符串时返回 undefined
|
|
133
|
+
*/
|
|
134
|
+
async _runRender(ctx, params) {
|
|
135
|
+
const html = ctx.result;
|
|
136
|
+
if (typeof html !== 'string') return undefined;
|
|
137
|
+
return await this.runFunc(this.config.render_name, ctx, params, html);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
HookFunc
|
|
143
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_hook_func",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "钩子函数模块,提供函数名值注册表并可作为插件向 web 管道注册 render 钩子。",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mm_mod",
|
|
8
|
+
"mm_infra",
|
|
9
|
+
"mm_common",
|
|
10
|
+
"hook",
|
|
11
|
+
"func",
|
|
12
|
+
"render"
|
|
13
|
+
],
|
|
14
|
+
"layer": "infra",
|
|
15
|
+
"group": "common",
|
|
16
|
+
"author": "邱文武",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"mm_corejs": "^1.1.4"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=12.0.0"
|
|
23
|
+
},
|
|
24
|
+
"directories": {
|
|
25
|
+
"lib": "lib"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "node test.js"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/test.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const assert = require('assert');
|
|
3
|
+
const mod = require('./index.js');
|
|
4
|
+
|
|
5
|
+
// 验证导出结构
|
|
6
|
+
assert.strictEqual(typeof mod.HookFunc, 'function', '应导出 HookFunc 类');
|
|
7
|
+
assert.strictEqual(typeof mod.getHookFunc, 'function', '应导出 getHookFunc 函数');
|
|
8
|
+
|
|
9
|
+
// 验证单例:多次获取返回同一实例
|
|
10
|
+
const h1 = mod.getHookFunc();
|
|
11
|
+
const h2 = mod.getHookFunc();
|
|
12
|
+
assert.ok(h1 instanceof mod.HookFunc, 'getHookFunc 应返回 HookFunc 实例');
|
|
13
|
+
assert.strictEqual(h1, h2, 'getHookFunc 应返回单例');
|
|
14
|
+
|
|
15
|
+
// 验证函数注册表基本功能
|
|
16
|
+
const fn = () => 'ok';
|
|
17
|
+
h1.addFunc('test_func', fn);
|
|
18
|
+
assert.strictEqual(h1.hasFunc('test_func'), true, 'addFunc 后 hasFunc 应为 true');
|
|
19
|
+
assert.strictEqual(h1.delFunc('test_func'), true, 'delFunc 应删除成功');
|
|
20
|
+
assert.strictEqual(h1.hasFunc('test_func'), false, 'delFunc 后 hasFunc 应为 false');
|
|
21
|
+
|
|
22
|
+
console.log('mm_hook_func 模块测试通过');
|
package/README.md
DELETED