@ainc/fs 0.1.22 → 0.1.23

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 (56) 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/downloadFile.js +19 -13
  6. package/dist/index.d.ts +37 -1
  7. package/dist/index.exports.json +34 -0
  8. package/dist/index.js +59 -3
  9. package/dist/isEsmModule.d.ts +18 -0
  10. package/dist/isEsmModule.js +63 -0
  11. package/dist/loadPackageDescription.d.ts +61 -0
  12. package/dist/loadPackageDescription.js +71 -0
  13. package/dist/loadTsConfig.d.ts +87 -0
  14. package/dist/loadTsConfig.js +219 -0
  15. package/dist/match.d.ts +30 -0
  16. package/dist/match.js +59 -0
  17. package/dist/resolveAlias.d.ts +25 -0
  18. package/dist/resolveAlias.js +82 -0
  19. package/dist/resolveDirect.d.ts +15 -0
  20. package/dist/resolveDirect.js +144 -0
  21. package/dist/resolveExports.d.ts +19 -0
  22. package/dist/resolveExports.js +54 -0
  23. package/dist/resolveImports.d.ts +21 -0
  24. package/dist/resolveImports.js +114 -0
  25. package/dist/resolveModuleDir.d.ts +12 -0
  26. package/dist/resolveModuleDir.js +67 -0
  27. package/dist/resolveModuleId.d.ts +6 -0
  28. package/dist/resolveModuleId.js +32 -0
  29. package/dist/resolvePath.d.ts +23 -0
  30. package/dist/resolvePath.js +86 -0
  31. package/dist/resolvePaths.d.ts +13 -0
  32. package/dist/resolvePaths.js +42 -0
  33. package/dist/split.d.ts +6 -0
  34. package/dist/split.js +24 -0
  35. package/dist/sys.d.ts +60 -0
  36. package/dist/sys.js +260 -0
  37. package/esm/cache.mjs +22 -0
  38. package/esm/dict.mjs +63 -0
  39. package/esm/downloadFile.mjs +19 -13
  40. package/esm/index.exports.json +34 -0
  41. package/esm/index.mjs +29 -1
  42. package/esm/isEsmModule.mjs +59 -0
  43. package/esm/loadPackageDescription.mjs +67 -0
  44. package/esm/loadTsConfig.mjs +215 -0
  45. package/esm/match.mjs +53 -0
  46. package/esm/resolveAlias.mjs +79 -0
  47. package/esm/resolveDirect.mjs +142 -0
  48. package/esm/resolveExports.mjs +51 -0
  49. package/esm/resolveImports.mjs +112 -0
  50. package/esm/resolveModuleDir.mjs +64 -0
  51. package/esm/resolveModuleId.mjs +30 -0
  52. package/esm/resolvePath.mjs +84 -0
  53. package/esm/resolvePaths.mjs +40 -0
  54. package/esm/split.mjs +22 -0
  55. package/esm/sys.mjs +258 -0
  56. package/package.json +3 -2
