autosnippet 1.1.21 → 1.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.
package/bin/create.js CHANGED
@@ -61,8 +61,6 @@ async function findTargetRootDir(filePath) {
61
61
  // 检查当前目录是否包含 Code 或 Sources 目录
62
62
  for (const entry of entries) {
63
63
  if (entry.isDirectory() && (entry.name === 'Code' || entry.name === 'Sources')) {
64
- // 找到包含 Code 或 Sources 的目录,这就是 target 根目录
65
- console.log(`[findTargetRootDir] 找到 target 根目录: ${currentPath} (包含 ${entry.name})`);
66
64
  return currentPath;
67
65
  }
68
66
  }
@@ -82,7 +80,6 @@ async function findTargetRootDir(filePath) {
82
80
  }
83
81
  }
84
82
 
85
- console.log(`[findTargetRootDir] 未找到 target 根目录(Code 或 Sources)`);
86
83
  return null;
87
84
  }
88
85
 
@@ -324,7 +321,6 @@ function readStream(specFile, filePathArr, snippet, isHaveHeader) {
324
321
  // 如果找不到 target 根目录,使用 Package.swift 所在目录作为后备
325
322
  targetRootDir = packageInfo.path;
326
323
  }
327
- console.log(`[createCodeSnippets] target 根目录: ${targetRootDir}`);
328
324
  const moduleRoot = targetRootDir;
329
325
 
330
326
  // ✅ 查找头文件(适配 SPM 的 include/ModuleName/ 结构)
@@ -332,7 +328,7 @@ function readStream(specFile, filePathArr, snippet, isHaveHeader) {
332
328
  const headerPath = await findPath.findSubHeaderPath(targetRootDir, headerNameWithoutExt, moduleName);
333
329
 
334
330
  snippet['{content}'] = codeList;
335
- snippet['{specName}'] = moduleName; // ✅ specName 是 target 名称(如 BDNetworkAPI),不是包名(如 Business)
331
+ snippet['{specName}'] = moduleName;
336
332
 
337
333
  if (headerPath) {
338
334
  // ✅ headName 存储相对于 target 根目录的相对路径
@@ -447,7 +443,7 @@ async function saveFromFile(specFile, snippet) {
447
443
  if (err.code === 'ENOENT') {
448
444
  rootPlaceholder = { list: [] };
449
445
  } else {
450
- console.error(`[saveFromFile] 读取根配置文件失败: ${err.message}`);
446
+ // 忽略错误
451
447
  }
452
448
  }
453
449
 
@@ -475,11 +471,10 @@ async function saveFromFile(specFile, snippet) {
475
471
  // 写入根配置文件
476
472
  const rootContent = JSON.stringify(rootPlaceholder, null, 4);
477
473
  fs.writeFileSync(rootSpecFile, rootContent, 'utf8');
478
- console.log(`[saveFromFile] 已同步 snippet 到根目录配置文件: ${rootSpecFile}`);
479
474
  }
480
475
  }
481
476
  } catch (err) {
482
- console.error(`[saveFromFile] 同步到根配置文件失败: ${err.message}`);
477
+ // 忽略错误
483
478
  }
484
479
 
485
480
  // ✅ 只写入刚创建的单个代码片段
package/bin/findPath.js CHANGED
@@ -12,9 +12,6 @@ const README_NAME = 'readme.md';
12
12
  const directoryCache = new Map();
13
13
  const CACHE_TTL = 60000; // 缓存 60 秒
14
14
 
