@ainc/fs 0.1.22 → 0.1.24

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.
Files changed (64) hide show
  1. package/dist/cache.d.ts +16 -0
  2. package/dist/cache.js +24 -0
  3. package/dist/dict.d.ts +21 -0
  4. package/dist/dict.js +66 -0
  5. package/dist/download.js +4 -16
  6. package/dist/downloadFile.js +19 -13
  7. package/dist/gzip.d.ts +13 -0
  8. package/dist/gzip.js +50 -0
  9. package/dist/index.d.ts +37 -1
  10. package/dist/index.exports.json +34 -0
  11. package/dist/index.js +60 -3
  12. package/dist/isEsmModule.d.ts +18 -0
  13. package/dist/isEsmModule.js +63 -0
  14. package/dist/loadPackageDescription.d.ts +61 -0
  15. package/dist/loadPackageDescription.js +71 -0
  16. package/dist/loadTsConfig.d.ts +87 -0
  17. package/dist/loadTsConfig.js +219 -0
  18. package/dist/match.d.ts +30 -0
  19. package/dist/match.js +59 -0
  20. package/dist/promises.d.ts +69 -0
  21. package/dist/promises.js +103 -0
  22. package/dist/resolveAlias.d.ts +25 -0
  23. package/dist/resolveAlias.js +82 -0
  24. package/dist/resolveDirect.d.ts +15 -0
  25. package/dist/resolveDirect.js +144 -0
  26. package/dist/resolveExports.d.ts +19 -0
  27. package/dist/resolveExports.js +54 -0
  28. package/dist/resolveImports.d.ts +21 -0
  29. package/dist/resolveImports.js +114 -0
  30. package/dist/resolveModuleDir.d.ts +12 -0
  31. package/dist/resolveModuleDir.js +67 -0
  32. package/dist/resolveModuleId.d.ts +6 -0
  33. package/dist/resolveModuleId.js +32 -0
  34. package/dist/resolvePath.d.ts +23 -0
  35. package/dist/resolvePath.js +86 -0
  36. package/dist/resolvePaths.d.ts +13 -0
  37. package/dist/resolvePaths.js +42 -0
  38. package/dist/split.d.ts +6 -0
  39. package/dist/split.js +24 -0
  40. package/dist/sys.d.ts +60 -0
  41. package/dist/sys.js +260 -0
  42. package/esm/cache.mjs +22 -0
  43. package/esm/dict.mjs +63 -0
  44. package/esm/download.mjs +4 -16
  45. package/esm/downloadFile.mjs +19 -13
  46. package/esm/gzip.mjs +47 -0
  47. package/esm/index.exports.json +34 -0
  48. package/esm/index.mjs +29 -1
  49. package/esm/isEsmModule.mjs +59 -0
  50. package/esm/loadPackageDescription.mjs +67 -0
  51. package/esm/loadTsConfig.mjs +215 -0
  52. package/esm/match.mjs +53 -0
  53. package/esm/promises.mjs +96 -0
  54. package/esm/resolveAlias.mjs +79 -0
  55. package/esm/resolveDirect.mjs +142 -0
  56. package/esm/resolveExports.mjs +51 -0
  57. package/esm/resolveImports.mjs +112 -0
  58. package/esm/resolveModuleDir.mjs +64 -0
  59. package/esm/resolveModuleId.mjs +30 -0
  60. package/esm/resolvePath.mjs +84 -0
  61. package/esm/resolvePaths.mjs +40 -0
  62. package/esm/split.mjs +22 -0
  63. package/esm/sys.mjs +258 -0
  64. package/package.json +5 -6
package/esm/index.mjs CHANGED
@@ -5,6 +5,22 @@
5
5
  *****************************************
6
6
  */
7
7
  'use strict';