@@ -0,0 +1,64 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2025-05-29 20:26:27
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { resolve, join } from 'node:path';
14
+ import { dirname } from './dirname.mjs';
15
+ import { isDir } from './stat.mjs';
16
+ import { match } from './match.mjs';
17
+ /**
18
+ *****************************************
19
+ * 模块路径缓存
20
+ *****************************************
21
+ */
22
+ const cacheModuleDirs = new Map();
23
+ const cacheModuleDir = new Map();
24
+ /**
25
+ *****************************************
26
+ * 解析模块目录
27
+ *****************************************
28
+ */
29
+ export function resolveModuleDir(id, from) {
30
+ const cacheId = `${from}:${id}`;
31
+ if (cacheModuleDir.has(cacheId)) {
32
+ return cacheModuleDir.get(cacheId);
33
+ }
34
+ // 解析目录
35
+ const dirs = resolveModuleDirs(from);
36
+ const result = match(dirs, dir => isDir(resolve(dir, id)));
37
+ // 缓存结果
38
+ cacheModuleDir.set(cacheId, result);
39
+ // 返回结果
40
+ return result;
41
+ }
42
+ /**
43
+ *****************************************
44
+ * 解析模块目录列表
45
+ *****************************************
46
+ */
47
+ export function resolveModuleDirs(from) {
48
+ if (!from) {
49
+ return [];
50
+ }
51
+ // 存在缓存时,直接返回
52
+ const cached = cacheModuleDirs.get(from);
53
+ if (cached) {
54
+ return cached;
55
+ }
56
+ // 解析目录
57
+ const dirs = resolveModuleDirs(dirname(from));
58
+ const dir = join(from, 'node_modules');
59
+ const result = isDir(dir) ? [dir, ...dirs] : dirs;
60
+ // 缓存结果
61
+ cacheModuleDirs.set(from, result);
62
+ // 返回结果
63
+ return result;
64
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2025-05-29 20:26:27
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 解析模块路径
11
+ *****************************************
12
+ */
13
+ export function resolveModuleId(id) {
14
+ const idx1 = id.indexOf('/');
15
+ // 处理不带域的模块路径
16
+ if (idx1 === -1) {
17
+ return [id, '.'];
18
+ }
19
+ else if (id.charAt(0) !== '@') {
20
+ return [id.slice(0, idx1), '.' + id.slice(idx1)];
21
+ }
22
+ // 分割模块路径
23
+ const idx2 = id.indexOf('/', idx1 + 1);
24
+ if (idx2 === -1) {
25
+ return [id, '.'];
26
+ }
27
+ else {
28
+ return [id.slice(0, idx2), '.' + id.slice(idx2)];
29
+ }
30
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2026-03-18 20:06:20
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { dirname, resolve } from 'node:path';
14
+ import { loadCompilerOptions } from './loadTsConfig.mjs';
15
+ import { sys } from './sys.mjs';
16
+ import { isEsmFile, isEsmPackage } from './isEsmModule.mjs';
17
+ /**
18
+ *****************************************
19
+ * 创建文件系统
20
+ *****************************************
21
+ */
22
+ function createFileSystem(options) {
23
+ return {
24
+ ...sys,
25
+ ...options,
26
+ cache: options.cache || sys.cache,
27
+ cwd: options.cwd || sys.cwd,
28
+ mainFields: options.mainFields || sys.mainFields,
29
+ conditions: options.conditions || sys.conditions,
30
+ extensions: options.extensions || sys.extensions,
31
+ };
32
+ }
33
+ /**
34
+ *****************************************
35
+ * 判断是否为 ESM 模块
36
+ *****************************************
37
+ */
38
+ function isEsmModule(dir, filename) {
39
+ if (filename) {
40
+ const result = isEsmFile(filename);
41
+ if (result !== undefined) {
42
+ return result;
43
+ }
44
+ }
45
+ // 判断为 ESM 模块
46
+ if (isEsmPackage(dir)) {
47
+ return true;
48
+ }
49
+ // 判断 TS 配置
50
+ const { module } = loadCompilerOptions(dir) || {};
51
+ if (module && module.toLowerCase().startsWith('es')) {
52
+ return true;
53
+ }
54
+ else {
55
+ return false;
56
+ }
57
+ }
58
+ /**
59
+ *****************************************
60
+ * 解析路径
61
+ *****************************************
62
+ */
63
+ export function resolvePath(id, issuer, options) {
64
+ const from = issuer ? dirname(resolve(issuer)) : process.cwd();
65
+ const opts = options || {};
66
+ const sys = createFileSystem(opts);
67
+ // 设置模块路径映射
68
+ if (!opts.paths && !opts.baseUrl) {
69
+ const { baseUrl, paths } = loadCompilerOptions(from) || {};
70
+ sys.baseUrl = baseUrl;
71
+ sys.paths = paths;
72
+ }
73
+ else {
74
+ sys.baseUrl = opts.baseUrl && resolve(opts.baseUrl);
75
+ }
76
+ // 设置加载条件
77
+ if (!opts.conditions) {
78
+ sys.conditions = isEsmModule(from, issuer) ? ['import', 'node'] : ['require', 'node'];
79
+ }
80
+ // 生成缓存 ID
81
+ sys.cacheSalt = sys.conditions.join(',');
82
+ // 执行解析
83
+ return sys.resolve(id, from);
84
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2025-05-26 22:30:23
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ import { match } from './match.mjs';
9
+ import { cache } from './cache.mjs';
10
+ import { resolveDict } from './resolveAlias.mjs';
11
+ import { resolveDirect } from './resolveDirect.mjs';
12
+ /**
13
+ *****************************************
14
+ * 缓存
15
+ *****************************************
16
+ */
17
+ const cached = cache(new WeakMap());
18
+ /**
19
+ *****************************************
20
+ * 解析别名
21
+ *****************************************
22
+ */
23
+ export function resolvePaths(paths) {
24
+ return cached.get(paths, () => resolveDict(paths, resolvePath));
25
+ }
26
+ /**
27
+ *****************************************
28
+ * 解析匹配规则
29
+ *****************************************
30
+ */
31
+ function resolvePath(key, paths) {
32
+ const { test, resolve } = resolveDirect(key);
33
+ const rules = paths.map(resolve);
34
+ // 返回解析函数
35
+ return function resolve(id, handler) {
36
+ if (test(id)) {
37
+ return match(rules, direct => handler(direct(id)));
38
+ }
39
+ };
40
+ }
package/esm/split.mjs ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2025-05-24 23:56:16
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 分割字符串
11
+ *****************************************
12
+ */
13
+ export function split(str, sep) {
14
+ const idx = str.indexOf(sep);
15
+ // 执行切割
16
+ if (idx === -1) {
17
+ return [str, undefined];
18
+ }
19
+ else {
20
+ return [str.slice(0, idx), str.slice(idx + sep.length)];
21
+ }
22
+ }
package/esm/sys.mjs ADDED
@@ -0,0 +1,258 @@
1
+ /**
2
+ *****************************************
3
+ * Created by edonet@163.com
4
+ * Created on 2025-06-29 16:06:27
5
+ *****************************************
6
+ */
7
+ 'use strict';
8
+ /**
9
+ *****************************************
10
+ * 加载依赖
11
+ *****************************************
12
+ */
13
+ import { fileURLToPath } from 'node:url';
14
+ import { resolve, isAbsolute, sep } from 'node:path';
15
+ import { builtinModules } from 'node:module';
16
+ import { isRelative } from './relative.mjs';
17
+ import { stat } from './stat.mjs';
18
+ import { resolvePackageDescription } from './loadPackageDescription.mjs';
19
+ import { resolveModuleId } from './resolveModuleId.mjs';
20
+ import { resolveModuleDir } from './resolveModuleDir.mjs';
21
+ import { resolveAlias } from './resolveAlias.mjs';
22
+ import { resolvePaths } from './resolvePaths.mjs';
23
+ import { resolveImports } from './resolveImports.mjs';
24
+ import { resolveExports } from './resolveExports.mjs';
25
+ /**
26
+ *****************************************
27
+ * 全局缓存
28
+ *****************************************
29
+ */
30
+ const cache = new Map();
31
+ /**
32
+ *****************************************
33
+ * 文件系统
34
+ *****************************************
35
+ */
36
+ export const sys = {
37
+ /** 解析基准路径 */
38
+ baseUrl: undefined,
39
+ /** 别名配置 */
40
+ alias: undefined,
41
+ /** 路径配置 */
42
+ paths: undefined,
43
+ /** 缓存 ID */
44
+ cacheSalt: '',
45
+ /** 缓存 */
46
+ cache,
47
+ /** 当前目录 */
48
+ cwd: process.cwd(),
49
+ /** 是否解析模块 */
50
+ module: true,
51
+ /** 是否解析模块导出 */
52
+ moduleExports: true,
53
+ /** 解析 main 字段 */
54
+ mainFields: ['main'],
55
+ /** 解析条件 */
56
+ conditions: ['require', 'node'],
57
+ /** 解析扩展名 */
58
+ extensions: ['.ts', '.tsx', '.js', '.json', '.jsx', '.mjs', '.cjs', '.mts', '.cts', '.node', '.wasm'],
59
+ /** 解析路径 */
60
+ resolve(id, from) {
61
+ const cacheId = `${from}\x00${id}`;
62
+ const cacheSaltId = `${cacheId}\x00${this.cacheSalt}`;
63
+ // 存在缓存时,直接返回
64
+ if (this.cache.has(cacheId)) {
65
+ return this.cache.get(cacheId);
66
+ }
67
+ // 存在缓存时,直接返回
68
+ if (this.cache.has(cacheSaltId)) {
69
+ return this.cache.get(cacheSaltId);
70
+ }
71
+ // 添加缓存,避免循环解析
72
+ this.cache.set(cacheSaltId, null);
73
+ // 匹配规则
74
+ const rules = [
75
+ [cacheId, this.resolveBuiltin],
76
+ [cacheSaltId, this.resolveModuleImports],
77
+ [cacheId, this.resolveFile],
78
+ [cacheSaltId, this.resolveModule],
79
+ ];
80
+ // 解析规则
81
+ for (let i = 0, l = rules.length; i < l; i++) {
82
+ const [cacheId, handler] = rules[i];
83
+ const resolved = handler.call(this, id, from);
84
+ if (resolved !== undefined) {
85
+ this.cache.set(cacheId, resolved);
86
+ return resolved;
87
+ }
88
+ }
89
+ },
90
+ /** 解析内部模块 */
91
+ resolveBuiltin(id) {
92
+ if (builtinModules.includes(id)) {
93
+ return id;
94
+ }
95
+ // 处理内置模块
96
+ const prefix = id.slice(0, 5);
97
+ if (prefix === 'node:') {
98
+ return id;
99
+ }
100
+ // 处理 URL 路径
101
+ if (prefix === 'file:') {
102
+ return fileURLToPath(id);
103
+ }
104
+ // 处理资源路径
105
+ if (prefix === 'data:' || prefix === 'http:' || id.startsWith('https:')) {
106
+ return id;
107
+ }
108
+ },
109
+ /** 解析文件 */
110
+ resolveFile(id, from) {
111
+ // 解析相对路径
112
+ if (isRelative(id)) {
113
+ return this.resolveTarget(resolve(from, id));
114
+ }
115
+ // 解析绝对路径
116
+ if (isAbsolute(id)) {
117
+ return this.resolveTarget(id);
118
+ }
119
+ // 解析别名
120
+ if (this.alias) {
121
+ const alias = resolveAlias(this.alias);
122
+ const resolved = alias.match(resolve => resolve(id, alias => this.resolve(alias, this.cwd)));
123
+ if (resolved !== undefined) {
124
+ return resolved;
125
+ }
126
+ }
127
+ // 解析基准路径
128
+ if (this.baseUrl) {
129
+ const resolved = this.resolveTarget(resolve(this.baseUrl, id));
130
+ if (resolved !== undefined) {
131
+ return resolved;
132
+ }
133
+ }
134
+ // 解析路径映射
135
+ if (this.paths) {
136
+ const baseUrl = this.baseUrl || this.cwd;
137
+ const paths = resolvePaths(this.paths);
138
+ const resolved = paths.match(resolve => resolve(id, alias => this.resolve(alias, baseUrl)));
139
+ if (resolved !== undefined) {
140
+ return resolved;
141
+ }
142
+ }
143
+ },
144
+ /** 解析文件目标 */
145
+ resolveTarget(path) {
146
+ const stats = stat(path);
147
+ // 目标存在时,需要解析目标是目录的情况
148
+ if (stats) {
149
+ return stats.isDirectory() ? this.resolveDir(path) : path;
150
+ }
151
+ else {
152
+ return this.resolveExtensions(path);
153
+ }
154
+ },
155
+ /** 解析目录 */
156
+ resolveDir(path) {
157
+ const pkg = resolvePackageDescription(path);
158
+ // 解析主入口配置
159
+ if (pkg && pkg.dir === path && pkg.config) {
160
+ return this.resolveMainFile(path, pkg.config);
161
+ }
162
+ else {
163
+ return this.resolveIndex(path);
164
+ }
165
+ },
166
+ /** 解析 main 文件 */
167
+ resolveMainFile(path, pkg) {
168
+ for (let i = 0, l = this.mainFields.length; i < l; i++) {
169
+ const main = pkg[this.mainFields[i]];
170
+ // 存在主入口文件配置
171
+ if (main) {
172
+ return this.resolveTarget(resolve(path, main));
173
+ }
174
+ }
175
+ // 解析 index 文件
176
+ return this.resolveIndex(path);
177
+ },
178
+ /** 解析 index 文件 */
179
+ resolveIndex(path) {
180
+ return this.resolveExtensions(path + sep + 'index');
181
+ },
182
+ /** 解析扩展名 */
183
+ resolveExtensions(path) {
184
+ for (let i = 0, l = this.extensions.length; i < l; i++) {
185
+ const file = path + this.extensions[i];
186
+ const stats = stat(file);
187
+ if (stats && stats.isFile()) {
188
+ return file;
189
+ }
190
+ }
191
+ },
192
+ /** 解析包自身 */
193
+ resolveSelf(name, path, from) {
194
+ const pkg = resolvePackageDescription(from);
195
+ if (!pkg || !pkg.config) {
196
+ return;
197
+ }
198
+ // 获取配置
199
+ const { dir, config } = pkg;
200
+ // 解析模块导出
201
+ if (config.name === name) {
202
+ return this.resolveModuleExports(path, dir, config) || null;
203
+ }
204
+ },
205
+ /** 解析模块 */
206
+ resolveModule(id, from) {
207
+ const [name, subpath] = resolveModuleId(id);
208
+ const path = subpath === './' ? '.' : subpath;
209
+ // 解析当前包本身
210
+ const resolved = this.resolveSelf(name, path, from);
211
+ if (resolved !== undefined || this.module === false) {
212
+ return resolved;
213
+ }
214
+ // 解析模块目录
215
+ const dir = resolveModuleDir(name, from);
216
+ if (!dir) {
217
+ return;
218
+ }
219
+ // 读取包描述文件
220
+ const pkg = resolvePackageDescription(dir);
221
+ if (pkg && pkg.dir === dir && pkg.config) {
222
+ return this.resolveModuleExports(path, dir, pkg.config);
223
+ }
224
+ // 解析目标路径
225
+ if (path === '.') {
226
+ return this.resolveIndex(path);
227
+ }
228
+ else {
229
+ return this.resolveTarget(resolve(dir, path));
230
+ }
231
+ },
232
+ /** 解析模块导入 */
233
+ resolveModuleImports(id, from) {
234
+ const pkg = id.charAt(0) === '#' && resolvePackageDescription(from);
235
+ if (!pkg || !pkg.config || !pkg.config.imports) {
236
+ return;
237
+ }
238
+ // 执行配置
239
+ const imports = pkg.config.imports;
240
+ const dir = pkg.dir;
241
+ // 执行解析
242
+ return resolveImports(id, this.conditions, imports, path => this.resolve(path, dir));
243
+ },
244
+ /** 解析模块导出 */
245
+ resolveModuleExports(id, from, pkg) {
246
+ // 处理导出配置
247
+ if (pkg.exports && this.moduleExports) {
248
+ return resolveExports(id, this.conditions, pkg.exports, path => this.resolveTarget(resolve(from, path))) || null;
249
+ }
250
+ // 解析目标路径
251
+ if (id === '.') {
252
+ return this.resolveMainFile(from, pkg);
253
+ }
254
+ else {
255
+ return this.resolveTarget(resolve(from, id));
256
+ }
257
+ },
258
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainc/fs",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Let's do something nice with @ainc/esb!",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
@@ -43,11 +43,12 @@
43
43
  "jest": "^30.2.0"
44
44
  },
45
45
  "scripts": {
46
- "build": "pnpm clean && pnpm compile && pnpm esm",
46
+ "build": "pnpm clean && pnpm compile && pnpm esm && pnpm exports",
47
47
  "watch": "pnpm compile --watch",
48
48
  "esm": "pnpm compile -m es2022 --outDir ./esm --declaration false && node ../../scripts/esm.js",
49
49
  "compile": "tsc -p ./tsconfig.build.json",
50
50
  "download": "node ./bin/download.mjs ./build/node-service.exe https://unpkg.com/@ainc/node-service-win32/core/node-service.exe",
51
+ "exports": "node ../../scripts/exports.js",
51
52
  "test": "jest",
52
53
  "clean": "rimraf ./dist ./esm"
53
54
  }