15
- /**
16
- * 获取目录内容(带缓存)
17
- */
18
15
  async function getDirectoryEntries(dirPath) {
19
16
  const cacheKey = path.resolve(dirPath);
20
17
 
@@ -23,15 +20,11 @@ async function getDirectoryEntries(dirPath) {
23
20
  try {
24
21
  const stats = await fs.promises.stat(dirPath);
25
22
  if (stats.isFile()) {
26
- // 如果是文件,清除可能的错误缓存,然后返回 null
27
- console.log(`[getDirectoryEntries] 路径是文件,返回 null: ${dirPath}`);
28
23
  directoryCache.delete(cacheKey);
29
24
  return null;
30
25
  }
31
26
  } catch (err) {
32
- // 如果 stat 失败,可能是路径不存在或其他错误,继续处理
33
- // 如果是 ENOTDIR,会在下面的 readdir 中被捕获
34
- console.log(`[getDirectoryEntries] stat 失败: ${dirPath}, 错误: ${err.code || err.message}`);
27
+ // 继续
35
28
  }
36
29
 
37
30
  const cached = directoryCache.get(cacheKey);
@@ -41,12 +34,10 @@ async function getDirectoryEntries(dirPath) {
41
34
  }
42
35
 
43
36
  try {
44
- console.log(`[getDirectoryEntries] 尝试读取目录: ${dirPath}`);
45
37
  const entries = await fs.promises.readdir(dirPath, {
46
- withFileTypes: true // 返回 Dirent 对象,减少 stat 调用
38
+ withFileTypes: true
47
39
  });
48
40
 
49
- // 清理过期缓存(保持缓存大小合理)
50
41
  if (directoryCache.size > 1000) {
51
42
  const now = Date.now();
52
43
  for (const [key, value] of directoryCache.entries()) {
@@ -63,19 +54,13 @@ async function getDirectoryEntries(dirPath) {
63
54
 
64
55
  return entries;
65
56
  } catch (err) {
66
- // ✅ 处理各种文件系统错误
67
- console.log(`[getDirectoryEntries] readdir 失败: ${dirPath}, 错误: ${err.code || err.message}`);
68
57
  if (err.code === 'ENOENT' || err.code === 'EACCES' || err.code === 'ENOTDIR') {
69
- return null; // 路径不存在、权限不足或不是目录
58
+ return null;
70
59
  }
71
60
  throw err;
72
61
  }
73
62
  }
74
63
 
75
- /**
76
- * 检测是否为工程根目录
77
- * 通过查找常见的工程根目录标记来判断
78
- */
79
64
  function isProjectRoot(dirPath, entries) {
80
65
  if (!entries) {
81
66
  return false;
@@ -83,24 +68,17 @@ function isProjectRoot(dirPath, entries) {
83
68
 
84
69
  // 工程根目录标记(按优先级)
85
70
  const rootMarkers = [
86
- '.git', // Git 仓库根目录
87
- PACKAGE_SWIFT, // SPM 项目根目录
88
- '.xcodeproj', // Xcode 项目根目录
89
- '.xcworkspace', // Xcode 工作空间根目录
90
- 'Podfile', // CocoaPods 项目根目录
91
- '.swiftpm', // Swift Package Manager 元数据目录
71
+ '.git',
72
+ PACKAGE_SWIFT,
73
+ '.xcodeproj',
74
+ '.xcworkspace',
75
+ 'Podfile',
76
+ '.swiftpm',
92
77
  ];
93
78
 
94
79
  for (const entry of entries) {
95
80
  const name = entry.name;
96
-
97
- // 检查文件标记
98
- if (entry.isFile() && rootMarkers.includes(name)) {
99
- return true;
100
- }
101
-
102
- // 检查目录标记(.git 可能是目录)
103
- if (entry.isDirectory() && rootMarkers.includes(name)) {
81
+ if (rootMarkers.includes(name) && (entry.isFile() || entry.isDirectory())) {
104
82
  return true;
105
83
  }
106
84
  }
@@ -108,55 +86,29 @@ function isProjectRoot(dirPath, entries) {
108
86
  return false;
109
87
  }
110
88
 
111
- // 向上查找AutoSnippet配置文件(优化:找到配置文件后,继续向上查找直到找到工程根目录)
112
- async function findASSpecPathAsync(filePath) {
113
- let configPath = null;
114
- let configDir = null;
89
+ async function searchUpwardForFile(filePath, fileName) {
115
90
  let currentPath = path.resolve(filePath);
116
- const maxLevels = 20; // 安全限制:最多向上查找 20 层
91
+ const maxLevels = 20;
117
92
  let levelsChecked = 0;
118
93
 
119
94
  while (currentPath && levelsChecked < maxLevels) {
120
95
  try {
121
96
  const entries = await getDirectoryEntries(currentPath);
122
-
123
- // 查找 AutoSnippet.boxspec.json
124
97
  if (entries) {
125
98
  for (const entry of entries) {
126
- if (entry.isFile() && entry.name === HOLDER_NAME) {
127
- if (!configPath) {
128
- // 第一次找到配置文件
129
- configPath = path.join(currentPath, entry.name);
130
- configDir = currentPath;
131
- }
99
+ if (entry.isFile() && entry.name === fileName) {
100
+ return path.join(currentPath, entry.name);
132
101
  }
133
102
  }
134
103
  }
135
104
 
136
- // 如果已经找到配置文件,检查是否到达工程根目录
137
- if (configPath) {
138
- // 如果在配置文件所在目录或以上发现了工程根目录标记,停止查找
139
- if (isProjectRoot(currentPath, entries)) {
140
- return configPath;
141
- }
142
-
143
- // 如果已经向上查找了,但没有找到工程根目录标记,继续查找
144
- if (path.resolve(currentPath) !== configDir) {
145
- // 当前目录不是配置文件所在目录,继续向上查找
146
- }
147
- }
148
-
149
- // 继续向上查找
150
105
  const parentPath = path.dirname(currentPath);
151
106
  if (parentPath === currentPath) {
152
- // 已到达根目录
153
107
  break;
154
108
  }
155
109
  currentPath = parentPath;
156
110
  levelsChecked++;
157
-
158
111
  } catch (err) {
159
- // 错误处理:权限错误继续查找
160
112
  if (err.code === 'ENOENT' || err.code === 'EACCES') {
161
113
  const parentPath = path.dirname(currentPath);
162
114
  if (parentPath === currentPath) {
@@ -166,18 +118,22 @@ async function findASSpecPathAsync(filePath) {
166
118
  levelsChecked++;
167
119
  continue;
168
120
  }
169
- // 其他错误,抛出
170
121
  throw err;
171
122
  }
172
123
  }
173
124
 
174
- // 如果找到配置文件,返回它(即使没有找到明确的工程根目录)
175
- return configPath || null;
125
+ return null;
126
+ }
127
+
128
+ async function findASSpecPathAsync(filePath) {
129
+ const holderPath = await searchUpwardForFile(filePath, HOLDER_NAME);
130
+ if (holderPath) {
131
+ return holderPath;
132
+ }
133
+
134
+ return await searchUpwardForFile(filePath, ROOT_MARKER_NAME);
176
135
  }
177
136
 
178
- /**
179
- * 同步版本:检测是否为工程根目录
180
- */
181
137
  function isProjectRootSync(dirPath, files) {
182
138
  if (!files || files.length === 0) {
183
139
  return false;
@@ -185,17 +141,15 @@ function isProjectRootSync(dirPath, files) {
185
141
 
186
142
  // 工程根目录标记(按优先级)
187
143
  const rootMarkers = [
188
- '.git', // Git 仓库根目录
189
- PACKAGE_SWIFT, // SPM 项目根目录
190
- '.xcodeproj', // Xcode 项目根目录
191
- '.xcworkspace', // Xcode 工作空间根目录
192
- 'Podfile', // CocoaPods 项目根目录
144
+ '.git',
145
+ PACKAGE_SWIFT,
146
+ '.xcodeproj',
147
+ '.xcworkspace',
148
+ 'Podfile',
193
149
  ];
194
150
 
195
- // 检查文件名
196
151
  for (const filename of files) {
197
152
  if (rootMarkers.includes(filename)) {
198
- // 检查是否为文件或目录
199
153
  try {
200
154
  const filePath = path.join(dirPath, filename);
201
155
  const stats = fs.lstatSync(filePath);
@@ -203,7 +157,7 @@ function isProjectRootSync(dirPath, files) {
203
157
  return true;
204
158
  }
205
159
  } catch (err) {
206
- // 忽略错误,继续检查
160
+ // 继续检查
207
161
  }
208
162
  }
209
163
  }
@@ -211,45 +165,35 @@ function isProjectRootSync(dirPath, files) {
211
165
  return false;
212
166
  }
213
167
 
214
- // 向上查找AutoSnippet配置文件(保留回调版本,兼容现有代码)
215
168
  function findASSpecPath(filePath, callback, configPath, configDir) {
216
- // 初始化参数
217
169
  if (configPath === undefined) configPath = null;
218
170
  if (configDir === undefined) configDir = null;
219
171
 
220
- const maxLevels = 20; // 安全限制:最多向上查找 20 层
172
+ const maxLevels = 20;
221
173
  let levelsChecked = 0;
222
174
 
223
175
  function search(currentPath, foundConfigPath, foundConfigDir, level) {
224
176
  if (level >= maxLevels) {
225
177
  if (foundConfigPath) {
226
178
  callback(foundConfigPath);
227
- } else {
228
- console.log('未找到 AutoSnippet.boxspec.json 文件,请检查路径。');
229
179
  }
230
180
  return;
231
181
  }
232
182
 
233
183
  fs.readdir(currentPath, function (err, files) {
234
184
  if (err) {
235
- // 错误处理:权限错误继续查找
236
185
  if (err.code === 'ENOENT' || err.code === 'EACCES') {
237
186
  const parentPath = path.join(currentPath, '/..');
238
187
  const parentResolvedPath = path.resolve(parentPath);
239
188
 
240
- // 如果已经到达根目录,停止查找
241
189
  if (parentResolvedPath === path.resolve(currentPath)) {
242
190
  if (foundConfigPath) {
243
191
  callback(foundConfigPath);
244
- } else {
245
- console.log('未找到 AutoSnippet.boxspec.json 文件,请检查路径。');
246
192
  }
247
193
  return;
248
194
  }
249
195
 
250
196
  search(parentPath, foundConfigPath, foundConfigDir, level + 1);
251
- } else {
252
- console.log(err);
253
197
  }
254
198
  return;
255
199
  }
@@ -258,41 +202,32 @@ function findASSpecPath(filePath, callback, configPath, configDir) {
258
202
  let currentConfigPath = foundConfigPath;
259
203
  let currentConfigDir = foundConfigDir;
260
204
 
261
- // 查找 AutoSnippet.boxspec.json
262
- files.forEach(function (filename) {
263
- if (filename === HOLDER_NAME) {
205
+ files.forEach(function (filename) {
206
+ if (filename === HOLDER_NAME) {
264
207
  isFound = true;
265
208
  if (!currentConfigPath) {
266
- // 第一次找到配置文件,记录路径(不立即调用回调)
267
209
  currentConfigPath = path.join(currentPath, filename);
268
210
  currentConfigDir = path.resolve(currentPath);
269
- }
270
- }
271
- });
211
+ }
212
+ }
213
+ });
272
214
 
273
- // 如果已经找到配置文件,检查是否到达工程根目录
274
215
  if (currentConfigPath) {
275
- // 如果在配置文件所在目录或以上发现了工程根目录标记,停止查找并调用回调
276
216
  if (isProjectRootSync(currentPath, files)) {
277
217
  callback(currentConfigPath);
278
- return;
279
- }
218
+ return;
219
+ }
280
220
  }
281
221
 
282
- // 继续向上查找
283
222
  const parentPath = path.join(currentPath, '/..');
284
223
  const parentResolvedPath = path.resolve(parentPath);
285
224
 
286
- // 如果已经到达根目录,停止查找
287
225
  if (parentResolvedPath === path.resolve(currentPath)) {
288
- // 如果找到了配置文件,即使没找到工程根目录标记,也调用回调
289
226
  if (currentConfigPath) {
290
227
  callback(currentConfigPath);
291
- } else {
292
- console.log('未找到 AutoSnippet.boxspec.json 文件,请检查路径。');
293
228
  }
294
- return;
295
- }
229
+ return;
230
+ }
296
231
 
297
232
  search(parentPath, currentConfigPath, currentConfigDir, level + 1);
298
233
  });
@@ -301,7 +236,6 @@ function findASSpecPath(filePath, callback, configPath, configDir) {
301
236
  search(filePath, configPath, configDir, 0);
302
237
  }
303
238
 
304
- // 向上查找 Package.swift 文件(SPM 模块规范文件)
305
239
  async function findPackageSwiftPath(filePath) {
306
240
  let currentPath = path.resolve(filePath);
307
241
 
@@ -317,14 +251,12 @@ async function findPackageSwiftPath(filePath) {
317
251
  continue;
318
252
  }
319
253
 
320
- // 查找 Package.swift 文件
321
254
  for (const entry of entries) {
322
255
  if (entry.isFile() && entry.name === PACKAGE_SWIFT) {
323
256
  return path.join(currentPath, entry.name);
324
257
  }
325
258
  }
326
259
 
327
- // 继续向上查找
328
260
  const parentPath = path.dirname(currentPath);
329
261
  if (parentPath === currentPath) {
330
262
  break;
@@ -347,14 +279,9 @@ async function findPackageSwiftPath(filePath) {
347
279
  return null;
348
280
  }
349
281
 
350
- /**
351
- * 解析 Package.swift 文件,提取模块信息
352
- */
353
282
  async function parsePackageSwift(packagePath) {
354
283
  try {
355
284
  const content = await fs.promises.readFile(packagePath, 'utf8');
356
-
357
- // 简单解析 Package.swift(实际可以使用 Swift AST 解析器)
358
285
  const packageNameMatch = content.match(/name:\s*"([^"]+)"/);
359
286
  const targetsMatch = content.match(/\.target\s*\([^)]+name:\s*"([^"]+)"/g);
360
287
 
@@ -376,14 +303,24 @@ async function parsePackageSwift(packagePath) {
376
303
  path: path.dirname(packagePath)
377
304
  };
378
305
  } catch (err) {
379
- console.error('Error parsing Package.swift:', err);
380
306
  return null;
381
307
  }
382
308
  }
383
309
 
384
- // 向下查找模块头文件(优化:适配 SPM 结构,优先查找 include/ModuleName/ 目录)
385
310
  async function findSubHeaderPath(filePath, headerName, moduleName) {
386
- // 优先查找 include/ModuleName/ 目录(SPM 结构)
311
+ const codePath = path.join(filePath, 'Code');
312
+ try {
313
+ const stats = await fs.promises.stat(codePath);
314
+ if (stats.isDirectory()) {
315
+ const result = await findSubHeaderPath(codePath, headerName, null);
316
+ if (result) {
317
+ return result;
318
+ }
319
+ }
320
+ } catch {
321
+ // 继续查找
322
+ }
323
+
387
324
  if (moduleName) {
388
325
  const includePath = path.join(filePath, 'include', moduleName);
389
326
  try {
@@ -394,15 +331,14 @@ async function findSubHeaderPath(filePath, headerName, moduleName) {
394
331
  await fs.promises.access(headerPath);
395
332
  return headerPath;
396
333
  } catch {
397
- // 头文件不存在,继续查找
334
+ // 继续查找
398
335
  }
399
336
  }
400
337
  } catch {
401
- // include 目录不存在,继续查找
338
+ // 继续查找
402
339
  }
403
340
  }
404
341
 
405
- // ✅ 降级:在整个模块目录中查找(深度限制)
406
342
  try {
407
343
  const entries = await getDirectoryEntries(filePath);
408
344
  if (!entries) {
@@ -413,7 +349,6 @@ async function findSubHeaderPath(filePath, headerName, moduleName) {
413
349
  if (entry.isFile() && entry.name === `${headerName}.h`) {
414
350
  return path.join(filePath, entry.name);
415
351
  } else if (entry.isDirectory()) {
416
- // 跳过 node_modules、.git 等目录
417
352
  if (entry.name.startsWith('.') || entry.name === 'node_modules') {
418
353
  continue;
419
354
  }
@@ -425,56 +360,36 @@ async function findSubHeaderPath(filePath, headerName, moduleName) {
425
360
  }
426
361
  }
427
362
  } catch (err) {
428
- console.error(err);
363
+ // 忽略错误
429
364
  }
430
365
 
431
366
  return null;
432
367
  }
433
368
 
434
- // 向下查找AutoSnippet配置文件(优化:异步 I/O)
435
369
  async function findSubASSpecPath(filePath) {
436
- console.log(`[findSubASSpecPath] 开始查找,传入路径: ${filePath}`);
437
370
  let resultArray = [];
438
371
 
439
372
  try {
440
- // ✅ 确保 filePath 是目录路径,而不是文件路径
441
- // 如果传入的是文件路径,获取其所在目录
442
373
  let dirPath = filePath;
443
374
 
444
- // 首先检查路径是否存在,并确定是文件还是目录
445
375
  try {
446
376
  const stats = await fs.promises.stat(filePath);
447
377
  if (stats.isFile()) {
448
- // 如果是文件,使用其所在目录
449
378
  dirPath = path.dirname(filePath);
450
- console.log(`[findSubASSpecPath] 检测到文件路径,转换为目录: ${filePath} -> ${dirPath}`);
451
379
  } else if (!stats.isDirectory()) {
452
- // 既不是文件也不是目录,直接返回空数组
453
- console.log(`[findSubASSpecPath] 路径既不是文件也不是目录,返回空数组: ${filePath}`);
454
380
  return resultArray;
455
381
  }
456
382
  } catch (err) {
457
- console.log(`[findSubASSpecPath] stat 失败: ${filePath}, 错误: ${err.code || err.message}`);
458
- // 如果 stat 失败(路径不存在、权限错误等),尝试使用 dirname
459
383
  if (err.code === 'ENOENT' || err.code === 'EACCES') {
460
- // 如果路径看起来像文件路径(包含文件名),尝试使用 dirname
461
384
  if (path.basename(filePath) === HOLDER_NAME || path.extname(filePath) !== '') {
462
385
  dirPath = path.dirname(filePath);
463
- console.log(`[findSubASSpecPath] 根据路径特征转换为目录: ${filePath} -> ${dirPath}`);
464
386
  } else {
465
- // 可能是目录路径,但不存在,直接返回空数组
466
- console.log(`[findSubASSpecPath] 路径不存在,返回空数组: ${filePath}`);
467
387
  return resultArray;
468
388
  }
469
389
  } else {
470
- // 其他错误,直接返回空数组
471
- console.log(`[findSubASSpecPath] stat 错误,返回空数组: ${filePath}, 错误: ${err.code || err.message}`);
472
390
  return resultArray;
473
391
  }
474
392
  }
475
-
476
- // ✅ 再次确认 dirPath 是目录(防止 ENOTDIR 错误)
477
- console.log(`[findSubASSpecPath] 调用 getDirectoryEntries: ${dirPath}`);
478
393
  const entries = await getDirectoryEntries(dirPath);
479
394
  if (!entries) {
480
395
  return resultArray;
@@ -484,7 +399,6 @@ async function findSubASSpecPath(filePath) {
484
399
  if (entry.isFile() && entry.name === HOLDER_NAME) {
485
400
  resultArray.push(path.join(dirPath, entry.name));
486
401
  } else if (entry.isDirectory()) {
487
- // 跳过 node_modules、.git 等目录
488
402
  if (entry.name.startsWith('.') || entry.name === 'node_modules') {
489
403
  continue;
490
404
  }
@@ -494,187 +408,34 @@ async function findSubASSpecPath(filePath) {
494
408
  }
495
409
  }
496
410
  } catch (err) {
497
- // ✅ 忽略 ENOTDIR 错误(传入的是文件路径)和其他文件系统错误
498
411
  if (err.code !== 'ENOTDIR') {
499
- console.log(err);
412
+ // 忽略错误
500
413
  }
501
414
  }
502
415
 
503
416
  return resultArray;
504
417
  }
505
418
 
506
- /**
507
- * 向上查找项目根目录(查找 AutoSnippetRoot.boxspec.json 文件)
508
- * @param {string} filePath - 起始文件路径或目录路径
509
- * @returns {Promise<string|null>} 项目根目录路径(AutoSnippetRoot.boxspec.json 所在目录),如果找不到返回 null
510
- */
511
419
  async function findProjectRoot(filePath) {
512
- console.log(`[findProjectRoot] 开始查找,传入路径: ${filePath}`);
513
- // ✅ 简化逻辑:向上查找 AutoSnippetRoot.boxspec.json 文件
514
- let currentPath = path.resolve(filePath);
420
+ let startPath = path.resolve(filePath);
515
421
 
516
- // 检查路径是文件还是目录
517
422
  try {
518
- const stats = await fs.promises.stat(currentPath);
423
+ const stats = await fs.promises.stat(startPath);
519
424
  if (stats.isFile()) {
520
- // 如果是文件,使用其所在目录
521
- currentPath = path.dirname(currentPath);
522
- console.log(`[findProjectRoot] 检测到文件路径,转换为目录: ${filePath} -> ${currentPath}`);
425
+ startPath = path.dirname(startPath);
523
426
  }
524
427
  } catch (err) {
525
- console.log(`[findProjectRoot] stat 失败: ${currentPath}, 错误: ${err.code || err.message}`);
526
- // 如果 stat 失败,假设是目录路径,或者使用 dirname 作为后备
527
428
  if (err.code === 'ENOENT' || err.code === 'EACCES') {
528
- // 如果路径看起来像文件路径,使用 dirname
529
429
  if (path.basename(filePath).includes('.') || path.extname(filePath) !== '') {
530
- currentPath = path.dirname(currentPath);
430
+ startPath = path.dirname(startPath);
531
431
  }
532
432
  }
533
- // 其他错误继续处理,可能是目录路径
534
433
  }
535
434
 
536
- const maxLevels = 20;
537
- let levelsChecked = 0;
538
-
539
- while (currentPath && levelsChecked < maxLevels) {
540
- try {
541
- // ✅ 查找 AutoSnippetRoot.boxspec.json 文件
542
- const rootMarkerPath = path.join(currentPath, ROOT_MARKER_NAME);
543
- try {
544
- const stats = await fs.promises.stat(rootMarkerPath);
545
- if (stats.isFile()) {
546
- console.log(`[findProjectRoot] 找到根目录标记文件: ${rootMarkerPath}`);
547
- return currentPath;
548
- }
549
- } catch (err) {
550
- // 文件不存在,继续向上查找
551
- }
552
-
553
- const parentPath = path.dirname(currentPath);
554
- if (parentPath === currentPath) {
555
- break;
556
- }
557
- currentPath = parentPath;
558
- levelsChecked++;
559
- } catch (err) {
560
- // ✅ 处理各种文件系统错误
561
- if (err.code === 'ENOENT' || err.code === 'EACCES' || err.code === 'ENOTDIR') {
562
- const parentPath = path.dirname(currentPath);
563
- if (parentPath === currentPath) {
564
- break;
565
- }
566
- currentPath = parentPath;
567
- levelsChecked++;
568
- continue;
569
- }
570
- throw err;
571
- }
572
- }
573
-
574
- console.log(`[findProjectRoot] 未找到根目录标记文件 ${ROOT_MARKER_NAME}`);
575
- return null;
576
- }
577
-
578
- /**
579
- * 从项目根目录找到模块,并返回模块名和头文件名
580
- * @param {string} projectRoot - 项目根目录
581
- * @param {string} specName - 模块名(target 名称)
582
- * @param {string} headName - 头文件相对路径(相对于模块根目录)
583
- * @returns {Promise<{moduleName: string, headerFileName: string}|null>}
584
- */
585
- async function findModuleHeaderFromRoot(projectRoot, specName, headName) {
586
- if (!projectRoot || !specName || !headName) {
587
- return null;
588
- }
589
-
590
- // 从项目根目录向下查找包含 specName 的目录(可能是模块目录)
591
- // 例如:BDVideoPlayer、UI/BDVideoPlayer 等
592
- const headerFileName = path.basename(headName);
593
-
594
- // 尝试在项目根目录下查找模块目录
595
- // 1. 直接查找 specName 目录
596
- const directModulePath = path.join(projectRoot, specName);
597
- try {
598
- const entries = await getDirectoryEntries(directModulePath);
599
- if (entries) {
600
- // 检查是否有 include/ModuleName/ 目录
601
- const includePath = path.join(directModulePath, 'include', specName, headerFileName);
602
- try {
603
- await fs.promises.access(includePath);
604
- return {
605
- moduleName: specName,
606
- headerFileName: headerFileName
607
- };
608
- } catch (err) {
609
- // 继续查找
610
- }
611
- }
612
- } catch (err) {
613
- // 继续查找
614
- }
615
-
616
- // 2. 递归查找包含 specName 的目录
617
- const foundModule = await findModuleDirectory(projectRoot, specName, headerFileName);
618
- if (foundModule) {
619
- return foundModule;
620
- }
621
-
622
- // 如果找不到,返回默认值(使用 specName 和 headerFileName)
623
- return {
624
- moduleName: specName,
625
- headerFileName: headerFileName
626
- };
627
- }
628
-
629
- /**
630
- * 递归查找模块目录
631
- */
632
- async function findModuleDirectory(dirPath, moduleName, headerFileName) {
633
- try {
634
- const entries = await getDirectoryEntries(dirPath);
635
- if (!entries) {
636
- return null;
637
- }
638
-
639
- for (const entry of entries) {
640
- if (entry.isDirectory()) {
641
- const dirName = entry.name;
642
- // 跳过隐藏目录和常见目录
643
- if (dirName.startsWith('.') || dirName === 'node_modules') {
644
- continue;
645
- }
646
-
647
- const fullPath = path.join(dirPath, dirName);
648
-
649
- // 检查是否是模块目录(包含 include/ModuleName/ 结构)
650
- const includePath = path.join(fullPath, 'include', moduleName, headerFileName);
651
- try {
652
- await fs.promises.access(includePath);
653
- return {
654
- moduleName: moduleName,
655
- headerFileName: headerFileName
656
- };
657
- } catch (err) {
658
- // 继续递归查找
659
- const found = await findModuleDirectory(fullPath, moduleName, headerFileName);
660
- if (found) {
661
- return found;
662
- }
663
- }
664
- }
665
- }
666
- } catch (err) {
667
- // 忽略错误
668
- }
669
-
670
- return null;
435
+ const rootMarkerPath = await searchUpwardForFile(startPath, ROOT_MARKER_NAME);
436
+ return rootMarkerPath ? path.dirname(rootMarkerPath) : null;
671
437
  }
672
438
 
673
- /**
674
- * 获取根目录的 AutoSnippetRoot.boxspec.json 文件路径
675
- * @param {string} filePath - 起始文件路径或目录路径
676
- * @returns {Promise<string|null>} 根目录的 AutoSnippetRoot.boxspec.json 文件路径,如果找不到返回 null
677
- */
678
439
  async function getRootSpecFilePath(filePath) {
679
440
  const projectRoot = await findProjectRoot(filePath);
680
441
  if (!projectRoot) {
@@ -682,12 +443,10 @@ async function getRootSpecFilePath(filePath) {
682
443
  }
683
444
  const rootSpecFile = path.join(projectRoot, ROOT_MARKER_NAME);
684
445
 
685
- // 检查文件是否存在,如果不存在则创建
686
446
  try {
687
447
  await fs.promises.access(rootSpecFile);
688
448
  } catch (err) {
689
449
  if (err.code === 'ENOENT') {
690
- // 文件不存在,创建它
691
450
  const specObj = {
692
451
  list: []
693
452
  };
@@ -706,6 +465,5 @@ exports.parsePackageSwift = parsePackageSwift;
706
465
  exports.findSubHeaderPath = findSubHeaderPath;
707
466
  exports.findSubASSpecPath = findSubASSpecPath;
708
467
  exports.findProjectRoot = findProjectRoot;
709
- exports.findModuleHeaderFromRoot = findModuleHeaderFromRoot;
710
468
  exports.getRootSpecFilePath = getRootSpecFilePath;
711
469
  exports.ROOT_MARKER_NAME = ROOT_MARKER_NAME;
package/bin/init.js CHANGED
@@ -16,27 +16,18 @@ async function mergeSubSpecs(mainSpecFile) {
16
16
  list: []
17
17
  };
18
18
 
19
- // ✅ 找到项目根目录的 AutoSnippetRoot.boxspec.json 文件
20
- console.log(`[mergeSubSpecs] 主配置文件路径: ${mainSpecFile}`);
21
19
  const rootSpecFile = await findPath.getRootSpecFilePath(mainSpecFile);
22
20
  if (!rootSpecFile) {
23
- console.error(`[mergeSubSpecs] 未找到项目根目录,无法聚合配置`);
24
21
  return;
25
22
  }
26
- console.log(`[mergeSubSpecs] 根目录配置文件: ${rootSpecFile}`);
27
23
 
28
24
  const projectRoot = path.dirname(rootSpecFile);
29
25
  const searchRoot = projectRoot;
30
- console.log(`[mergeSubSpecs] 项目根目录: ${projectRoot}`);
31
- console.log(`[mergeSubSpecs] 搜索根目录: ${searchRoot}`);
32
26
 
33
27
  const specSlashIndex = rootSpecFile.lastIndexOf('/');
34
28
  const specFilePath = rootSpecFile.substring(0, specSlashIndex + 1);
35
29
 
36
- // ✅ 从项目根目录向下查找子模块的 AutoSnippet.boxspec.json
37
- console.log(`[mergeSubSpecs] 开始查找子模块配置,搜索根目录: ${searchRoot}`);
38
30
  const array = await findPath.findSubASSpecPath(searchRoot);
39
- console.log(`[mergeSubSpecs] 找到 ${array.length} 个子模块配置文件`);
40
31
 
41
32
  for (let i = 0; i < array.length; i++) {
42
33
  const filename = array[i];
@@ -62,8 +53,6 @@ async function mergeSubSpecs(mainSpecFile) {
62
53
  }
63
54
  }
64
55
  idsArray.push(item['{identifier}']);
65
- // ✅ SPM 模块:headName 已经是相对于模块根目录的相对路径
66
- // headName 保持相对于各自模块根目录的路径(不需要转换)
67
56
  return true;
68
57
  });
69
58
  specObj.list = specObj.list.concat(arr);
@@ -76,12 +65,10 @@ async function mergeSubSpecs(mainSpecFile) {
76
65
  try {
77
66
  const content = JSON.stringify(specObj, null, 4);
78
67
  if (content) {
79
- // ✅ 写入根目录的 AutoSnippetRoot.boxspec.json
80
68
  fs.writeFileSync(rootSpecFile, content, 'utf8');
81
- console.log(`[mergeSubSpecs] 已聚合 ${specObj.list.length} 个 snippet 到根目录配置文件`);
82
69
  }
83
70
  } catch (err) {
84
- console.error(err);
71
+ // 忽略错误
85
72
  }
86
73
  }
87
74
 
@@ -104,7 +91,6 @@ async function findTargetRootDirFromPath(dirPath) {
104
91
  for (const entry of entries) {
105
92
  if (entry.isDirectory() && (entry.name === 'Code' || entry.name === 'Sources')) {
106
93
  // 找到包含 Code 或 Sources 的目录,这就是 target 根目录
107
- console.log(`[findTargetRootDirFromPath] 找到 target 根目录: ${currentPath} (包含 ${entry.name})`);
108
94
  return currentPath;
109
95
  }
110
96
  }
@@ -124,7 +110,6 @@ async function findTargetRootDirFromPath(dirPath) {
124
110
  }
125
111
  }
126
112
 
127
- console.log(`[findTargetRootDirFromPath] 未找到 target 根目录(Code 或 Sources)`);
128
113
  return null;
129
114
  }
130
115
 
@@ -137,31 +122,22 @@ async function initSpec() {
137
122
  let packagePath = await findPath.findPackageSwiftPath(CMD_PATH);
138
123
  if (packagePath) {
139
124
  targetRootDir = path.dirname(packagePath);
140
- console.log(`[initSpec] 使用 Package.swift 所在目录作为 target 根目录: ${targetRootDir}`);
141
125
  } else {
142
- // 如果都找不到,使用当前目录
143
126
  targetRootDir = CMD_PATH;
144
- console.log(`[initSpec] 使用当前目录作为 target 根目录: ${targetRootDir}`);
145
127
  }
146
128
  }
147
129
 
148
130
  const filePath = path.join(targetRootDir, 'AutoSnippet.boxspec.json');
149
- console.log(`[initSpec] 将在 target 根目录创建配置文件: ${filePath}`);
150
131
 
151
- // 如果配置文件不存在,创建一个空的
152
132
  try {
153
133
  await fs.promises.access(filePath);
154
- console.log(`[initSpec] 配置文件已存在: ${filePath}`);
155
134
  } catch (error) {
156
135
  const specObj = {
157
136
  list: []
158
137
  };
159
138
  const content = JSON.stringify(specObj, null, 4);
160
139
  fs.writeFileSync(filePath, content, 'utf8');
161
- console.log(`[initSpec] 已创建配置文件: ${filePath}`);
162
140
  }
163
-
164
- // ✅ 聚合子模块配置到根目录的 AutoSnippetRoot.boxspec.json
165
141
  await mergeSubSpecs(filePath);
166
142
  }
167
143
 
package/bin/injection.js CHANGED
@@ -91,16 +91,40 @@ async function handleHeaderLine(specFile, updateFile, headerLine, importArray, i
91
91
  // 获取当前文件所在的模块名(通过路径判断)
92
92
  const currentModuleName = determineCurrentModuleName(updateFile, currentPackageInfo);
93
93
 
94
- // ✅ 获取头文件缓存,然后确定头文件所在的模块名
95
- const headCache = await cache.getHeadCache(specFile);
96
- const headerModuleName = await determineHeaderModuleName(specFile, header, headCache);
94
+ // ✅ 优先从标记中获取相对路径,如果没有则从缓存获取
95
+ // 标记格式:// ahead <Module/Header.h> relative/path/to/Header.h
96
+ let headRelativePath = header.headRelativePathFromMark;
97
+ if (!headRelativePath) {
98
+ // 标记中没有相对路径,尝试从缓存获取
99
+ const headCache = await cache.getHeadCache(specFile);
100
+ if (headCache && headCache[header.headerName]) {
101
+ headRelativePath = headCache[header.headerName];
102
+ }
103
+ }
104
+
105
+ const headerInfo = await determineHeaderInfo(specFile, header, headRelativePath, currentPackageInfo, currentModuleName);
97
106
 
98
- // ✅ 更新 header 中的模块名和 specName,确保使用正确的模块名(最近的 target 模块名)
99
- header.moduleName = headerModuleName;
100
- header.specName = '<' + headerModuleName + '/' + header.headerName + '>';
107
+ // ✅ 更新 header 中的模块名、相对路径和 specName
108
+ header.moduleName = headerInfo.moduleName;
109
+ header.headRelativePath = headerInfo.headRelativePath; // 相对于模块根目录的相对路径
110
+ header.specName = '<' + headerInfo.moduleName + '/' + header.headerName + '>';
101
111
 
102
112
  // ✅ 判断是否为同一模块
103
- const isSameModule = currentModuleName === headerModuleName;
113
+ const isSameModule = currentModuleName === headerInfo.moduleName;
114
+
115
+ // ✅ 如果是同一模块,计算相对于当前文件的相对路径
116
+ if (isSameModule && headerInfo.headRelativePath) {
117
+ // 当前文件相对于模块根目录的路径
118
+ const currentFileRelativeToModuleRoot = path.relative(currentPackageInfo.path, updateFile);
119
+ // 头文件相对于模块根目录的路径
120
+ const headRelativeToModuleRoot = headerInfo.headRelativePath;
121
+
122
+ // 计算从当前文件到头文件的相对路径
123
+ const currentFileDir = path.dirname(currentFileRelativeToModuleRoot);
124
+ const relativePathToHeader = path.relative(currentFileDir, headRelativeToModuleRoot).replace(/\\/g, '/');
125
+
126
+ header.relativePathToCurrentFile = relativePathToHeader;
127
+ }
104
128
 
105
129
  // 如果是同一模块,使用相对路径;否则使用 <> 格式
106
130
  handleModuleHeader(specFile, updateFile, header, importArray, !isSameModule);
@@ -125,57 +149,112 @@ function determineCurrentModuleName(filePath, packageInfo) {
125
149
  }
126
150
 
127
151
  /**
128
- * 确定头文件所在的模块名(SPM)
152
+ * 确定头文件信息(模块名、相对路径等)
129
153
  * 从头文件路径查找 Package.swift,确定最近的 target 模块名
154
+ * 同时计算相对于当前文件的相对路径
155
+ * @param {string} specFile - 配置文件路径
156
+ * @param {object} header - 头文件信息对象
157
+ * @param {string} headRelativePath - 头文件相对路径(相对于模块根目录),可能来自标记或缓存
158
+ * @param {object} currentPackageInfo - 当前文件的 Package.swift 信息
159
+ * @param {string} currentModuleName - 当前模块名
130
160
  */
131
- async function determineHeaderModuleName(specFile, header, headCache) {
132
- if (!headCache) {
133
- // 没有缓存,使用从 headerLine 解析的模块名(可能不准确)
134
- return header.moduleName;
135
- }
161
+ async function determineHeaderInfo(specFile, header, headRelativePath, currentPackageInfo, currentModuleName) {
162
+ // 默认值
163
+ let moduleName = header.moduleName;
164
+ let relativePathToCurrentFile = null;
136
165
 
137
- // 从头缓存中获取头文件的相对路径
138
- const headRelativePath = headCache[header.headerName];
139
166
  if (!headRelativePath) {
140
- // 找不到头文件路径,使用从 headerLine 解析的模块名
141
- return header.moduleName;
167
+ // 没有相对路径,使用从 headerLine 解析的模块名(可能不准确)
168
+ return {
169
+ moduleName: moduleName,
170
+ headRelativePath: null,
171
+ relativePathToCurrentFile: null
172
+ };
142
173
  }
143
174
 
144
- // ✅ specFile 位于模块根目录(如 ModuleRoot/AutoSnippet.boxspec.json
145
- const moduleRootDir = path.dirname(specFile);
146
- const headPath = path.join(moduleRootDir, headRelativePath);
175
+ // ✅ specFile 可能是根目录的 AutoSnippetRoot.boxspec.json,需要找到头文件所在的模块配置
176
+ // 尝试从根目录的配置文件查找头文件所在的模块
177
+ const rootSpecDir = path.dirname(specFile);
178
+ let headPath = null;
179
+
180
+ // 尝试多种可能的路径
181
+ // 1. 直接使用根目录的相对路径
182
+ headPath = path.join(rootSpecDir, headRelativePath);
183
+
184
+ // 2. 如果文件不存在,尝试从子模块中查找
185
+ if (!fs.existsSync(headPath)) {
186
+ // 从头文件路径向上查找 Package.swift
187
+ const headerPackagePath = await findPath.findPackageSwiftPath(headPath);
188
+ if (headerPackagePath) {
189
+ const headerPackageInfo = await findPath.parsePackageSwift(headerPackagePath);
190
+ if (headerPackageInfo) {
191
+ // 找到 Package.swift,使用它的路径作为模块根目录
192
+ const headerModuleRootDir = path.dirname(headerPackagePath);
193
+ headPath = path.join(headerModuleRootDir, headRelativePath);
194
+ }
195
+ }
196
+ }
147
197
 
148
198
  // 从头文件路径向上查找 Package.swift
149
199
  const headerPackagePath = await findPath.findPackageSwiftPath(headPath);
150
200
  if (!headerPackagePath) {
151
201
  // 找不到 Package.swift,使用从 headerLine 解析的模块名
152
- return header.moduleName;
202
+ return {
203
+ moduleName: moduleName,
204
+ headRelativePath: headRelativePath,
205
+ relativePathToCurrentFile: null
206
+ };
153
207
  }
154
208
 
155
209
  // 解析 Package.swift 获取模块信息
156
210
  const headerPackageInfo = await findPath.parsePackageSwift(headerPackagePath);
157
211
  if (!headerPackageInfo) {
158
- return header.moduleName;
212
+ return {
213
+ moduleName: moduleName,
214
+ headRelativePath: headRelativePath,
215
+ relativePathToCurrentFile: null
216
+ };
159
217
  }
160
218
 
161
219
  // ✅ 根据头文件路径确定最近的 target 模块名
162
- return determineCurrentModuleName(headPath, headerPackageInfo);
220
+ moduleName = determineCurrentModuleName(headPath, headerPackageInfo);
221
+
222
+ // ✅ 如果是同一模块,计算相对于当前文件的相对路径
223
+ // 注意:这里需要知道当前文件的路径,所以需要从外部传入
224
+ // 但当前函数中还没有 updateFile,所以这部分逻辑在 handleHeaderLine 中完成
225
+
226
+ return {
227
+ moduleName: moduleName,
228
+ headRelativePath: headRelativePath,
229
+ relativePathToCurrentFile: null // 将在 handleHeaderLine 中计算
230
+ };
163
231
  }
164
232
 
165
233
  // isOuter区分模块内部引用""格式和模块外部引用<>格式
166
234
  // ✅ SPM 模块:
167
- // - isOuter = false:同一模块内部,使用相对路径 #import "Header.h"
235
+ // - isOuter = false:同一模块内部,使用相对路径 #import "relative/path/Header.h" 或 #import "Header.h"
168
236
  // - isOuter = true:不同模块之间,使用 #import <ModuleName/Header.h>
169
237
  function handleModuleHeader(specFile, updateFile, header, importArray, isOuter) {
170
- // ✅ 根据 isOuter 选择不同的引入格式
171
- const headName = isOuter ? header.name : header.headerStrName; // isOuter: <ModuleName/Header.h>, 否则: "Header.h"
238
+ // ✅ 根据 isOuter 选择不同的引入格式,用于检查是否已存在
239
+ let headNameToCheck;
240
+ if (isOuter) {
241
+ // 外部模块,使用 <> 格式
242
+ headNameToCheck = header.name; // <ModuleName/Header.h>
243
+ } else {
244
+ // 同一模块内部,使用相对路径
245
+ if (header.relativePathToCurrentFile) {
246
+ headNameToCheck = '"' + header.relativePathToCurrentFile + '"'; // "relative/path/Header.h"
247
+ } else {
248
+ headNameToCheck = header.headerStrName; // "Header.h"
249
+ }
250
+ }
172
251
  const moduleName = isOuter ? header.specName : header.moduleStrName;
173
252
 
174
253
  // 检查是否已经引入头文件
175
254
  for (let i = 0; i < importArray.length; i++) {
176
255
  const importHeader = importArray[i].split(importMark)[1].trim();
177
256
 
178
- if (importHeader === headName) {
257
+ if (importHeader === headNameToCheck) {
179
258
  // 已经引入头文件
180
259
  handelAddHeaderStatus(specFile, updateFile, header, true, false, isOuter);
181
260
  return;
@@ -267,10 +346,21 @@ function removeMarkFromFile(updateFile, header, string) {
267
346
  function addHeaderToFile(updateFile, header, isOuter) {
268
347
  // ✅ 根据 isOuter 选择不同的引入格式
269
348
  // isOuter = true: 使用 <> 格式(#import <ModuleName/Header.h>)
270
- // isOuter = false: 使用相对路径(#import "Header.h")
271
- const importLine = isOuter
272
- ? importMark + ' ' + header.name // <ModuleName/Header.h>
273
- : importMark + ' ' + header.headerStrName; // "Header.h"
349
+ // isOuter = false: 使用相对路径(#import "relative/path/Header.h" 或 #import "Header.h"
350
+ let importLine;
351
+ if (isOuter) {
352
+ // 外部模块,使用 <> 格式
353
+ importLine = importMark + ' ' + header.name; // <ModuleName/Header.h>
354
+ } else {
355
+ // 同一模块内部,使用相对路径
356
+ if (header.relativePathToCurrentFile) {
357
+ // 使用计算出的相对路径(如 "SubDir/Header.h" 或 "../Header.h")
358
+ importLine = importMark + ' "' + header.relativePathToCurrentFile + '"';
359
+ } else {
360
+ // 如果没有相对路径,使用文件名(如 "Header.h")
361
+ importLine = importMark + ' ' + header.headerStrName; // "Header.h"
362
+ }
363
+ }
274
364
 
275
365
  readStream(updateFile, importLine, importMark);
276
366
  checkDependency(updateFile, header.moduleName, '自动注入头文件完成。').catch(err => {
package/bin/install.js CHANGED
@@ -30,6 +30,11 @@ function writeSingleSnippet(snippet, template) {
30
30
  // 例如:<BDVideoPlayer/BDVideoCacheManager.h> 而不是 <BDVideoPlayer/UI/BDVideoPlayer/Code/BDVideoCacheManager.h>
31
31
  const headerFileName = path.basename(extPlace['{headName}']);
32
32
  let header = '<' + extPlace['{specName}'] + '/' + headerFileName + '>';
33
+
34
+ // ✅ 在标记中包含相对路径信息,格式:// ahead <Module/Header.h> relative/path/to/Header.h
35
+ // 这样即使没有缓存也能解析出完整信息
36
+ const headRelativePath = extPlace['{headName}']; // 相对于模块根目录的相对路径
37
+ header = header + ' ' + headRelativePath;
33
38
  header = escapeString(header);
34
39
 
35
40
  // swift只需要考虑工作空间是否引入
@@ -42,7 +47,7 @@ function writeSingleSnippet(snippet, template) {
42
47
  extPlace['{completion}'] = extPlace['{completion}'] + 'Z';
43
48
  extPlace['{summary}'] = extPlace['{summary}'] + header;
44
49
 
45
- // 添加替换header标识位
50
+ // 添加替换header标识位(格式:// ahead <Module/Header.h> relative/path/to/Header.h)
46
51
  let array = ['// ahead ' + header];
47
52
  extPlace['{content}'].forEach(element => {
48
53
  array.push(element);
@@ -159,6 +164,11 @@ function addCodeSnippets(specFile, singleSnippet) {
159
164
  // ✅ 从项目根目录找到模块,只使用模块名和头文件名
160
165
  const headerFileName = path.basename(extPlace['{headName}']);
161
166
  let header = '<' + extPlace['{specName}'] + '/' + headerFileName + '>';
167
+
168
+ // ✅ 在标记中包含相对路径信息,格式:// ahead <Module/Header.h> relative/path/to/Header.h
169
+ // 这样即使没有缓存也能解析出完整信息
170
+ const headRelativePath = extPlace['{headName}']; // 相对于模块根目录的相对路径
171
+ header = header + ' ' + headRelativePath;
162
172
  header = escapeString(header);
163
173
 
164
174
  // swift只需要考虑工作空间是否引入
package/bin/watch.js CHANGED
@@ -14,7 +14,8 @@ const alinkMark = 'alink';
14
14
  const wellMark = '#';
15
15
  const atMark = '@';
16
16
 
17
- const headerReg = /^\/\/ ahead <\w+\/\w+.h>$/;
17
+ // 更新正则以匹配包含相对路径的新格式:// ahead <Module/Header.h> relative/path/to/Header.h
18
+ const headerReg = /^\/\/ ahead <\w+\/\w+.h>(\s+.+)?$/;
18
19
  const headerSwiftReg = /^\/\/ ahead \w+$/;
19
20
  const importReg = /^\#import\s*<\w+\/\w+.h>$/;
20
21
  const importSwiftReg = /^import\s*\w+$/;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autosnippet",
3
- "version": "1.1.21",
3
+ "version": "1.1.23",
4
4
  "description": "A iOS module management tool.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -31,5 +31,8 @@
31
31
  "devDependencies": {},
32
32
  "bugs": {
33
33
  "url": "https://github.com/GxFn/AutoSnippet/issues"
34
+ },
35
+ "directories": {
36
+ "doc": "docs"
34
37
  }
35
38
  }