8
+ /**
9
+ *****************************************
10
+ * 文件系统
11
+ *****************************************
12
+ */
13
+ export { sys } from './sys.mjs';
14
+ /**
15
+ *****************************************
16
+ * 导出工具
17
+ *****************************************
18
+ */
19
+ export { unary, noop, nil, match } from './match.mjs';
20
+ export { split } from './split.mjs';
21
+ export { cache } from './cache.mjs';
22
+ export { retry } from './retry.mjs';
23
+ export { Dict } from './dict.mjs';
8
24
  /**
9
25
  *****************************************
10
26
  * 导出接口
@@ -13,8 +29,8 @@
13
29
  export { resolve, join, isAbsolute } from 'node:path';
14
30
  export { relative, isRelative } from './relative.mjs';
15
31
  export { dirname } from './dirname.mjs';
32
+ export { isEsmModule, isEsmFile, isEsmPackage } from './isEsmModule.mjs';
16
33
  export { stat, isDir, isFile } from './stat.mjs';
17
- export { resolveFile } from './resolveFile.mjs';
18
34
  export { readFile } from './readFile.mjs';
19
35
  export { writeFile } from './writeFile.mjs';
20
36
  export { copy } from './copy.mjs';
@@ -24,3 +40,15 @@ export { md5 } from './md5.mjs';
24
40
  export { json, jsonc } from './jsonc.mjs';
25
41
  export { findUp } from './findUp.mjs';
26
42
  export { download } from './download.mjs';
43
+ export { gzip, ungzip } from './gzip.mjs';
44
+ export { loadPackageDescription, resolvePackageDescription } from './loadPackageDescription.mjs';
45
+ export { loadTsConfig, loadCompilerOptions, resolveTsConfig } from './loadTsConfig.mjs';
46
+ export { resolveAlias, resolveDict } from './resolveAlias.mjs';
47
+ export { resolvePaths } from './resolvePaths.mjs';
48
+ export { resolvePath } from './resolvePath.mjs';
49
+ export { resolveFile } from './resolveFile.mjs';
50
+ export { resolveDirect } from './resolveDirect.mjs';
51
+ export { resolveImports } from './resolveImports.mjs';
52
+ export { resolveExports } from './resolveExports.mjs';
53
+ export { resolveModuleDir, resolveModuleDirs } from './resolveModuleDir.mjs';
54
+ export { resolveModuleId } from './resolveModuleId.mjs';
@@ -0,0 +1,59 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-18 20:14:00
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { dirname, extname } from 'node:path';
14
+ import { loadPackageDescription } from './loadPackageDescription.mjs';
15
+ /**
16
+ *****************************************
17
+ * 判断是否为 ESM 模块
18
+ *****************************************
19
+ */
20
+ export function isEsmModule(filename, dir = dirname(filename)) {
21
+ const result = isEsmFile(filename);
22
+ // 文件扩展名未匹配成功时,解析文件所在包的配置
23
+ if (result === undefined) {
24
+ return isEsmPackage(dir);
25
+ }
26
+ else {
27
+ return result;
28
+ }
29
+ }
30
+ /**
31
+ *****************************************
32
+ * 判断是否为 ESM 模块
33
+ *****************************************
34
+ */
35
+ export function isEsmPackage(dir) {
36
+ const pkg = loadPackageDescription(dir);
37
+ if (pkg && pkg.type === 'module') {
38
+ return true;
39
+ }
40
+ else {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ *****************************************
46
+ * 判断为 ESM 文件
47
+ *****************************************
48
+ */
49
+ export function isEsmFile(filename) {
50
+ const ext = extname(filename);
51
+ // 判断 mjs 模块
52
+ if (['.mjs', '.mts', '.mjsx', '.mtsx'].includes(ext)) {
53
+ return true;
54
+ }
55
+ // 判断 cjs 模块
56
+ if (['.cjs', '.cts', '.cjsx', '.ctsx'].includes(ext)) {
57
+ return false;
58
+ }
59
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2023-12-02 11:43:57
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { sep } from 'node:path';
14
+ import { isFile } from './stat.mjs';
15
+ import { lookup } from './lookup.mjs';
16
+ import { json } from './jsonc.mjs';
17
+ import { readFile } from './readFile.mjs';
18
+ /**
19
+ *****************************************
20
+ * 加载包描述
21
+ *****************************************
22
+ */
23
+ export function loadPackageDescription(from) {
24
+ const data = resolvePackageDescription(from);
25
+ // 返回配置
26
+ if (data) {
27
+ return data.config;
28
+ }
29
+ }
30
+ /**
31
+ *****************************************
32
+ * 读取包描述
33
+ *****************************************
34
+ */
35
+ export function readPackageDescription(dir) {
36
+ const data = resolvePackageDescription(dir);
37
+ // 返回配置
38
+ if (data && data.path.startsWith(dir)) {
39
+ return data.config;
40
+ }
41
+ }
42
+ /**
43
+ *****************************************
44
+ * 缓存
45
+ *****************************************
46
+ */
47
+ const cache = new Map();
48
+ const moduleDir = sep + 'node_modules';
49
+ /**
50
+ *****************************************
51
+ * 解析包配置
52
+ *****************************************
53
+ */
54
+ export function resolvePackageDescription(from) {
55
+ return lookup('package.json', {
56
+ from,
57
+ cache,
58
+ resolve(path, dir) {
59
+ if (isFile(path)) {
60
+ return { dir, path, config: json(readFile(path)) };
61
+ }
62
+ if (dir.endsWith(moduleDir)) {
63
+ return { dir, path };
64
+ }
65
+ },
66
+ });
67
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2023-12-30 13:48:09
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { readFileSync } from 'node:fs';
14
+ import { dirname, resolve, sep, isAbsolute } from 'node:path';
15
+ import { relative, isRelative } from './relative.mjs';
16
+ import { resolveFile } from './resolveFile.mjs';
17
+ import { isFile } from './stat.mjs';
18
+ import { lookup } from './lookup.mjs';
19
+ import { jsonc } from './jsonc.mjs';
20
+ import { match } from './match.mjs';
21
+ import { resolveModuleDirs } from './resolveModuleDir.mjs';
22
+ /**
23
+ *****************************************
24
+ * 加载 TS 配置
25
+ *****************************************
26
+ */
27
+ export function loadTsConfig(from) {
28
+ const data = resolveTsConfig(from);
29
+ // 返回配置
30
+ if (data) {
31
+ return data.config;
32
+ }
33
+ }
34
+ /**
35
+ *****************************************
36
+ * 加载编译配置
37
+ *****************************************
38
+ */
39
+ export function loadCompilerOptions(from) {
40
+ const data = resolveTsConfig(from);
41
+ // 返回配置
42
+ if (data && data.config) {
43
+ return data.config.compilerOptions;
44
+ }
45
+ }
46
+ /**
47
+ *****************************************
48
+ * 缓存内容
49
+ *****************************************
50
+ */
51
+ const cache = new Map();
52
+ /**
53
+ *****************************************
54
+ * 解析 TS 配置
55
+ *****************************************
56
+ */
57
+ export function resolveTsConfig(from) {
58
+ return lookup('tsconfig.json', {
59
+ from,
60
+ cache,
61
+ resolve(path) {
62
+ return isFile(path) ? loadTsConfigFile(path) : undefined;
63
+ },
64
+ });
65
+ }
66
+ /**
67
+ *****************************************
68
+ * 解析 TS 配置文件
69
+ *****************************************
70
+ */
71
+ function loadTsConfigFile(path) {
72
+ const config = parseTsConfig(path, new Set([path]), ['.json', sep + 'tsconfig.json']);
73
+ const dir = dirname(path);
74
+ // 移除继承属性
75
+ config.extends = undefined;
76
+ // 格式化 include 配置
77
+ if (config.include) {
78
+ config.include = config.include.map(path => relative(dir, path));
79
+ }
80
+ // 格式化 exclude 配置
81
+ if (config.exclude) {
82
+ config.exclude = config.exclude.map(path => relative(dir, path));
83
+ }
84
+ // 格式化 files 配置
85
+ if (config.files) {
86
+ config.files = config.files.map(path => relative(dir, path));
87
+ }
88
+ // 返回结果
89
+ return { path, config };
90
+ }
91
+ /**
92
+ *****************************************
93
+ * 解析配置
94
+ *****************************************
95
+ */
96
+ function parseTsConfig(path, tracker, extensions) {
97
+ const data = jsonc(readFileSync(path, 'utf8'));
98
+ const dir = dirname(path);
99
+ const config = normalizeTsConfig(data, dir);
100
+ // 不存在继承,直接返回
101
+ if (!config.extends) {
102
+ return config;
103
+ }
104
+ // 获取继承列表
105
+ const extendsList = Array.isArray(config.extends) ? config.extends : [config.extends];
106
+ const configs = extendsList.map(path => parseExtendsTsConfig(path, dir, tracker, extensions));
107
+ // 追加当前配置
108
+ configs.push(config);
109
+ // 合并配置
110
+ return configs.reduce(mergeTsConfig);
111
+ }
112
+ /**
113
+ *****************************************
114
+ * 合并配置
115
+ *****************************************
116
+ */
117
+ function mergeTsConfig(target, source) {
118
+ const { baseUrl, paths } = source.compilerOptions || {};
119
+ const config = { ...target, ...source };
120
+ // 合并配置项
121
+ config.compilerOptions = { ...target.compilerOptions, ...source.compilerOptions };
122
+ config.watchOptions = { ...target.watchOptions, ...source.watchOptions };
123
+ // 更新 paths 配置
124
+ if (baseUrl || paths) {
125
+ config.compilerOptions.baseUrl = baseUrl;
126
+ config.compilerOptions.paths = paths;
127
+ }
128
+ // 返回配置
129
+ return config;
130
+ }
131
+ /**
132
+ *****************************************
133
+ * 解析继承配置
134
+ *****************************************
135
+ */
136
+ function parseExtendsTsConfig(path, from, tracker, extensions) {
137
+ const extendsFile = resolveExtendsFile(path, from, extensions);
138
+ // 未找到文件
139
+ if (!extendsFile) {
140
+ throw new Error(`file '${path}' not found.`);
141
+ }
142
+ // 循环引用
143
+ if (tracker.has(extendsFile)) {
144
+ throw new Error(`circularity detected while resolving configuration: ${extendsFile}`);
145
+ }
146
+ // 添加引用文件
147
+ tracker.add(extendsFile);
148
+ // 解析文件
149
+ return parseTsConfig(extendsFile, tracker, extensions);
150
+ }
151
+ /**
152
+ *****************************************
153
+ * 解析继承文件地址
154
+ *****************************************
155
+ */
156
+ function resolveExtendsFile(path, from, extensions) {
157
+ // 解析相对路径
158
+ if (isRelative(path)) {
159
+ return resolveFile(resolve(from, path), extensions);
160
+ }
161
+ // 解析绝对路径
162
+ if (isAbsolute(path)) {
163
+ return resolveFile(path, extensions);
164
+ }
165
+ // 解析模块目录
166
+ const moduleDirs = resolveModuleDirs(from);
167
+ // 模块目录
168
+ return match(moduleDirs, dir => resolveFile(resolve(dir, path), extensions));
169
+ }
170
+ /**
171
+ *****************************************
172
+ * 格式化配置
173
+ *****************************************
174
+ */
175
+ function normalizeTsConfig(config, dir) {
176
+ const compilerOptions = config.compilerOptions;
177
+ const watchOptions = config.watchOptions;
178
+ // 格式化 include 配置
179
+ if (config.include) {
180
+ config.include = config.include.map(path => resolve(dir, path));
181
+ }
182
+ // 格式化 exclude 配置
183
+ if (config.exclude) {
184
+ config.exclude = config.exclude.map(path => resolve(dir, path));
185
+ }
186
+ // 格式化 files 配置
187
+ if (config.files) {
188
+ config.files = config.files.map(path => resolve(dir, path));
189
+ }
190
+ // 格式化 compilerOptions 配置
191
+ if (compilerOptions) {
192
+ // 格式化 baseUrl 配置
193
+ if (compilerOptions.baseUrl) {
194
+ compilerOptions.baseUrl = resolve(dir, compilerOptions.baseUrl);
195
+ }
196
+ // 格式化 outDir 配置
197
+ if (compilerOptions.outDir) {
198
+ compilerOptions.outDir = resolve(dir, compilerOptions.outDir);
199
+ }
200
+ // 格式化 rootDir 配置
201
+ if (compilerOptions.rootDir) {
202
+ compilerOptions.rootDir = resolve(dir, compilerOptions.rootDir);
203
+ }
204
+ // 格式化 rootDirs 配置
205
+ if (compilerOptions.rootDirs) {
206
+ compilerOptions.rootDirs = compilerOptions.rootDirs.map(path => resolve(dir, path));
207
+ }
208
+ }
209
+ // 格式化监听路径
210
+ if (watchOptions && watchOptions.excludeDirectories) {
211
+ watchOptions.excludeDirectories = watchOptions.excludeDirectories.map(path => resolve(dir, path));
212
+ }
213
+ // 返回配置
214
+ return config;
215
+ }
package/esm/match.mjs ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-18 15:12:42
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 空函数
11
+ *****************************************
12
+ */
13
+ export function noop() {
14
+ // do nothing
15
+ }
16
+ /**
17
+ *****************************************
18
+ * nil 函数
19
+ *****************************************
20
+ */
21
+ export function nil() {
22
+ return null;
23
+ }
24
+ /**
25
+ *****************************************
26
+ * false
27
+ *****************************************
28
+ */
29
+ export function falsy() {
30
+ return false;
31
+ }
32
+ /**
33
+ *****************************************
34
+ * 一元函数
35
+ *****************************************
36
+ */
37
+ export function unary(value) {
38
+ return value;
39
+ }
40
+ /**
41
+ *****************************************
42
+ * 执行匹配
43
+ *****************************************
44
+ */
45
+ export function match(list, handler) {
46
+ for (let i = 0; i < list.length; i++) {
47
+ const result = handler(list[i]);
48
+ // 查找到结果
49
+ if (result !== undefined) {
50
+ return result;
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-21 12:37:59
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ import { dirname } from 'node:path';
9
+ import * as fs from 'node:fs/promises';
10
+ /**
11
+ *****************************************
12
+ * 获取文件状态
13
+ *****************************************
14
+ */
15
+ export async function stat(path, options) {
16
+ return fs.stat(path, options).catch(err => err.code === 'ENOENT' ? null : Promise.reject(err));
17
+ }
18
+ /**
19
+ *****************************************
20
+ * 删除文件
21
+ *****************************************
22
+ */
23
+ export async function rm(path, options) {
24
+ if (await stat(path)) {
25
+ await fs.rm(path, { force: true, recursive: true, ...options });
26
+ }
27
+ }
28
+ /**
29
+ *****************************************
30
+ * 创建文件目录
31
+ *****************************************
32
+ */
33
+ export async function mkdir(path, options) {
34
+ const stats = await stat(path);
35
+ const opts = { recursive: true, ...options };
36
+ // 创建目录
37
+ if (!stats) {
38
+ await fs.mkdir(path, opts);
39
+ return true;
40
+ }
41
+ else if (stats.isDirectory()) {
42
+ return true;
43
+ }
44
+ else if (!opts.force) {
45
+ return false;
46
+ }
47
+ else {
48
+ await fs.unlink(path);
49
+ await fs.mkdir(path, opts);
50
+ return true;
51
+ }
52
+ }
53
+ /**
54
+ *****************************************
55
+ * pipe
56
+ *****************************************
57
+ */
58
+ export async function pipe(src, dest, options) {
59
+ return new Promise((resolve, reject) => {
60
+ src.once('close', resolve);
61
+ src.once('error', reject);
62
+ src.pipe(dest, options);
63
+ });
64
+ }
65
+ /**
66
+ *****************************************
67
+ * 读取文件
68
+ *****************************************
69
+ */
70
+ export async function readFile(path) {
71
+ const stats = await stat(path);
72
+ if (stats && !stats.isDirectory()) {
73
+ return fs.readFile(path, 'utf8');
74
+ }
75
+ }
76
+ /**
77
+ *****************************************
78
+ * 写入文件
79
+ *****************************************
80
+ */
81
+ export async function writeFile(path, content, options) {
82
+ const stats = await stat(path);
83
+ if (stats) {
84
+ if (!options || !options.force) {
85
+ return false;
86
+ }
87
+ else {
88
+ await rm(path);
89
+ }
90
+ }
91
+ // 写入文件内容
92
+ await fs.mkdir(dirname(path), { recursive: true });
93
+ await fs.writeFile(path, content);
94
+ // 返回结果
95
+ return true;
96
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2025-05-26 22:30:23
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { Dict } from './dict.mjs';
14
+ import { cache } from './cache.mjs';
15
+ import { resolveDirect } from './resolveDirect.mjs';
16
+ /**
17
+ *****************************************
18
+ * 缓存
19
+ *****************************************
20
+ */
21
+ const cached = cache(new WeakMap());
22
+ /**
23
+ *****************************************
24
+ * 解析别名
25
+ *****************************************
26
+ */
27
+ export function resolveAlias(alias) {
28
+ return cached.get(alias, resolveTarget);
29
+ }
30
+ /**
31
+ *****************************************
32
+ * 解析别名
33
+ *****************************************
34
+ */
35
+ function resolveTarget(alias) {
36
+ return resolveDict(alias, resolvePath);
37
+ }
38
+ /**
39
+ *****************************************
40
+ * 解析匹配路径
41
+ *****************************************
42
+ */
43
+ function resolvePath(key, value) {
44
+ const { test, resolve } = resolveDirect(key);
45
+ const rule = resolve(value);
46
+ // 返回匹配函数
47
+ return function match(id, handler) {
48
+ if (test(id)) {
49
+ return handler(rule(id));
50
+ }
51
+ };
52
+ }
53
+ /**
54
+ *****************************************
55
+ * 解析字典
56
+ *****************************************
57
+ */
58
+ export function resolveDict(data, handler) {
59
+ const result = new Dict();
60
+ // 生成元素
61
+ Object.keys(data)
62
+ .forEach(key => result.set(key, handler(key, data[key])));
63
+ // 排序列表
64
+ result.sort((a, b) => {
65
+ const idxA = a.indexOf('*');
66
+ const idxB = b.indexOf('*');
67
+ const baseA = idxA === -1 ? a.length : idxA;
68
+ const baseB = idxB === -1 ? b.length : idxB;
69
+ // 比较基准长度
70
+ if (baseA !== baseB) {
71
+ return baseB - baseA;
72
+ }
73
+ else {
74
+ return idxA === -1 ? -1 : idxB === -1 ? 1 : b.length - a.length;
75
+ }
76
+ });
77
+ // 返回结果
78
+ return result;
79
+ }