mm_files 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.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * mm_file 模块最小可运行示例
3
+ * @description 演示 File 文件存储类的文本/JSON 读写与删除等核心能力,
4
+ * 使用系统临时目录,示例结束自动清理
5
+ */
6
+ const fs = require('fs');
7
+ const os = require('os');
8
+ const path = require('path');
9
+ const { File, fileAdmin } = require('../index.js');
10
+
11
+ // 使用系统临时目录,示例结束自动清理
12
+ const TMP_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'mm_file_demo_'));
13
+
14
+ try {
15
+ // 创建 File 实例
16
+ const file = new File({ name: 'demo', dir: TMP_DIR });
17
+
18
+ // 写入并读取文本
19
+ file.saveText('hello.txt', 'hello mm_file');
20
+ console.log('hasFile:', file.hasFile('hello.txt'));
21
+ console.log('loadText:', file.loadText('hello.txt'));
22
+
23
+ // 写入并读取 JSON
24
+ file.saveJson('data.json', { name: 'mm_file', ok: true });
25
+ console.log('loadJson:', JSON.stringify(file.loadJson('data.json')));
26
+
27
+ // 复制与删除
28
+ file.copyFile('hello.txt', 'hello_copy.txt');
29
+ console.log('复制后存在:', file.hasFile('hello_copy.txt'));
30
+ file.delFile('hello.txt');
31
+ console.log('删除后存在:', file.hasFile('hello.txt'));
32
+
33
+ // 工厂函数获取实例
34
+ const file2 = fileAdmin('demo2', { dir: TMP_DIR });
35
+ console.log('fileAdmin 返回 File 实例:', file2 instanceof File);
36
+ } finally {
37
+ fs.rmSync(TMP_DIR, { recursive: true, force: true });
38
+ }
package/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * mm_files 文件存储模块
3
+ * @description 提供文件存储适配器,支持 os.js 的 .admin 工厂调用规则
4
+ */
5
+ const File = require('./lib/file');
6
+ const Admin = require('mm_corejs').Admin;
7
+
8
+ /**
9
+ * 文件管理器实例(Admin 工厂)
10
+ * 支持 os.js 调用:require('mm_files').admin.setServer(os) -> admin.get('os', config)
11
+ */
12
+ let admin = new Admin();
13
+ admin.setClass(File);
14
+
15
+ // 模块导出
16
+ module.exports = {
17
+ File,
18
+ admin,
19
+ fileAdmin(scope, config) {
20
+ if (!scope) {
21
+ scope = 'os';
22
+ }
23
+ return admin.get(scope, config);
24
+ }
25
+ };
package/lib/file.js ADDED
@@ -0,0 +1,259 @@
1
+ /**
2
+ * 文件存储操作类
3
+ * @description 基于 mm_helper 文件工具函数,封装文件读写、复制、删除、遍历等能力
4
+ */
5
+ const { Base } = require('mm_mod');
6
+ const { file: FileUtil } = require('mm_helper');
7
+ const {
8
+ fullname,
9
+ isFile,
10
+ isDir,
11
+ hasFile,
12
+ hasDir,
13
+ saveText,
14
+ loadText,
15
+ loadJson,
16
+ delFile,
17
+ delDir,
18
+ addDir,
19
+ copyFile,
20
+ copyDir,
21
+ getFile,
22
+ getDir,
23
+ getAllFile,
24
+ getAllDir,
25
+ dirname,
26
+ basename,
27
+ extname
28
+ } = require('mm_helper');
29
+
30
+ /**
31
+ * 文件存储操作类
32
+ * @class File
33
+ * @augments Base
34
+ */
35
+ class File extends Base {
36
+ /**
37
+ * 默认配置
38
+ */
39
+ static config = {
40
+ name: 'default',
41
+ dir: fullname('./data/'),
42
+ encode: 'utf-8'
43
+ };
44
+
45
+ /**
46
+ * 构造函数
47
+ * @param {Object} config 配置对象
48
+ */
49
+ constructor(config) {
50
+ super(config);
51
+ }
52
+
53
+ /**
54
+ * 补全文件路径
55
+ * @param {String} file 文件路径
56
+ * @returns {String} 完整路径
57
+ */
58
+ getFullname(file) {
59
+ return fullname(file, this.config.dir);
60
+ }
61
+
62
+ /**
63
+ * 判断路径是否为文件
64
+ * @param {String} path 文件路径
65
+ * @returns {Boolean} 是文件返回true,否则返回false
66
+ */
67
+ isFile(path) {
68
+ return isFile(path);
69
+ }
70
+
71
+ /**
72
+ * 判断路径是否为目录
73
+ * @param {String} path 目录路径
74
+ * @returns {Boolean} 是目录返回true,否则返回false
75
+ */
76
+ isDir(path) {
77
+ return isDir(path);
78
+ }
79
+
80
+ /**
81
+ * 判断文件是否存在
82
+ * @param {String} file 文件路径
83
+ * @returns {Boolean} 存在返回true,否则返回false
84
+ */
85
+ hasFile(file) {
86
+ return hasFile(this.getFullname(file));
87
+ }
88
+
89
+ /**
90
+ * 判断目录是否存在
91
+ * @param {String} dir 目录路径
92
+ * @returns {Boolean} 存在返回true,否则返回false
93
+ */
94
+ hasDir(dir) {
95
+ return hasDir(this.getFullname(dir));
96
+ }
97
+
98
+ /**
99
+ * 保存文本到文件
100
+ * @param {String} file 文件路径
101
+ * @param {String} text 文本内容
102
+ * @returns {Boolean} 保存成功返回true,否则返回false
103
+ */
104
+ saveText(file, text) {
105
+ return saveText(this.getFullname(file), text);
106
+ }
107
+
108
+ /**
109
+ * 保存对象为JSON文件
110
+ * @param {String} file 文件路径
111
+ * @param {Object} obj 被保存的对象
112
+ * @param {Boolean} format 是否格式化
113
+ * @param {Number} space 格式化缩进空格数
114
+ * @returns {Boolean} 保存成功返回true,否则返回false
115
+ */
116
+ saveJson(file, obj, format = true, space = 2) {
117
+ return FileUtil.saveJson(this.getFullname(file), obj, format, space);
118
+ }
119
+
120
+ /**
121
+ * 加载文本文件
122
+ * @param {String} file 文件路径
123
+ * @param {String} encode 编码方式
124
+ * @returns {String|undefined} 加载的文本
125
+ */
126
+ loadText(file, encode) {
127
+ return loadText(this.getFullname(file), encode || this.config.encode);
128
+ }
129
+
130
+ /**
131
+ * 加载JSON文件
132
+ * @param {String} file 文件路径
133
+ * @returns {Object|undefined} 加载后转换的对象
134
+ */
135
+ loadJson(file) {
136
+ return loadJson(this.getFullname(file));
137
+ }
138
+
139
+ /**
140
+ * 删除文件
141
+ * @param {String} file 文件路径
142
+ * @returns {void}
143
+ */
144
+ delFile(file) {
145
+ return delFile(this.getFullname(file));
146
+ }
147
+
148
+ /**
149
+ * 删除目录
150
+ * @param {String} dir 目录路径
151
+ * @returns {void}
152
+ */
153
+ delDir(dir) {
154
+ return delDir(this.getFullname(dir));
155
+ }
156
+
157
+ /**
158
+ * 创建目录
159
+ * @param {String} dir 目录路径
160
+ * @returns {void}
161
+ */
162
+ addDir(dir) {
163
+ return addDir(this.getFullname(dir));
164
+ }
165
+
166
+ /**
167
+ * 复制文件
168
+ * @param {String} source 源文件路径
169
+ * @param {String} target 目标路径
170
+ * @returns {Boolean} 复制成功返回true,否则返回false
171
+ */
172
+ copyFile(source, target) {
173
+ return copyFile(this.getFullname(source), this.getFullname(target));
174
+ }
175
+
176
+ /**
177
+ * 复制目录
178
+ * @param {String} source 源目录路径
179
+ * @param {String} target 目标路径
180
+ * @returns {Boolean} 复制成功返回true,否则返回false
181
+ */
182
+ copyDir(source, target) {
183
+ return copyDir(this.getFullname(source), this.getFullname(target));
184
+ }
185
+
186
+ /**
187
+ * 获取当前目录下所有文件
188
+ * @param {String} dir 目录路径
189
+ * @param {String} keyword 搜索关键词
190
+ * @returns {Array} 文件路径数组
191
+ */
192
+ getFile(dir, keyword) {
193
+ return getFile(this.getFullname(dir), keyword);
194
+ }
195
+
196
+ /**
197
+ * 获取当前目录下所有目录
198
+ * @param {String} dir 目录路径
199
+ * @param {String} keyword 搜索关键词
200
+ * @returns {Array} 目录路径数组
201
+ */
202
+ getDir(dir, keyword) {
203
+ return getDir(this.getFullname(dir), keyword);
204
+ }
205
+
206
+ /**
207
+ * 递归搜索目录下所有文件
208
+ * @param {String} dir 目录路径
209
+ * @param {String} keyword 文件搜索关键词
210
+ * @param {String} keyword_dir 目录搜索关键词
211
+ * @param {Array} ignore 忽略目录数组
212
+ * @param {Number} max_depth 最大搜索深度,-1表示不限制深度
213
+ * @returns {Array} 文件路径数组
214
+ */
215
+ getAllFile(dir, keyword, keyword_dir, ignore, max_depth) {
216
+ return getAllFile(this.getFullname(dir), keyword, keyword_dir, ignore, max_depth);
217
+ }
218
+
219
+ /**
220
+ * 递归搜索目录下所有目录
221
+ * @param {String} dir 目录路径
222
+ * @param {String} keyword 目录搜索关键词
223
+ * @param {Array} ignore 忽略目录数组
224
+ * @param {Number} max_depth 最大搜索深度,-1表示不限制深度
225
+ * @returns {Array} 目录路径数组
226
+ */
227
+ getAllDir(dir, keyword, ignore, max_depth) {
228
+ return getAllDir(this.getFullname(dir), keyword, ignore, max_depth);
229
+ }
230
+
231
+ /**
232
+ * 获取路径所在目录
233
+ * @param {String} path 路径
234
+ * @returns {String} 路径所在目录
235
+ */
236
+ getDirname(path) {
237
+ return dirname(path);
238
+ }
239
+
240
+ /**
241
+ * 获取路径基础名
242
+ * @param {String} path 路径
243
+ * @returns {String} 基础名
244
+ */
245
+ getBasename(path) {
246
+ return basename(path);
247
+ }
248
+
249
+ /**
250
+ * 获取路径拓展名
251
+ * @param {String} path 路径
252
+ * @returns {String} 拓展名
253
+ */
254
+ getExtname(path) {
255
+ return extname(path);
256
+ }
257
+ }
258
+
259
+ module.exports = File;
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
- "name": "mm_files",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
2
+ "name": "mm_files",
3
+ "version": "1.0.0",
4
+ "description": "高性能文件存储操作模块,提供文件读写、复制、删除、遍历等能力,支持与mm_framework无缝集成",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "node test.js",
8
+ "dev": "nodemon test.js",
9
+ "lint": "eslint . --config eslint.config.js",
10
+ "lint:fix": "eslint . --config eslint.config.js --fix"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://gitee.com/qiuwenwu91/mm_file.git"
15
+ },
16
+ "keywords": [
17
+ "mm_mod",
18
+ "mm_adapter",
19
+ "mm_persist",
20
+ "file",
21
+ "node.js",
22
+ "async",
23
+ "await",
24
+ "promise",
25
+ "storage",
26
+ "mm_file"
27
+ ],
28
+ "layer": "adapter",
29
+ "group": "persist",
30
+ "author": "邱文武",
31
+ "license": "MIT",
32
+ "bugs": {
33
+ "url": "https://gitee.com/qiuwenwu91/mm_file/issues"
34
+ },
35
+ "homepage": "https://gitee.com/qiuwenwu91/mm_file#readme",
36
+ "engines": {
37
+ "node": ">=14.0.0"
38
+ },
39
+ "dependencies": {
40
+ "mm_corejs": "^1.1.4",
41
+ "mm_mod": "^1.0.1",
42
+ "mm_helper": "^1.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "eslint": "^10.9.1",
46
+ "eslint-plugin-jsdoc": "^64.2.1",
47
+ "mm_eslint": "^1.7.7"
48
+ }
6
49
  }
