autosnippet 1.1.20 → 1.1.22

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/asnip.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const fs = require('fs');
4
+ const path = require('path');
4
5
  // 读取输入命令
5
6
  const inquirer = require('inquirer');
6
7
  // 命令行工具
@@ -219,19 +220,32 @@ commander
219
220
  commander
220
221
  .command('w')
221
222
  .description('recognize that Snippet automatically injects dependency header files')
222
- .action(() => {
223
- getSpecFile(function (specFile) {
224
- install.addCodeSnippets(specFile);
225
- watch.watchFileChange(specFile);
226
- });
223
+ .action(async () => {
224
+ // 从执行位置向上查找 AutoSnippetRoot.boxspec.json,找到根目录
225
+ const projectRoot = await findPath.findProjectRoot(CMD_PATH);
226
+
227
+ if (!projectRoot) {
228
+ console.error('未找到项目根目录(AutoSnippetRoot.boxspec.json)。');
229
+ console.error('请先使用 asd root 命令在项目根目录创建根目录标记文件。');
230
+ return;
231
+ }
232
+
233
+ console.log(`[asd w] 项目根目录: ${projectRoot}`);
234
+
235
+ // ✅ 使用根目录的 AutoSnippetRoot.boxspec.json 作为配置文件
236
+ const rootSpecFile = path.join(projectRoot, findPath.ROOT_MARKER_NAME);
237
+ console.log(`[asd w] 使用配置文件: ${rootSpecFile}`);
238
+
239
+ // 先安装 snippets
240
+ install.addCodeSnippets(rootSpecFile);
241
+ // 在根目录启动监听
242
+ watch.watchFileChange(rootSpecFile, projectRoot);
227
243
  });
228
244
 
229
245
  commander
230
246
  .command('root')
231
247
  .description('mark current directory as project root by creating AutoSnippetRoot.boxspec.json')
232
248
  .action(() => {
233
- const fs = require('fs');
234
- const path = require('path');
235
249
  const rootMarkerPath = path.join(CMD_PATH, 'AutoSnippetRoot.boxspec.json');
236
250
 
237
251
  try {
package/bin/findPath.js CHANGED
@@ -383,7 +383,24 @@ async function parsePackageSwift(packagePath) {
383
383
 
384
384
  // 向下查找模块头文件(优化:适配 SPM 结构,优先查找 include/ModuleName/ 目录)
385
385
  async function findSubHeaderPath(filePath, headerName, moduleName) {
386
- // ✅ 优先查找 include/ModuleName/ 目录(SPM 结构)
386
+ // ✅ 优先查找 Code/ 目录(实际源代码位置)
387
+ // 按照用户期望的顺序:target根目录 → Code → 子文件夹/头文件
388
+ const codePath = path.join(filePath, 'Code');
389
+ try {
390
+ const stats = await fs.promises.stat(codePath);
391
+ if (stats.isDirectory()) {
392
+ // 在 Code 目录中递归查找头文件
393
+ const result = await findSubHeaderPath(codePath, headerName, null);
394
+ if (result) {
395
+ return result;
396
+ }
397
+ }
398
+ } catch {
399
+ // Code 目录不存在,继续查找
400
+ }
401
+
402
+ // ✅ 降级:查找 include/ModuleName/ 目录(SPM 公共头文件结构)
403
+ // 注意:include/ 目录通常是符号链接,但作为后备方案保留
387
404
  if (moduleName) {
388
405
  const includePath = path.join(filePath, 'include', moduleName);
389
406
  try {
@@ -402,7 +419,7 @@ async function findSubHeaderPath(filePath, headerName, moduleName) {
402
419
  }
403
420
  }
404
421
 
405
- // ✅ 降级:在整个模块目录中查找(深度限制)
422
+ // ✅ 最后:在整个模块目录中查找(深度限制)
406
423
  try {
407
424
  const entries = await getDirectoryEntries(filePath);
408
425
  if (!entries) {
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+$/;
@@ -22,10 +23,11 @@ const importSwiftReg = /^import\s*\w+$/;
22
23
  let timeoutLink = null;
23
24
  let timeoutHead = null;
24
25
 
25
- function watchFileChange(specFile) {
26
-
27
- // 监听文件变化
28
- const filePath = CMD_PATH;
26
+ function watchFileChange(specFile, watchRootPath) {
27
+ // ✅ 如果指定了监听根目录,使用它;否则使用当前工作目录
28
+ const filePath = watchRootPath || CMD_PATH;
29
+ console.log(`[watchFileChange] 监听目录: ${filePath}`);
30
+ console.log(`[watchFileChange] 配置文件: ${specFile}`);
29
31
  let isReading = false;
30
32
 
31
33
  fs.watch(filePath, {recursive: true}, (event, filename) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autosnippet",
3
- "version": "1.1.20",
3
+ "version": "1.1.22",
4
4
  "description": "A iOS module management tool.",
5
5
  "main": "index.js",
6
6
  "scripts": {