mm_dict 1.0.2 → 1.0.4

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 CHANGED
@@ -18,12 +18,12 @@ npm install mm_dict
18
18
  const { Dict, dictAdmin } = require('mm_dict');
19
19
 
20
20
  // 直接使用存储类
21
- const dict = new Dict('./data/dict.json');
21
+ const dict = new Dict({ file: './data/dict.json' });
22
22
  dict.set('val', 'value').set('生命值', 'hp');
23
23
  dict.save();
24
24
 
25
25
  // 通过管理器按作用域获取实例(相同作用域返回同一实例)
26
- const scoped = dictAdmin('app', './data/app_dict.json');
26
+ const scoped = dictAdmin('app', { file: './data/app_dict.json' });
27
27
  scoped.set('HP', 'hp');
28
28
  ```
29
29
 
@@ -40,7 +40,16 @@ scoped.set('HP', 'hp');
40
40
  | load | 从持久化文件加载 | - | boolean |
41
41
 
42
42
  ## 依赖
43
- - mm_corejs:提供 Admin 管理器
43
+ - mm_admin:提供 Admin 管理器
44
44
 
45
45
  ## 许可证
46
46
  ISC
47
+
48
+ ## 工具契约(LLM 可调用)
49
+
50
+ 本模块 `tool/` 下登记以下工具契约,实现位于 `lib/tools/<name>/`,`tool/<name>/index.js` 仅为薄适配层。
51
+ 其它模块可直接 `require('<pkg>').tools.<name>` 复用实现,无需经过工具注册面。
52
+
53
+ | 工具名 | 标题 | 说明 |
54
+ | --- | --- | --- |
55
+ | `dict` | 字符串字典 | 字符串键值字典读写 |
package/example/index.js CHANGED
@@ -23,14 +23,14 @@ function main() {
23
23
 
24
24
  // 方式2:类实例 + 文件持久化
25
25
  const file = path.join(TMP_DIR, 'dict.json');
26
- const dict = new Dict(file);
26
+ const dict = new Dict({ file });
27
27
  dict.set('zh', '中文').set('en', 'English');
28
28
  console.log('字典列表:', dict.list());
29
29
  console.log('has(zh):', dict.has('zh'));
30
30
  console.log('保存到文件:', dict.save());
31
31
 
32
32
  // 从文件重新加载
33
- const loaded = new Dict(file);
33
+ const loaded = new Dict({ file });
34
34
  loaded.load();
35
35
  console.log('加载后读取 en:', loaded.get('en'));
36
36
 
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
- const Admin = require('mm_corejs').Admin;
1
+ const { reg } = require('mm_admin');
2
2
  const Dict = require('./lib/dict.js');
3
3
 
4
- let admin = new Admin();
4
+ const admin = reg('dict');
5
5
  admin.setClass(Dict);
6
6
 
7
7
  module.exports = {
@@ -14,12 +14,13 @@ module.exports = {
14
14
  * @returns {Dict} 字典存储实例
15
15
  */
16
16
  dictAdmin(scope, config) {
17
- if (!scope) {
18
- scope = 'os';
19
- }
20
- return admin.get(scope, config);
17
+ return admin.get(scope || 'os', config);
21
18
  },
22
19
  getDict() {
23
20
  return admin.get('os');
24
21
  }
25
22
  };
23
+
24
+ /* mm-tool-logic-export 工具能力层:其它模块可 require("mm_dict").tools.<name> 直接引用 */
25
+ Object.defineProperty(module.exports, 'tools', { enumerable: true, configurable: true,
26
+ get: function () { return require('./lib/tools'); } });
package/jest.config.js ADDED
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Jest 测试配置
5
+ */
6
+ module.exports = {
7
+ testEnvironment: 'node',
8
+ testMatch: ['<rootDir>/test/**/*.test.js'],
9
+ collectCoverageFrom: ['lib/**/*.js', 'index.js'],
10
+ coverageThreshold: {
11
+ global: {
12
+ branches: 100,
13
+ functions: 100,
14
+ lines: 100,
15
+ statements: 100
16
+ }
17
+ }
18
+ };
package/lib/dict.js CHANGED
@@ -17,14 +17,6 @@ class Dict extends KvStore {
17
17
  throw new TypeError('dict 的值必须是字符串');
18
18
  }
19
19
  }
20
-
21
- /**
22
- * 是否允许覆盖已存在的配置项
23
- * @returns {boolean} 不允许覆盖返回 false
24
- */
25
- _isOverwritable() {
26
- return false;
27
- }
28
20
  }
29
21
 
30
22
  module.exports = Dict;
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+ /**
3
+ * dict —— 字符串字典工具
4
+ * 复用模块 Dict 实例(键值字符串约束由模块强制)。
5
+ */
6
+ const { dictAdmin } = require('../../../index.js');
7
+
8
+ /**
9
+ * 落盘:未配置持久化文件时只保留内存结果
10
+ * @param {object} store 存储实例
11
+ * @returns {boolean} 是否已落盘
12
+ */
13
+ function _save(store) {
14
+ const file = (store.config && store.config.file) || '';
15
+ if (!file) return false;
16
+ store.save();
17
+ return true;
18
+ }
19
+
20
+ async function main(params, ctx, options) {
21
+ void options;
22
+ const p = params || {};
23
+ const action = p.action || 'list';
24
+ const done = (data) => { ctx.output = data; return data; };
25
+
26
+ try {
27
+ const store = dictAdmin(p.scope || 'os');
28
+
29
+ if (action === 'set') {
30
+ if (!p.key) throw new TypeError('key 不能为空');
31
+ if (typeof p.value !== 'string') throw new TypeError('value 必须是字符串');
32
+ store.set(p.key, p.value);
33
+ _save(store);
34
+ return done({ code: 0, msg: '写入成功', key: p.key });
35
+ }
36
+
37
+ if (action === 'get') {
38
+ if (!p.key) throw new TypeError('key 不能为空');
39
+ return done({ code: 0, msg: '成功', key: p.key, value: store.get(p.key), exists: store.has(p.key) });
40
+ }
41
+
42
+ if (action === 'del') {
43
+ if (!p.key) throw new TypeError('key 不能为空');
44
+ const deleted = store.del(p.key);
45
+ _save(store);
46
+ return done({ code: 0, msg: deleted ? '删除成功' : '键不存在', key: p.key, deleted: !!deleted });
47
+ }
48
+
49
+ if (action === 'has') {
50
+ if (!p.key) throw new TypeError('key 不能为空');
51
+ return done({ code: 0, msg: '成功', key: p.key, exists: store.has(p.key) });
52
+ }
53
+
54
+ if (action === 'list') {
55
+ const list = store.list();
56
+ return done({ code: 0, msg: '成功', list, count: Object.keys(list || {}).length });
57
+ }
58
+
59
+ if (action === 'save') {
60
+ _save(store);
61
+ return done({ code: 0, msg: '已落盘', ok: true });
62
+ }
63
+
64
+ return done({ code: 10001, msg: '不支持的操作: ' + action });
65
+ } catch (error) {
66
+ return done({ code: 10000, msg: '执行失败:' + error.message, error: { name: error.name, message: error.message } });
67
+ }
68
+ }
69
+
70
+ module.exports = { main };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ /** 模块能力层:懒加载工具实现,避免模块入口被 require 时加载全部实现 */
5
+ module.exports = new Proxy({}, {
6
+ get(_t, key) {
7
+ if (typeof key !== 'string') return undefined;
8
+ if (!fs.existsSync(path.join(__dirname, key, 'index.js'))) return undefined;
9
+ return require('./' + key);
10
+ },
11
+ has(_t, key) {
12
+ return typeof key === 'string' && fs.existsSync(path.join(__dirname, key, 'index.js'));
13
+ },
14
+ ownKeys() { return fs.readdirSync(__dirname, { withFileTypes: true }).filter(e => e.isDirectory()).map(e => e.name); },
15
+ getOwnPropertyDescriptor(_t, key) { return this.has(_t, key) ? { enumerable: true, configurable: true } : undefined; }
16
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_dict",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "字典存储模块:键和值都只能是字符串,用于键值映射",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -15,15 +15,15 @@
15
15
  "字典",
16
16
  "存储"
17
17
  ],
18
- "layer": "infra",
19
- "group": "data",
18
+ "layer": "infrastructure",
19
+ "group": "state",
20
20
  "author": "邱文武",
21
21
  "license": "ISC",
22
22
  "scripts": {
23
23
  "test": "jest --coverage"
24
24
  },
25
25
  "dependencies": {
26
- "mm_corejs": "^1.1.4",
26
+ "mm_admin": "^1.1.0",
27
27
  "mm_kv_store": "^1.0.0"
28
28
  },
29
29
  "devDependencies": {
package/test/dict.test.js CHANGED
@@ -21,6 +21,10 @@ describe('mm_dict 模块入口', () => {
21
21
  it('dictAdmin 缺省作用域为 os', () => {
22
22
  expect(mod.dictAdmin()).toBeInstanceOf(Dict);
23
23
  });
24
+
25
+ it('getDict 返回 os 作用域的实例', () => {
26
+ expect(mod.getDict()).toBeInstanceOf(Dict);
27
+ });
24
28
  });
25
29
 
26
30
  describe('Dict', () => {
@@ -37,14 +41,14 @@ describe('Dict', () => {
37
41
  describe('构造', () => {
38
42
  it('默认不传文件路径时 file 为空字符串', () => {
39
43
  const dict = new Dict();
40
- expect(dict._file).toBe('');
44
+ expect(dict.config.file).toBe('');
41
45
  expect(dict.list()).toEqual({});
42
46
  });
43
47
 
44
48
  it('传入文件路径时保存路径', () => {
45
49
  const file = path.join(tmp_dir, 'dict.json');
46
- const dict = new Dict(file);
47
- expect(dict._file).toBe(file);
50
+ const dict = new Dict({ file });
51
+ expect(dict.config.file).toBe(file);
48
52
  });
49
53
  });
50
54
 
@@ -146,7 +150,7 @@ describe('Dict', () => {
146
150
 
147
151
  it('save 写入文件返回 true', () => {
148
152
  const file = path.join(tmp_dir, 'dict.json');
149
- const dict = new Dict(file);
153
+ const dict = new Dict({ file });
150
154
  dict.set('val', 'value');
151
155
  expect(dict.save()).toBe(true);
152
156
  expect(JSON.parse(fs.readFileSync(file, 'utf8'))).toEqual({ val: 'value' });
@@ -158,14 +162,14 @@ describe('Dict', () => {
158
162
  });
159
163
 
160
164
  it('文件不存在时 load 返回 false', () => {
161
- const dict = new Dict(path.join(tmp_dir, 'nope.json'));
165
+ const dict = new Dict({ file: path.join(tmp_dir, 'nope.json') });
162
166
  expect(dict.load()).toBe(false);
163
167
  });
164
168
 
165
169
  it('文件存在时 load 加载数据返回 true', () => {
166
170
  const file = path.join(tmp_dir, 'dict.json');
167
171
  fs.writeFileSync(file, JSON.stringify({ val: 'value', key: 'k' }));
168
- const dict = new Dict(file);
172
+ const dict = new Dict({ file });
169
173
  expect(dict.load()).toBe(true);
170
174
  expect(dict.get('val')).toBe('value');
171
175
  expect(dict.get('key')).toBe('k');
@@ -174,7 +178,7 @@ describe('Dict', () => {
174
178
  it('文件含非字符串值时 load 抛 TypeError', () => {
175
179
  const file = path.join(tmp_dir, 'dict.json');
176
180
  fs.writeFileSync(file, JSON.stringify({ val: 123 }));
177
- const dict = new Dict(file);
181
+ const dict = new Dict({ file });
178
182
  expect(() => dict.load()).toThrow('dict 的值必须是字符串');
179
183
  });
180
184
  });
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+ /**
3
+ * dict —— 工具契约适配层
4
+ * 业务实现归位于模块 lib/tools/dict/,本文件只把模块能力暴露给加载器。
5
+ * 其它模块可直接 require('mm_dict').tools.dict 复用。
6
+ */
7
+ module.exports = require('../../lib/tools/dict');
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "dict",
3
+ "title": "字符串字典",
4
+ "description": "基于 mm_dict 的字典存储能力:写入键值均为字符串的映射、读取、删除、判断存在、列出全部并落盘。适用场景:维护枚举映射(状态码→文案)、别名表、固定键值字典。",
5
+ "category": "状态存储",
6
+ "group": "state",
7
+ "type": "function",
8
+ "main": "./index.js",
9
+ "params": {
10
+ "type": "object",
11
+ "properties": {
12
+ "action": {
13
+ "type": "string",
14
+ "description": "操作类型: set(写入字典)/get(读取)/del(删除)/has(判断存在)/list(列出全部)/save(落盘)",
15
+ "enum": [
16
+ "set",
17
+ "get",
18
+ "del",
19
+ "has",
20
+ "list",
21
+ "save"
22
+ ],
23
+ "default": "set"
24
+ },
25
+ "key": {
26
+ "type": "string",
27
+ "description": "字典键(get/del/has/set 必填)"
28
+ },
29
+ "value": {
30
+ "type": "string",
31
+ "description": "字典值(set 必填,必须是字符串)"
32
+ },
33
+ "scope": {
34
+ "type": "string",
35
+ "description": "实例作用域,缺省 os",
36
+ "default": "os"
37
+ }
38
+ },
39
+ "required": [
40
+ "action"
41
+ ]
42
+ },
43
+ "returns": {
44
+ "type": "object",
45
+ "properties": {
46
+ "code": {
47
+ "type": "number",
48
+ "description": "0 表示成功,1xxxx 表示业务/执行异常"
49
+ },
50
+ "msg": {
51
+ "type": "string",
52
+ "description": "结果描述"
53
+ },
54
+ "value": {
55
+ "type": "string",
56
+ "description": "读取到的值(get)"
57
+ },
58
+ "exists": {
59
+ "type": "boolean",
60
+ "description": "是否存在"
61
+ },
62
+ "deleted": {
63
+ "type": "boolean",
64
+ "description": "是否删除成功(del)"
65
+ },
66
+ "list": {
67
+ "type": "object",
68
+ "description": "全部字典项(list)"
69
+ },
70
+ "count": {
71
+ "type": "number",
72
+ "description": "数量"
73
+ },
74
+ "error": {
75
+ "type": "object",
76
+ "description": "异常对象 { name, message }"
77
+ }
78
+ }
79
+ },
80
+ "handler": "manager"
81
+ }