autosnippet 1.1.18 → 1.1.19

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/bin/findPath.js CHANGED
@@ -16,6 +16,23 @@ const CACHE_TTL = 60000; // 缓存 60 秒
16
16
  */
17
17
  async function getDirectoryEntries(dirPath) {
18
18
  const cacheKey = path.resolve(dirPath);
19
+
20
+ // ✅ 首先检查路径是否是文件,如果是文件,立即返回 null(避免 ENOTDIR 错误)
21
+ // 注意:这个检查要在缓存检查之前,因为缓存可能包含错误的条目
22
+ try {
23
+ const stats = await fs.promises.stat(dirPath);
24
+ if (stats.isFile()) {
25
+ // 如果是文件,清除可能的错误缓存,然后返回 null
26
+ console.log(`[getDirectoryEntries] 路径是文件,返回 null: ${dirPath}`);
27
+ directoryCache.delete(cacheKey);
28
+ return null;
29
+ }
30
+ } catch (err) {
31
+ // 如果 stat 失败,可能是路径不存在或其他错误,继续处理
32
+ // 如果是 ENOTDIR,会在下面的 readdir 中被捕获
33
+ console.log(`[getDirectoryEntries] stat 失败: ${dirPath}, 错误: ${err.code || err.message}`);
34
+ }
35
+
19
36
  const cached = directoryCache.get(cacheKey);
20
37
 
21
38
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
@@ -23,6 +40,7 @@ async function getDirectoryEntries(dirPath) {
23
40
  }
24
41
 
25
42
  try {
43
+ console.log(`[getDirectoryEntries] 尝试读取目录: ${dirPath}`);
26
44
  const entries = await fs.promises.readdir(dirPath, {
27
45
  withFileTypes: true // 返回 Dirent 对象,减少 stat 调用
28
46
  });
@@ -44,8 +62,10 @@ async function getDirectoryEntries(dirPath) {
44
62
 
45
63
  return entries;
46
64
  } catch (err) {
47
- if (err.code === 'ENOENT' || err.code === 'EACCES') {
48
- return null; // 路径不存在或权限不足
65
+ // 处理各种文件系统错误
66
+ console.log(`[getDirectoryEntries] readdir 失败: ${dirPath}, 错误: ${err.code || err.message}`);
67
+ if (err.code === 'ENOENT' || err.code === 'EACCES' || err.code === 'ENOTDIR') {
68
+ return null; // 路径不存在、权限不足或不是目录
49
69
  }
50
70
  throw err;
51
71
  }
@@ -208,7 +228,7 @@ function findASSpecPath(filePath, callback, configPath, configDir) {
208
228
  }
209
229
  return;
210
230
  }
211
-
231
+
212
232
  fs.readdir(currentPath, function (err, files) {
213
233
  if (err) {
214
234
  // 错误处理:权限错误继续查找
@@ -220,7 +240,7 @@ function findASSpecPath(filePath, callback, configPath, configDir) {
220
240
  if (parentResolvedPath === path.resolve(currentPath)) {
221
241
  if (foundConfigPath) {
222
242
  callback(foundConfigPath);
223
- } else {
243
+ } else {
224
244
  console.log('未找到 AutoSnippet.boxspec.json 文件,请检查路径。');
225
245
  }
226
246
  return;
@@ -228,34 +248,34 @@ function findASSpecPath(filePath, callback, configPath, configDir) {
228
248
 
229
249
  search(parentPath, foundConfigPath, foundConfigDir, level + 1);
230
250
  } else {
231
- console.log(err);
251
+ console.log(err);
232
252
  }
233
- return;
234
- }
253
+ return;
254
+ }
235
255
 
236
256
  let isFound = false;
237
257
  let currentConfigPath = foundConfigPath;
238
258
  let currentConfigDir = foundConfigDir;
239
259
 
240
260
  // 查找 AutoSnippet.boxspec.json
241
- files.forEach(function (filename) {
242
- if (filename === HOLDER_NAME) {
261
+ files.forEach(function (filename) {
262
+ if (filename === HOLDER_NAME) {
243
263
  isFound = true;
244
264
  if (!currentConfigPath) {
245
265
  // 第一次找到配置文件,记录路径(不立即调用回调)
246
266
  currentConfigPath = path.join(currentPath, filename);
247
267
  currentConfigDir = path.resolve(currentPath);
248
- }
249
- }
250
- });
268
+ }
269
+ }
270
+ });
251
271
 
252
272
  // 如果已经找到配置文件,检查是否到达工程根目录
253
273
  if (currentConfigPath) {
254
274
  // 如果在配置文件所在目录或以上发现了工程根目录标记,停止查找并调用回调
255
275
  if (isProjectRootSync(currentPath, files)) {
256
276
  callback(currentConfigPath);
257
- return;
258
- }
277
+ return;
278
+ }
259
279
  }
260
280
 
261
281
  // 继续向上查找
@@ -270,8 +290,8 @@ function findASSpecPath(filePath, callback, configPath, configDir) {
270
290
  } else {
271
291
  console.log('未找到 AutoSnippet.boxspec.json 文件,请检查路径。');
272
292
  }
273
- return;
274
- }
293
+ return;
294
+ }
275
295
 
276
296
  search(parentPath, currentConfigPath, currentConfigDir, level + 1);
277
297
  });