package/test.js ADDED
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * mm_files 模块测试
5
+ * @description 验证 File 类的导出结构、实例化及基于临时目录的文件读写能力。
6
+ */
7
+
8
+ const assert = require('assert');
9
+ const fs = require('fs');
10
+ const os = require('os');
11
+ const path = require('path');
12
+
13
+ const { File, admin, fileAdmin } = require('./index');
14
+
15
+ let tempDir = '';
16
+ try {
17
+ // 创建临时目录,测试结束后清理
18
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mm_file_'));
19
+
20
+ // 1. 导出类型校验
21
+ assert.strictEqual(typeof File, 'function', 'File 应为构造函数');
22
+ assert.strictEqual(typeof admin, 'object', 'admin 应为对象');
23
+ assert.strictEqual(typeof admin.get, 'function', 'admin.get 应为函数');
24
+ assert.strictEqual(typeof fileAdmin, 'function', 'fileAdmin 应为函数');
25
+
26
+ // 2. 实例化校验
27
+ const file = new File({ name: 'test', dir: tempDir });
28
+ assert.ok(file instanceof File, '实例应属于 File 类');
29
+ assert.strictEqual(file.config.name, 'test');
30
+ assert.strictEqual(file.config.dir, tempDir);
31
+
32
+ // 3. 文本写入 / 存在判断 / 读取
33
+ assert.strictEqual(file.saveText('a.txt', 'hello mm_file'), true);
34
+ assert.strictEqual(file.hasFile('a.txt'), true);
35
+ assert.strictEqual(file.loadText('a.txt'), 'hello mm_file');
36
+
37
+ // 4. JSON 写入 / 读取
38
+ const jsonObj = { name: 'mm_file', ok: true };
39
+ assert.strictEqual(file.saveJson('data.json', jsonObj), true);
40
+ assert.deepStrictEqual(file.loadJson('data.json'), jsonObj);
41
+
42
+ // 5. 目录操作
43
+ fs.mkdirSync(path.join(tempDir, 'subdir'));
44
+ assert.strictEqual(file.hasDir('subdir'), true);
45
+ assert.strictEqual(file.isDir(file.getFullname('subdir')), true);
46
+ assert.strictEqual(file.isFile(file.getFullname('a.txt')), true);
47
+
48
+ // 6. 遍历操作
49
+ const files = file.getFile('.');
50
+ assert.ok(Array.isArray(files), 'getFile 应返回数组');
51
+ assert.ok(files.includes(file.getFullname('a.txt')), '遍历结果应包含 a.txt');
52
+ const dirs = file.getDir('.');
53
+ assert.ok(Array.isArray(dirs), 'getDir 应返回数组');
54
+ assert.ok(dirs.includes(file.getFullname('subdir')), '遍历结果应包含 subdir');
55
+ assert.ok(Array.isArray(file.getAllFile('.')), 'getAllFile 应返回数组');
56
+ assert.ok(Array.isArray(file.getAllDir('.')), 'getAllDir 应返回数组');
57
+
58
+ // 7. 复制 / 删除
59
+ assert.strictEqual(file.copyFile('a.txt', 'b.txt'), true);
60
+ assert.strictEqual(file.hasFile('b.txt'), true);
61
+ file.delFile('a.txt');
62
+ assert.strictEqual(file.hasFile('a.txt'), false);
63
+ file.delDir('subdir');
64
+ assert.strictEqual(file.hasDir('subdir'), false);
65
+
66
+ // 8. 工厂导出
67
+ const fa = fileAdmin('test', { dir: tempDir });
68
+ assert.ok(fa instanceof File, 'fileAdmin 应返回 File 实例');
69
+
70
+ console.log('mm_files 模块测试通过');
71
+ } finally {
72
+ if (tempDir) {
73
+ fs.rmSync(tempDir, { recursive: true, force: true });
74
+ }
75
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.