mm_vars 0.0.0-stage → 1.0.1
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/README.md +46 -2
- package/example/index.js +49 -0
- package/index.js +22 -0
- package/lib/vars.js +10 -0
- package/package.json +30 -4
- package/test/vars.test.js +169 -0
package/README.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 变量管理器(mm_vars)
|
|
2
|
+
## 说明
|
|
3
|
+
mm_vars 是变量存储模块,用于存储和检索程序的临时变量,可随时修改和删除。
|
|
4
|
+
例如:step = 1,state = 'busy'。
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
## 功能
|
|
7
|
+
- 键名称为非空字符串,值可为任意类型
|
|
8
|
+
- 支持覆盖已有值
|
|
9
|
+
- 支持删除、判断存在、获取副本、清空
|
|
10
|
+
- 支持保存到 JSON 文件与从 JSON 文件加载
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
```bash
|
|
14
|
+
npm install mm_vars
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 快速开始
|
|
18
|
+
```javascript
|
|
19
|
+
const { Vars, varsAdmin } = require('mm_vars');
|
|
20
|
+
|
|
21
|
+
// 直接使用存储类
|
|
22
|
+
const vars = new Vars({ file: './data/vars.json' });
|
|
23
|
+
vars.set('step', 1).set('state', 'busy');
|
|
24
|
+
vars.save();
|
|
25
|
+
|
|
26
|
+
// 通过管理器按作用域获取实例(相同作用域返回同一实例)
|
|
27
|
+
const scoped = varsAdmin('app', { file: './data/app_vars.json' });
|
|
28
|
+
scoped.set('count', 10);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## API
|
|
32
|
+
| 方法 | 说明 | 参数 | 返回值 |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| set | 设置变量,可覆盖 | key, value | Vars |
|
|
35
|
+
| get | 获取变量 | key | * |
|
|
36
|
+
| del | 删除变量 | key | boolean |
|
|
37
|
+
| has | 判断变量是否存在 | key | boolean |
|
|
38
|
+
| list | 获取变量表副本 | - | object |
|
|
39
|
+
| clear | 清空所有变量 | - | Vars |
|
|
40
|
+
| save | 保存到持久化文件 | - | boolean |
|
|
41
|
+
| load | 从持久化文件加载 | - | boolean |
|
|
42
|
+
|
|
43
|
+
## 依赖
|
|
44
|
+
- mm_corejs:提供 Admin 管理器
|
|
45
|
+
|
|
46
|
+
## 许可证
|
|
47
|
+
ISC
|
package/example/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mm_vars 变量存储示例
|
|
3
|
+
* 演示 varsAdmin() 作用域工厂,以及 Vars 类可随时修改、
|
|
4
|
+
* 删除的键值变量存取与 JSON 文件持久化(save / load)。
|
|
5
|
+
* 运行:node example/index.js
|
|
6
|
+
*/
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { Vars, varsAdmin } = require('../index.js');
|
|
11
|
+
|
|
12
|
+
/** 示例临时目录 */
|
|
13
|
+
const TMP_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'mm-vars-example-'));
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 主流程
|
|
17
|
+
*/
|
|
18
|
+
function main() {
|
|
19
|
+
// 方式1:作用域工厂,获取 os 作用域的变量存储实例
|
|
20
|
+
const store = varsAdmin('os');
|
|
21
|
+
store.set('token', 'abc123');
|
|
22
|
+
console.log('工厂实例读取 token:', store.get('token'));
|
|
23
|
+
|
|
24
|
+
// 方式2:类实例 + 文件持久化
|
|
25
|
+
const file = path.join(TMP_DIR, 'vars.json');
|
|
26
|
+
const vars = new Vars({ file });
|
|
27
|
+
vars.set('name', 'demo').set('count', 1);
|
|
28
|
+
console.log('变量列表:', vars.list());
|
|
29
|
+
console.log('保存到文件:', vars.save());
|
|
30
|
+
|
|
31
|
+
// 变量可随时修改
|
|
32
|
+
vars.set('count', 2);
|
|
33
|
+
console.log('修改后 count:', vars.get('count'));
|
|
34
|
+
|
|
35
|
+
// 变量可删除
|
|
36
|
+
console.log('删除 name:', vars.del('name'));
|
|
37
|
+
console.log('删除后列表:', vars.list());
|
|
38
|
+
|
|
39
|
+
// 从文件重新加载(文件里是保存时的数据)
|
|
40
|
+
const loaded = new Vars({ file });
|
|
41
|
+
loaded.load();
|
|
42
|
+
console.log('重新加载后 name:', loaded.get('name'));
|
|
43
|
+
console.log('重新加载后 count:', loaded.get('count'));
|
|
44
|
+
|
|
45
|
+
// 清理临时目录
|
|
46
|
+
fs.rmSync(TMP_DIR, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
main();
|
package/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const Admin = require('mm_corejs').Admin;
|
|
2
|
+
const Vars = require('./lib/vars.js');
|
|
3
|
+
|
|
4
|
+
let admin = new Admin();
|
|
5
|
+
admin.setClass(Vars);
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
Vars,
|
|
9
|
+
admin,
|
|
10
|
+
/**
|
|
11
|
+
* 获取指定作用域的变量存储实例,不存在时创建
|
|
12
|
+
* @param {string} [scope] 作用域名称,缺省时使用 os
|
|
13
|
+
* @param {string} [config] 持久化文件路径
|
|
14
|
+
* @returns {Vars} 变量存储实例
|
|
15
|
+
*/
|
|
16
|
+
varsAdmin(scope, config) {
|
|
17
|
+
if (!scope) {
|
|
18
|
+
scope = 'os';
|
|
19
|
+
}
|
|
20
|
+
return admin.get(scope, config);
|
|
21
|
+
}
|
|
22
|
+
};
|
package/lib/vars.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_vars",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "变量存储模块:用于存储可随时修改和删除的键值变量",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://gitee.com/qiuwenwu91/mm_vars.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"mm_mod",
|
|
12
|
+
"mm_infra",
|
|
13
|
+
"mm_data",
|
|
14
|
+
"vars",
|
|
15
|
+
"变量",
|
|
16
|
+
"存储"
|
|
17
|
+
],
|
|
18
|
+
"layer": "infra",
|
|
19
|
+
"group": "data",
|
|
20
|
+
"author": "邱文武",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "jest --coverage"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"mm_corejs": "^1.1.4",
|
|
27
|
+
"mm_kv_store": "^1.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"jest": "^30.5.2"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const mod = require('../index');
|
|
7
|
+
const Vars = require('../lib/vars');
|
|
8
|
+
|
|
9
|
+
describe('mm_vars 模块入口', () => {
|
|
10
|
+
it('导出 Vars 类与管理器', () => {
|
|
11
|
+
expect(mod.Vars).toBe(Vars);
|
|
12
|
+
expect(mod.admin).toBeDefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('varsAdmin 按作用域缓存并返回实例', () => {
|
|
16
|
+
const first = mod.varsAdmin('vars_scope');
|
|
17
|
+
expect(first).toBeInstanceOf(Vars);
|
|
18
|
+
expect(mod.varsAdmin('vars_scope')).toBe(first);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('varsAdmin 缺省作用域为 os', () => {
|
|
22
|
+
expect(mod.varsAdmin()).toBeInstanceOf(Vars);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('Vars', () => {
|
|
27
|
+
let tmp_dir;
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
tmp_dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mm-vars-'));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
fs.rmSync(tmp_dir, { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('构造', () => {
|
|
38
|
+
it('默认不传文件路径时 file 为空字符串', () => {
|
|
39
|
+
const vars = new Vars();
|
|
40
|
+
expect(vars.config.file).toBe('');
|
|
41
|
+
expect(vars.list()).toEqual({});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('传入文件路径时保存路径', () => {
|
|
45
|
+
const file = path.join(tmp_dir, 'vars.json');
|
|
46
|
+
const vars = new Vars({ file });
|
|
47
|
+
expect(vars.config.file).toBe(file);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('set / get', () => {
|
|
52
|
+
it('set 后可通过 get 读取,并支持链式调用', () => {
|
|
53
|
+
const vars = new Vars();
|
|
54
|
+
expect(vars.set('name', 'test')).toBe(vars);
|
|
55
|
+
expect(vars.get('name')).toBe('test');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('set 可覆盖已有值', () => {
|
|
59
|
+
const vars = new Vars();
|
|
60
|
+
vars.set('count', 1);
|
|
61
|
+
vars.set('count', 2);
|
|
62
|
+
expect(vars.get('count')).toBe(2);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('get 不存在的键返回 undefined', () => {
|
|
66
|
+
const vars = new Vars();
|
|
67
|
+
expect(vars.get('nope')).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('set 非字符串键抛 TypeError', () => {
|
|
71
|
+
const vars = new Vars();
|
|
72
|
+
expect(() => vars.set(123, 'x')).toThrow('键名必须是非空字符串');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('set 空字符串键抛 TypeError', () => {
|
|
76
|
+
const vars = new Vars();
|
|
77
|
+
expect(() => vars.set('', 'x')).toThrow('键名必须是非空字符串');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('get 非字符串键抛 TypeError', () => {
|
|
81
|
+
const vars = new Vars();
|
|
82
|
+
expect(() => vars.get(null)).toThrow('键名必须是非空字符串');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('del / has', () => {
|
|
87
|
+
it('del 删除存在的键返回 true', () => {
|
|
88
|
+
const vars = new Vars();
|
|
89
|
+
vars.set('a', 1);
|
|
90
|
+
expect(vars.del('a')).toBe(true);
|
|
91
|
+
expect(vars.has('a')).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('del 不存在的键返回 false', () => {
|
|
95
|
+
const vars = new Vars();
|
|
96
|
+
expect(vars.del('nope')).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('del 非字符串键抛 TypeError', () => {
|
|
100
|
+
const vars = new Vars();
|
|
101
|
+
expect(() => vars.del('')).toThrow('键名必须是非空字符串');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('has 存在返回 true,不存在返回 false', () => {
|
|
105
|
+
const vars = new Vars();
|
|
106
|
+
vars.set('a', 1);
|
|
107
|
+
expect(vars.has('a')).toBe(true);
|
|
108
|
+
expect(vars.has('b')).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('has 非字符串键抛 TypeError', () => {
|
|
112
|
+
const vars = new Vars();
|
|
113
|
+
expect(() => vars.has(undefined)).toThrow('键名必须是非空字符串');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('list / clear', () => {
|
|
118
|
+
it('list 返回副本,不引用内部对象', () => {
|
|
119
|
+
const vars = new Vars();
|
|
120
|
+
vars.set('a', 1);
|
|
121
|
+
const list = vars.list();
|
|
122
|
+
expect(list).toEqual({ a: 1 });
|
|
123
|
+
list.a = 99;
|
|
124
|
+
expect(vars.get('a')).toBe(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('clear 清空所有变量', () => {
|
|
128
|
+
const vars = new Vars();
|
|
129
|
+
vars.set('a', 1);
|
|
130
|
+
vars.set('b', 2);
|
|
131
|
+
expect(vars.clear()).toBe(vars);
|
|
132
|
+
expect(vars.list()).toEqual({});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('save / load', () => {
|
|
137
|
+
it('未配置文件路径时 save 抛 Error', () => {
|
|
138
|
+
const vars = new Vars();
|
|
139
|
+
expect(() => vars.save()).toThrow('未配置持久化文件路径');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('save 写入文件返回 true', () => {
|
|
143
|
+
const file = path.join(tmp_dir, 'vars.json');
|
|
144
|
+
const vars = new Vars({ file });
|
|
145
|
+
vars.set('a', 1);
|
|
146
|
+
expect(vars.save()).toBe(true);
|
|
147
|
+
expect(JSON.parse(fs.readFileSync(file, 'utf8'))).toEqual({ a: 1 });
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('未配置文件路径时 load 返回 false', () => {
|
|
151
|
+
const vars = new Vars();
|
|
152
|
+
expect(vars.load()).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('文件不存在时 load 返回 false', () => {
|
|
156
|
+
const vars = new Vars({ file: path.join(tmp_dir, 'nope.json') });
|
|
157
|
+
expect(vars.load()).toBe(false);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('文件存在时 load 加载数据返回 true', () => {
|
|
161
|
+
const file = path.join(tmp_dir, 'vars.json');
|
|
162
|
+
fs.writeFileSync(file, JSON.stringify({ a: 1, b: 'x' }));
|
|
163
|
+
const vars = new Vars({ file });
|
|
164
|
+
expect(vars.load()).toBe(true);
|
|
165
|
+
expect(vars.get('a')).toBe(1);
|
|
166
|
+
expect(vars.get('b')).toBe('x');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|