@@ -412,29 +432,71 @@ async function findSubHeaderPath(filePath, headerName, moduleName) {
412
432
 
413
433
  // 向下查找AutoSnippet配置文件(优化:异步 I/O)
414
434
  async function findSubASSpecPath(filePath) {
435
+ console.log(`[findSubASSpecPath] 开始查找,传入路径: ${filePath}`);
415
436
  let resultArray = [];
416
437
 
417
438
  try {
418
- const entries = await getDirectoryEntries(filePath);
439
+ // 确保 filePath 是目录路径,而不是文件路径
440
+ // 如果传入的是文件路径,获取其所在目录
441
+ let dirPath = filePath;
442
+
443
+ // 首先检查路径是否存在,并确定是文件还是目录
444
+ try {
445
+ const stats = await fs.promises.stat(filePath);
446
+ if (stats.isFile()) {
447
+ // 如果是文件,使用其所在目录
448
+ dirPath = path.dirname(filePath);
449
+ console.log(`[findSubASSpecPath] 检测到文件路径,转换为目录: ${filePath} -> ${dirPath}`);
450
+ } else if (!stats.isDirectory()) {
451
+ // 既不是文件也不是目录,直接返回空数组
452
+ console.log(`[findSubASSpecPath] 路径既不是文件也不是目录,返回空数组: ${filePath}`);
453
+ return resultArray;
454
+ }
455
+ } catch (err) {
456
+ console.log(`[findSubASSpecPath] stat 失败: ${filePath}, 错误: ${err.code || err.message}`);
457
+ // 如果 stat 失败(路径不存在、权限错误等),尝试使用 dirname
458
+ if (err.code === 'ENOENT' || err.code === 'EACCES') {
459
+ // 如果路径看起来像文件路径(包含文件名),尝试使用 dirname
460
+ if (path.basename(filePath) === HOLDER_NAME || path.extname(filePath) !== '') {
461
+ dirPath = path.dirname(filePath);
462
+ console.log(`[findSubASSpecPath] 根据路径特征转换为目录: ${filePath} -> ${dirPath}`);
463
+ } else {
464
+ // 可能是目录路径,但不存在,直接返回空数组
465
+ console.log(`[findSubASSpecPath] 路径不存在,返回空数组: ${filePath}`);
466
+ return resultArray;
467
+ }
468
+ } else {
469
+ // 其他错误,直接返回空数组
470
+ console.log(`[findSubASSpecPath] stat 错误,返回空数组: ${filePath}, 错误: ${err.code || err.message}`);
471
+ return resultArray;
472
+ }
473
+ }
474
+
475
+ // ✅ 再次确认 dirPath 是目录(防止 ENOTDIR 错误)
476
+ console.log(`[findSubASSpecPath] 调用 getDirectoryEntries: ${dirPath}`);
477
+ const entries = await getDirectoryEntries(dirPath);
419
478
  if (!entries) {
420
479
  return resultArray;
421
480
  }
422
481
 
423
482
  for (const entry of entries) {
424
483
  if (entry.isFile() && entry.name === HOLDER_NAME) {
425
- resultArray.push(path.join(filePath, entry.name));
484
+ resultArray.push(path.join(dirPath, entry.name));
426
485
  } else if (entry.isDirectory()) {
427
486
  // 跳过 node_modules、.git 等目录
428
487
  if (entry.name.startsWith('.') || entry.name === 'node_modules') {
429
488
  continue;
430
489
  }
431
490
 
432
- const array = await findSubASSpecPath(path.join(filePath, entry.name));
491
+ const array = await findSubASSpecPath(path.join(dirPath, entry.name));
433
492
  resultArray = resultArray.concat(array);
434
493
  }
435
494
  }
436
495
  } catch (err) {
437
- console.log(err);
496
+ // ✅ 忽略 ENOTDIR 错误(传入的是文件路径)和其他文件系统错误
497
+ if (err.code !== 'ENOTDIR') {
498
+ console.log(err);
499
+ }
438
500
  }
439
501
 
440
502
  return resultArray;
@@ -442,11 +504,34 @@ async function findSubASSpecPath(filePath) {
442
504
 
443
505
  /**
444
506
  * 向上查找项目根目录(包含 .git、Package.swift 等的目录)
445
- * @param {string} filePath - 起始文件路径
507
+ * @param {string} filePath - 起始文件路径或目录路径
446
508
  * @returns {Promise<string|null>} 项目根目录路径,如果找不到返回 null
447
509
  */
448
510
  async function findProjectRoot(filePath) {
511
+ console.log(`[findProjectRoot] 开始查找,传入路径: ${filePath}`);
512
+ // ✅ 确保从目录路径开始查找,如果是文件路径,先转换为目录路径
449
513
  let currentPath = path.resolve(filePath);
514
+
515
+ // 检查路径是文件还是目录
516
+ try {
517
+ const stats = await fs.promises.stat(currentPath);
518
+ if (stats.isFile()) {
519
+ // 如果是文件,使用其所在目录
520
+ currentPath = path.dirname(currentPath);
521
+ console.log(`[findProjectRoot] 检测到文件路径,转换为目录: ${filePath} -> ${currentPath}`);
522
+ }
523
+ } catch (err) {
524
+ console.log(`[findProjectRoot] stat 失败: ${currentPath}, 错误: ${err.code || err.message}`);
525
+ // 如果 stat 失败,假设是目录路径,或者使用 dirname 作为后备
526
+ if (err.code === 'ENOENT' || err.code === 'EACCES') {
527
+ // 如果路径看起来像文件路径,使用 dirname
528
+ if (path.basename(filePath).includes('.') || path.extname(filePath) !== '') {
529
+ currentPath = path.dirname(currentPath);
530
+ }
531
+ }
532
+ // 其他错误继续处理,可能是目录路径
533
+ }
534
+
450
535
  const maxLevels = 20;
451
536
  let levelsChecked = 0;
452
537
 
@@ -464,7 +549,8 @@ async function findProjectRoot(filePath) {
464
549
  currentPath = parentPath;
465
550
  levelsChecked++;
466
551
  } catch (err) {
467
- if (err.code === 'ENOENT' || err.code === 'EACCES') {
552
+ // 处理各种文件系统错误,包括 ENOTDIR
553
+ if (err.code === 'ENOENT' || err.code === 'EACCES' || err.code === 'ENOTDIR') {
468
554
  const parentPath = path.dirname(currentPath);
469
555
  if (parentPath === currentPath) {
470
556
  break;
package/bin/init.js CHANGED
@@ -18,14 +18,19 @@ async function mergeSubSpecs(mainSpecFile) {
18
18
 
19
19
  // ✅ 从项目根目录开始查找,而不是从主配置文件所在目录
20
20
  // 找到项目根目录(包含 .git、Package.swift 等的目录)
21
+ console.log(`[mergeSubSpecs] 主配置文件路径: ${mainSpecFile}`);
21
22
  const projectRoot = await findPath.findProjectRoot(mainSpecFile);
22
23
  const searchRoot = projectRoot || path.dirname(mainSpecFile);
24
+ console.log(`[mergeSubSpecs] 项目根目录: ${projectRoot || 'null'}`);
25
+ console.log(`[mergeSubSpecs] 搜索根目录: ${searchRoot}`);
23
26
 
24
27
  const specSlashIndex = mainSpecFile.lastIndexOf('/');
25
28
  const specFilePath = mainSpecFile.substring(0, specSlashIndex + 1);
26
29
 
27
30
  // ✅ 从项目根目录向下查找子模块的 AutoSnippet.boxspec.json
31
+ console.log(`[mergeSubSpecs] 开始查找子模块配置,搜索根目录: ${searchRoot}`);
28
32
  const array = await findPath.findSubASSpecPath(searchRoot);
33
+ console.log(`[mergeSubSpecs] 找到 ${array.length} 个子模块配置文件`);
29
34
 
30
35
  for (let i = 0; i < array.length; i++) {
31
36
  const filename = array[i];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autosnippet",
3
- "version": "1.1.18",
3
+ "version": "1.1.19",
4
4
  "description": "A iOS module management tool.",
5
5
  "main": "index.js",
6
6
  "scripts": {