autosnippet 1.1.12 → 1.1.14

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 高雪峰
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,36 +1,36 @@
1
1
  # AutoSnippet
2
2
 
3
- A iOS module management tool. Use the command line to create an Xcode Snippet, generate a JSON file, and share it with other developers in the code repository.
3
+ 一个 iOS 模块管理工具。使用命令行创建 Xcode 代码片段,生成 JSON 配置文件,并在代码仓库中与其他开发者共享。
4
4
 
5
- ## Installation
5
+ ## 安装
6
6
 
7
7
  ```bash
8
8
  $ npm install -g autosnippet
9
9
  ```
10
10
 
11
- ## Options
11
+ ## 命令选项
12
12
 
13
- Please use all the following commands in the current Xcode project file directory.
13
+ 请在当前 Xcode 项目文件目录下使用以下所有命令。
14
14
 
15
15
  ### init
16
16
 
17
- Execute this command in the root directory of the Xcode project to create a workspace:
17
+ Xcode 项目的根目录执行此命令以创建工作空间:
18
18
 
19
19
  ```bash
20
20
  $ asd init
21
21
  ```
22
22
 
23
- When creating a workspace, the Snippet configuration information of the sub-workspace will be collected to the current workspace.
23
+ 创建工作空间时,会将子工作空间的 Snippet 配置信息收集到当前工作空间。
24
24
 
25
25
  ### create
26
26
 
27
- Command to create an Xcode Snippet, in the file directory marked with `// ACode` code:
27
+ 创建 Xcode 代码片段的命令,在标记有 `// ACode` 代码的文件目录中:
28
28
 
29
29
  ```bash
30
30
  $ asd c
31
31
  ```
32
32
 
33
- Code like this:
33
+ 代码示例:
34
34
 
35
35
  ```
36
36
  // ACode
@@ -40,22 +40,22 @@ UIView *view = [[UIView alloc] init];
40
40
 
41
41
  ### install
42
42
 
43
- Add the shared Snippet to the Xcode environment:
43
+ 将共享的代码片段添加到 Xcode 环境:
44
44
 
45
45
  ```bash
46
46
  $ asd i
47
47
  ```
48
48
 
49
- Use code Snippet like this:
49
+ 使用代码片段示例:
50
50
 
51
51
  ```
52
- // view is code key entered when creating
52
+ // view 是创建时输入的代码键
53
53
  @view
54
54
  ```
55
55
 
56
56
  ### share
57
57
 
58
- Share local Snippet:
58
+ 共享本地代码片段:
59
59
 
60
60
  ```bash
61
61
  $ asd s
@@ -63,60 +63,60 @@ $ asd s
63
63
 
64
64
  ### watch
65
65
 
66
- In modular projects, recognize that Snippet automatically injects dependency header files:
66
+ 在模块化项目中,识别代码片段并自动注入依赖头文件:
67
67
 
68
68
  ```bash
69
69
  $ asd w
70
70
  ```
71
71
 
72
- #### Append header file
72
+ #### 追加头文件
73
73
 
74
- After the watch is turned on, if you want to append the header file, perform the following operations:
74
+ 开启监听后,如果想要追加头文件,请执行以下操作:
75
75
 
76
- 1. Down arrow to select the headerVersion of Snippet
77
- 2. Press the `Enter`
78
- 3. `Command + S` save file
76
+ 1. 向下箭头选择代码片段的 headerVersion
77
+ 2. `Enter`
78
+ 3. `Command + S` 保存文件
79
79
 
80
- Within 1 second, the header file is automatically added to the file header.
80
+ 1 秒内,头文件会自动添加到文件头部。
81
81
 
82
- #### Browser view
82
+ #### 浏览器查看
83
83
 
84
- After the watch is turned on, if you want to view more information about the module in the browser, perform the following operations:
84
+ 开启监听后,如果想要在浏览器中查看模块的更多信息,请执行以下操作:
85
85
 
86
- 1. Enter `@` and `module key`
87
- 2. Enter `#` and `ALink`
88
- 3. `Command + S` save file
86
+ 1. 输入 `@` `模块键`
87
+ 2. 输入 `#` `ALink`
88
+ 3. `Command + S` 保存文件
89
89
 
90
- Automatically jump to the browser to open the link configured during creation, and open the README.md file without a link.
90
+ 会自动跳转到浏览器打开创建时配置的链接,如果没有链接则打开 README.md 文件。
91
91
 
92
- Use ALink like this:
92
+ 使用 ALink 示例:
93
93
 
94
94
  ```
95
95
  @view#ALink
96
96
  ```
97
97
 
98
- ## Other
98
+ ## 其他
99
99
 
100
- ### Shortcuts for placeholders
100
+ ### 占位符快捷键
101
101
 
102
- You can add a placeholder in your snippets too using following tag:
102
+ 您也可以在代码片段中添加占位符,使用以下标签:
103
103
 
104
104
  ```
105
105
  <#placeholder#>
106
106
  ```
107
107
 
108
- E.g: the above placeholder can be written as:
108
+ 例如:上面的占位符可以写成:
109
109
 
110
110
  ```
111
111
  <#view: UIView#>
112
112
  ```
113
113
 
114
- Xcode detects <# and #> tokens and will make the text between them a placeholder. We can switch between multiple placeholders by pressing `Tab` key.
114
+ Xcode 会检测 `<#` `#>` 标记,并将它们之间的文本作为占位符。我们可以通过按 `Tab` 键在多个占位符之间切换。
115
115
 
116
- When there are multiple same placeholders, use `⌥⌘E` to select multiple placeholders continuously:
116
+ 当有多个相同的占位符时,使用 `⌥⌘E` 连续选择多个占位符:
117
117
 
118
- 1. Select a placeholder
119
- 2. `⌥⌘E` selects the next placeholder, `⌥⇧⌘E` selects the previous placeholder
120
- 3. Enter the modified content, all selected placeholders will be modified
118
+ 1. 选择一个占位符
119
+ 2. `⌥⌘E` 选择下一个占位符,`⌥⇧⌘E` 选择上一个占位符
120
+ 3. 输入修改的内容,所有选中的占位符都会被修改
121
121
 
122
- Thanks.
122
+ 感谢使用。
package/bin/asnip.js CHANGED
@@ -15,8 +15,66 @@ const watch = require('./watch.js');
15
15
  const cache = require('./cache.js');
16
16
  const share = require('./share.js');
17
17
  const init = require('./init.js');
18
+ const config = require('./config.js');
18
19
 
19
- function askQuestions(specFile) {
20
+ // 获取配置文件路径(测试模式优先使用 BiliDemo 配置)
21
+ function getSpecFile(callback) {
22
+ // 测试模式下,优先使用 BiliDemo 的配置文件
23
+ if (config.isTestMode()) {
24
+ const configPath = config.getConfigPath();
25
+ if (configPath && fs.existsSync(configPath)) {
26
+ callback(configPath);
27
+ return;
28
+ }
29
+ }
30
+
31
+ // 否则使用原有的查找逻辑
32
+ findPath.findASSpecPath(CMD_PATH, callback);
33
+ }
34
+
35
+ /**
36
+ * 先查找包含 // ACode 标记的文件,找到后再询问
37
+ */
38
+ async function findAndAsk(specFile) {
39
+ console.log('正在查找包含 // ACode 标记的文件...\n');
40
+
41
+ const filesWithACode = await create.findFilesWithACode(CMD_PATH);
42
+
43
+ if (filesWithACode.length === 0) {
44
+ console.log('未找到包含 // ACode 标记的文件。');
45
+ console.log('请在代码中添加 // ACode 标记,例如:');
46
+ console.log('');
47
+ console.log('// ACode');
48
+ console.log('UIView *view = [[UIView alloc] init];');
49
+ console.log('// ACode');
50
+ console.log('');
51
+ return;
52
+ }
53
+
54
+ // 显示找到的文件
55
+ console.log(`找到 ${filesWithACode.length} 个包含 // ACode 标记的文件:\n`);
56
+ filesWithACode.forEach((file, index) => {
57
+ console.log(` ${index + 1}. ${file.name} (第 ${file.line} 行)`);
58
+ });
59
+ console.log('');
60
+
61
+ // 如果只有一个文件,直接使用;如果有多个,让用户选择
62
+ let selectedFile = null;
63
+ if (filesWithACode.length === 1) {
64
+ selectedFile = filesWithACode[0].path;
65
+ console.log(`将使用文件: ${filesWithACode[0].name}\n`);
66
+ } else {
67
+ // 多个文件时,让用户选择(这里简化处理,使用第一个)
68
+ // 可以后续扩展为让用户选择
69
+ selectedFile = filesWithACode[0].path;
70
+ console.log(`将使用第一个文件: ${filesWithACode[0].name}\n`);
71
+ }
72
+
73
+ // 找到标记后,开始询问
74
+ askQuestions(specFile, selectedFile);
75
+ }
76
+
77
+ function askQuestions(specFile, selectedFilePath) {
20
78
  // 开始问问题
21
79
  const questions = [{
22
80
  type: 'input',
@@ -106,7 +164,8 @@ function askQuestions(specFile) {
106
164
  ];
107
165
 
108
166
  inquirer.prompt(questions).then((answers) => {
109
- create.createCodeSnippets(specFile, answers, null);
167
+ // 将选中的文件路径传递给 createCodeSnippets
168
+ create.createCodeSnippets(specFile, answers, null, selectedFilePath);
110
169
  });
111
170
  }
112
171
 
@@ -127,7 +186,7 @@ commander
127
186
  .command('i')
128
187
  .description('add the shared Snippet to the Xcode environment')
129
188
  .action(() => {
130
- findPath.findASSpecPath(CMD_PATH, function (specFile) {
189
+ getSpecFile(function (specFile) {
131
190
  install.addCodeSnippets(specFile);
132
191
  });
133
192
  });
@@ -136,7 +195,7 @@ commander
136
195
  .command('s')
137
196
  .description('share local Xcode Snippet')
138
197
  .action(() => {
139
- findPath.findASSpecPath(CMD_PATH, function (specFile) {
198
+ getSpecFile(function (specFile) {
140
199
  share.shareCodeSnippets(specFile);
141
200
  });
142
201
  });
@@ -145,8 +204,8 @@ commander
145
204
  .command('c')
146
205
  .description('create an Xcode Snippet, in the file directory marked with `// ACode` code')
147
206
  .action(() => {
148
- findPath.findASSpecPath(CMD_PATH, function (specFile) {
149
- askQuestions(specFile);
207
+ getSpecFile(function (specFile) {
208
+ findAndAsk(specFile);
150
209
  });
151
210
  });
152
211
 
@@ -154,7 +213,7 @@ commander
154
213
  .command('u <word> [key] [value]')
155
214
  .description('modify the `// ACode` code corresponding to `word`')
156
215
  .action((word, key, value) => {
157
- findPath.findASSpecPath(CMD_PATH, function (specFile) {
216
+ getSpecFile(function (specFile) {
158
217
  create.updateCodeSnippets(specFile, word, key, value);
159
218
  });
160
219
  });
@@ -163,7 +222,7 @@ commander
163
222
  .command('w')
164
223
  .description('recognize that Snippet automatically injects dependency header files')
165
224
  .action(() => {
166
- findPath.findASSpecPath(CMD_PATH, function (specFile) {
225
+ getSpecFile(function (specFile) {
167
226
  install.addCodeSnippets(specFile);
168
227
  watch.watchFileChange(specFile);
169
228
  });
package/bin/cache.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const fs = require('fs');
4
+ const path = require('path');
5
+ const config = require('./config.js');
4
6
 
5
7
  const SpecCache = 'SpecCache_';
6
8
  const KeysCache = 'KeysCache_';
@@ -114,15 +116,12 @@ async function getHeadCache(specFile) {
114
116
  function getFilePathFromHolderPath(key, specFile) {
115
117
  const pathBuff = Buffer.from(specFile, 'utf-8');
116
118
  const fileName = key + pathBuff.toString('base64') + '.json';
117
- const filePath = __dirname + '/../../AutoSnippetCache/';
119
+
120
+ // ✅ 使用配置模块获取缓存路径
121
+ const cachePath = config.getCachePath();
122
+ const filePath = path.join(cachePath, fileName);
118
123
 
119
- try {
120
- fs.accessSync(filePath, fs.F_OK);
121
- } catch (err) {
122
- fs.mkdirSync(filePath);
123
- }
124
-
125
- return filePath + fileName;
124
+ return filePath;
126
125
  }
127
126
 
128
127
  exports.updateCache = updateCache;
package/bin/config.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ // 检测是否为测试模式
7
+ // 通过环境变量 AUTOSNIPPET_TEST_MODE 或检测 BiliDemo 目录
8
+ function isTestMode() {
9
+ // 优先检查环境变量
10
+ if (process.env.AUTOSNIPPET_TEST_MODE === 'true') {
11
+ return true;
12
+ }
13
+
14
+ // 检查当前工作目录是否在 BiliDemo 项目内
15
+ const cwd = process.cwd();
16
+ if (cwd.includes('BiliDemo')) {
17
+ return true;
18
+ }
19
+
20
+ return false;
21
+ }
22
+
23
+ // 获取 BiliDemo 项目根目录
24
+ function getBiliDemoRoot() {
25
+ const cwd = process.cwd();
26
+ const parts = cwd.split(path.sep);
27
+
28
+ for (let i = parts.length; i > 0; i--) {
29
+ const testPath = parts.slice(0, i).join(path.sep);
30
+ if (fs.existsSync(path.join(testPath, 'BiliDili', 'AutoSnippet.boxspec.json'))) {
31
+ return testPath;
32
+ }
33
+ }
34
+
35
+ return null;
36
+ }
37
+
38
+ // 获取配置文件路径
39
+ function getConfigPath() {
40
+ if (isTestMode()) {
41
+ const biliDemoRoot = getBiliDemoRoot();
42
+ if (biliDemoRoot) {
43
+ return path.join(biliDemoRoot, 'BiliDili', 'AutoSnippet.boxspec.json');
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+
49
+ // 获取代码片段输出路径(测试模式写入 AutoSnippetCache,生产模式写入 Xcode)
50
+ function getSnippetsPath() {
51
+ if (isTestMode()) {
52
+ // ✅ 测试模式:写入 AutoSnippetCache/Snippets/
53
+ // __dirname: AutoSnippet/bin
54
+ // 目标路径: AutoSnippet/AutoSnippetCache/Snippets
55
+ const cachePath = path.join(__dirname, '../../AutoSnippetCache/Snippets');
56
+ try {
57
+ fs.accessSync(cachePath, fs.constants.F_OK);
58
+ } catch (err) {
59
+ fs.mkdirSync(cachePath, { recursive: true });
60
+ }
61
+ return cachePath;
62
+ } else {
63
+ // 生产模式:写入 Xcode CodeSnippets 目录
64
+ const USER_HOME = process.env.HOME || process.env.USERPROFILE;
65
+ return path.join(USER_HOME, 'Library/Developer/Xcode/UserData/CodeSnippets');
66
+ }
67
+ }
68
+
69
+ // 获取缓存目录路径
70
+ function getCachePath() {
71
+ // ✅ 缓存始终在 AutoSnippetCache 目录
72
+ // __dirname: AutoSnippet/bin
73
+ // 目标路径: AutoSnippet/AutoSnippetCache
74
+ const cachePath = path.join(__dirname, '../../AutoSnippetCache');
75
+ try {
76
+ fs.accessSync(cachePath, fs.constants.F_OK);
77
+ } catch (err) {
78
+ fs.mkdirSync(cachePath, { recursive: true });
79
+ }
80
+ return cachePath;
81
+ }
82
+
83
+ module.exports = {
84
+ isTestMode,
85
+ getBiliDemoRoot,
86
+ getConfigPath,
87
+ getSnippetsPath,
88
+ getCachePath
89
+ };
package/bin/create.js CHANGED
@@ -6,9 +6,32 @@ const readline = require('readline');
6
6
  const cache = require('./cache.js');
7
7
  const findPath = require('./findPath.js');
8
8
  const install = require('./install.js');
9
+ // 全局常量
10
+ const README_NAME = 'readme.md';
9
11
  // 全局路径
10
12
  const CMD_PATH = process.cwd();
11
13
 
14
+ /**
15
+ * 根据文件路径确定模块名(SPM)
16
+ */
17
+ function determineModuleName(filePath, packageInfo) {
18
+ // 从路径中提取模块名
19
+ // 例如:Services/Services/BDNetworkControl/Code/... -> BDNetworkControl
20
+ const packagePath = packageInfo.path;
21
+ const relativePath = path.relative(packagePath, filePath);
22
+ const segments = relativePath.split(path.sep);
23
+
24
+ // 查找匹配的 target
25
+ for (const segment of segments) {
26
+ if (packageInfo.targets.includes(segment)) {
27
+ return segment;
28
+ }
29
+ }
30
+
31
+ // 如果找不到,使用第一个 target
32
+ return packageInfo.targets[0] || packageInfo.name;
33
+ }
34
+
12
35
  function updateCodeSnippets(specFile, word, key, value) {
13
36
  if (key && key !== 'title' && key !== 'link' && key !== 'summary') {
14
37
  console.log('此项属性不存在或不可修改。');
@@ -54,12 +77,61 @@ function updateCodeSnippets(specFile, word, key, value) {
54
77
  }
55
78
  }
56
79
 
57
- function createCodeSnippets(specFile, answers, updateSnippet) {
80
+ /**
81
+ * 查找包含 // ACode 标记的文件
82
+ */
83
+ async function findFilesWithACode(filePath) {
84
+ const filesWithACode = [];
85
+
86
+ try {
87
+ const files = await fs.promises.readdir(filePath);
88
+
89
+ for (const filename of files) {
90
+ const filedir = path.join(filePath, filename);
91
+ try {
92
+ const stats = await fs.promises.lstat(filedir);
93
+ if (stats.isFile()) {
94
+ // 只检查源代码文件
95
+ if (filename.endsWith('.m') || filename.endsWith('.h') || filename.endsWith('.swift')) {
96
+ const content = await fs.promises.readFile(filedir, 'utf8');
97
+ const lines = content.split('\n');
98
+
99
+ // 检查是否包含 // ACode 标记
100
+ for (let i = 0; i < lines.length; i++) {
101
+ if (lines[i].trim().toLowerCase() === '// acode') {
102
+ filesWithACode.push({
103
+ path: filedir,
104
+ name: filename,
105
+ line: i + 1
106
+ });
107
+ break; // 找到标记后跳出,每个文件只记录一次
108
+ }
109
+ }
110
+ }
111
+ }
112
+ } catch (err) {
113
+ // 忽略无法读取的文件
114
+ continue;
115
+ }
116
+ }
117
+ } catch (err) {
118
+ console.error('Error reading directory:', err);
119
+ }
120
+
121
+ return filesWithACode;
122
+ }
123
+
124
+ function createCodeSnippets(specFile, answers, updateSnippet, selectedFilePath) {
58
125
  let snippet = updateSnippet;
59
126
  let isHaveHeader = snippet === null ? false : (snippet['{headName}'] !== undefined);
60
127
 
61
128
  if (snippet === null) {
62
- const answersKeys = answers.completion_first + answers.completion_more + answers.title;
129
+ // 处理 completion_more(可能是数组或字符串)
130
+ const completionMoreStr = Array.isArray(answers.completion_more)
131
+ ? answers.completion_more.join('')
132
+ : answers.completion_more;
133
+
134
+ const answersKeys = answers.completion_first + completionMoreStr + answers.title;
63
135
  const answersIdBuff = Buffer.from(answersKeys, 'utf-8');
64
136
  const identifier = 'AutoSnip_' + answersIdBuff.toString('base64').replace(/\//g, '');
65
137
 
@@ -67,7 +139,7 @@ function createCodeSnippets(specFile, answers, updateSnippet) {
67
139
  '{identifier}': identifier,
68
140
  '{title}': answers.title,
69
141
  '{completionKey}': answers.completion_first,
70
- '{completion}': '@' + answers.completion_first + answers.completion_more + '@Moudle',
142
+ '{completion}': '@' + answers.completion_first + completionMoreStr + '@Moudle',
71
143
  '{summary}': answers.summary,
72
144
  '{language}': 'Xcode.SourceCodeLanguage.Objective-C',
73
145
  };
@@ -78,31 +150,39 @@ function createCodeSnippets(specFile, answers, updateSnippet) {
78
150
  isHaveHeader = answers.header;
79
151
  }
80
152
 
81
- const filePath = CMD_PATH;
153
+ // 如果指定了文件路径,直接使用;否则查找当前目录下的所有文件
82
154
  let filePathArr = [];
155
+
156
+ if (selectedFilePath) {
157
+ // 使用指定的文件
158
+ filePathArr = [selectedFilePath];
159
+ readStream(specFile, filePathArr, snippet, isHaveHeader);
160
+ } else {
161
+ // 原有逻辑:查找当前目录下的所有文件
162
+ const filePath = CMD_PATH;
163
+ fs.readdir(filePath, function (err, files) {
164
+ if (err) {
165
+ console.log(err);
166
+ return;
167
+ }
83
168
 
84
- fs.readdir(filePath, function (err, files) {
85
- if (err) {
86
- console.log(err);
87
- return;
88
- }
89
-
90
- files.forEach(function (filename) {
91
- const filedir = path.join(filePath, filename);
92
- try {
93
- // 读取路径是否为文件
94
- const stats = fs.lstatSync(filedir);
95
- const isFile = stats.isFile();
96
- if (isFile) {
97
- filePathArr.push(filedir);
169
+ files.forEach(function (filename) {
170
+ const filedir = path.join(filePath, filename);
171
+ try {
172
+ // 读取路径是否为文件
173
+ const stats = fs.lstatSync(filedir);
174
+ const isFile = stats.isFile();
175
+ if (isFile) {
176
+ filePathArr.push(filedir);
177
+ }
178
+ } catch (err) {
179
+ console.error(err);
98
180
  }
99
- } catch (err) {
100
- console.error(err);
101
- }
102
- });
181
+ });
103
182
 
104
- readStream(specFile, filePathArr, snippet, isHaveHeader);
105
- });
183
+ readStream(specFile, filePathArr, snippet, isHaveHeader);
184
+ });
185
+ }
106
186
  }
107
187
 
108
188
  function readStream(specFile, filePathArr, snippet, isHaveHeader) {
@@ -152,24 +232,52 @@ function readStream(specFile, filePathArr, snippet, isHaveHeader) {
152
232
  const specSlashIndex = specFile.lastIndexOf('/');
153
233
  const specFilePath = specFile.substring(0, specSlashIndex + 1);
154
234
 
155
- findPath.findBPSpacPath(thePath, function (findFilePath, specName, readme) {
156
- const specPureName = specName.split('.')[0];
157
-
158
- findPath.findSubHeaderPath(findFilePath, specPureName).then(function (headerPath) {
235
+ // 使用 SPM Package.swift 查找(替代 .boxspec)
236
+ findPath.findPackageSwiftPath(thePath).then(async function (packagePath) {
237
+ if (!packagePath) {
238
+ console.log('未找到 Package.swift 文件,请检查路径。');
159
239
  snippet['{content}'] = codeList;
160
- snippet['{specName}'] = specPureName;
161
- snippet['{headName}'] = fileName;
162
-
163
- if (headerPath) {
164
- snippet['{specHeadPath}'] = encodeURI(headerPath.replace(specFilePath, ''));
165
- }
240
+ saveFromFile(specFile, snippet);
241
+ return;
242
+ }
166
243
 
167
- if (readme) {
168
- const readmePath = path.join(findFilePath, readme).replace(specFilePath, '');
169
- snippet['{readme}'] = encodeURI(readmePath);
170
- }
244
+ // 解析 Package.swift 获取模块信息
245
+ const packageInfo = await findPath.parsePackageSwift(packagePath);
246
+ if (!packageInfo) {
247
+ snippet['{content}'] = codeList;
171
248
  saveFromFile(specFile, snippet);
172
- });
249
+ return;
250
+ }
251
+
252
+ // 根据当前文件路径确定模块名
253
+ const moduleName = determineModuleName(filePath, packageInfo);
254
+ const headerName = fileName.substring(0, fileName.length - 2); // 移除 .h
255
+
256
+ // ✅ 查找头文件(适配 SPM 的 include/ModuleName/ 结构)
257
+ const headerPath = await findPath.findSubHeaderPath(packageInfo.path, headerName, moduleName);
258
+
259
+ snippet['{content}'] = codeList;
260
+ snippet['{specName}'] = moduleName;
261
+ snippet['{headName}'] = fileName;
262
+
263
+ if (headerPath) {
264
+ snippet['{specHeadPath}'] = encodeURI(headerPath.replace(specFilePath, ''));
265
+ }
266
+
267
+ // 查找 README.md
268
+ try {
269
+ const readmePath = path.join(packageInfo.path, README_NAME);
270
+ await fs.promises.access(readmePath);
271
+ snippet['{readme}'] = encodeURI(readmePath.replace(specFilePath, ''));
272
+ } catch {
273
+ // README.md 不存在,跳过
274
+ }
275
+
276
+ saveFromFile(specFile, snippet);
277
+ }).catch(function (err) {
278
+ console.error('Error finding Package.swift:', err);
279
+ snippet['{content}'] = codeList;
280
+ saveFromFile(specFile, snippet);
173
281
  });
174
282
  } else {
175
283
  snippet['{content}'] = codeList;
@@ -222,7 +330,8 @@ function saveFromFile(specFile, snippet) {
222
330
  console.log(err);
223
331
  }
224
332
  cache.updateCache(specFile, content);
225
- install.addCodeSnippets(specFile);
333
+ // ✅ 只写入刚创建的代码片段,而不是所有代码片段
334
+ install.addCodeSnippets(specFile, snippet);
226
335
  }
227
336
  }
228
337
  }
@@ -258,4 +367,5 @@ function escapeString(string) {
258
367
 
259
368
  exports.createCodeSnippets = createCodeSnippets;
260
369
  exports.updateCodeSnippets = updateCodeSnippets;
261
- exports.saveFromFile = saveFromFile;
370
+ exports.saveFromFile = saveFromFile;
371
+ exports.findFilesWithACode = findFilesWithACode;