zengen 0.1.36 → 0.2.0

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 (153) hide show
  1. package/.github/workflows/pages.yml +1 -1
  2. package/.zen/meta.json +128 -30
  3. package/.zen/src/en-US/01d04f7c17b4a541ead9d759d877b30b403e15b849182a49eb1f62bd29ecd18c.md +120 -0
  4. package/.zen/src/en-US/1b798c44a4f353e47296ca83d5905e37e6aba3e90bbd9bc3b3d34fc12059a2ca.md +75 -0
  5. package/.zen/src/en-US/1e96be58d76c60056b708eb5bd8b8b81d7b5845d9cfe0b879d85068a5f11df3a.md +189 -0
  6. package/.zen/src/en-US/5ec990146b35e00de2630559126ee07f7cdcddeb23b0e8cab3d85b4181353e26.md +53 -0
  7. package/.zen/src/en-US/6124ea88edec5bde737b26b21f71ecfeffe4e73151784856edf813ee231a4baa.md +11 -0
  8. package/.zen/src/en-US/80ae9bed74fc6348a7c1fe9f33e86b65f5d919169721f77bcf0e1bc29fbdb4f9.md +61 -0
  9. package/.zen/src/en-US/f0c2799126931ccd113a0c45b1e623870b0d4f4f400becf6dd877da8f1011517.md +41 -0
  10. package/.zen/src/en-US/fdfca9b960d0eaa8b2b96fe988ead7481d2c0b16f66ebc94fb477139b4178cdc.md +65 -0
  11. package/.zen/src/zh-Hans/01d04f7c17b4a541ead9d759d877b30b403e15b849182a49eb1f62bd29ecd18c.md +120 -0
  12. package/.zen/src/zh-Hans/1b798c44a4f353e47296ca83d5905e37e6aba3e90bbd9bc3b3d34fc12059a2ca.md +77 -0
  13. package/.zen/src/zh-Hans/1e96be58d76c60056b708eb5bd8b8b81d7b5845d9cfe0b879d85068a5f11df3a.md +189 -0
  14. package/.zen/src/zh-Hans/5ec990146b35e00de2630559126ee07f7cdcddeb23b0e8cab3d85b4181353e26.md +55 -0
  15. package/.zen/src/zh-Hans/6124ea88edec5bde737b26b21f71ecfeffe4e73151784856edf813ee231a4baa.md +1 -0
  16. package/.zen/src/zh-Hans/6ad8db715a1b60613fe934fefb29fa981ecad9b63145593accff144d73b44bde.md +175 -0
  17. package/.zen/src/zh-Hans/80ae9bed74fc6348a7c1fe9f33e86b65f5d919169721f77bcf0e1bc29fbdb4f9.md +63 -0
  18. package/.zen/src/zh-Hans/a1580f71c6c6c1ff4a314be72d410a8507af2f087d56360c7f5048d349c21953.md +48 -0
  19. package/.zen/src/zh-Hans/d49012f98c4367b34034063400e2f7826bf0615952210c82396920172d468e2c.md +107 -0
  20. package/.zen/src/zh-Hans/f0c2799126931ccd113a0c45b1e623870b0d4f4f400becf6dd877da8f1011517.md +41 -0
  21. package/.zen/src/zh-Hans/fdfca9b960d0eaa8b2b96fe988ead7481d2c0b16f66ebc94fb477139b4178cdc.md +65 -0
  22. package/assets/templates/default/layout.html +274 -0
  23. package/dist/ai/extractMetadataFromMarkdown.d.ts +8 -0
  24. package/dist/ai/extractMetadataFromMarkdown.d.ts.map +1 -0
  25. package/dist/ai/extractMetadataFromMarkdown.js +88 -0
  26. package/dist/ai/extractMetadataFromMarkdown.js.map +1 -0
  27. package/dist/ai/translateMarkdown.d.ts +8 -0
  28. package/dist/ai/translateMarkdown.d.ts.map +1 -0
  29. package/dist/ai/translateMarkdown.js +29 -0
  30. package/dist/ai/translateMarkdown.js.map +1 -0
  31. package/dist/build/pipeline.d.ts +6 -0
  32. package/dist/build/pipeline.d.ts.map +1 -0
  33. package/dist/build/pipeline.js +218 -0
  34. package/dist/build/pipeline.js.map +1 -0
  35. package/dist/cli.js +10 -118
  36. package/dist/cli.js.map +1 -1
  37. package/dist/findEntries.d.ts +10 -0
  38. package/dist/findEntries.d.ts.map +1 -0
  39. package/dist/findEntries.js +38 -0
  40. package/dist/findEntries.js.map +1 -0
  41. package/dist/index.d.ts +1 -32
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -35
  44. package/dist/index.js.map +1 -1
  45. package/dist/metadata.d.ts +14 -0
  46. package/dist/metadata.d.ts.map +1 -0
  47. package/dist/metadata.js +78 -0
  48. package/dist/metadata.js.map +1 -0
  49. package/dist/paths.d.ts +6 -0
  50. package/dist/paths.d.ts.map +1 -0
  51. package/dist/paths.js +10 -0
  52. package/dist/paths.js.map +1 -0
  53. package/dist/process/extractMetadataByAI.d.ts +5 -0
  54. package/dist/process/extractMetadataByAI.d.ts.map +1 -0
  55. package/dist/process/extractMetadataByAI.js +31 -0
  56. package/dist/process/extractMetadataByAI.js.map +1 -0
  57. package/dist/process/template.d.ts +5 -0
  58. package/dist/process/template.d.ts.map +1 -0
  59. package/dist/process/template.js +188 -0
  60. package/dist/process/template.js.map +1 -0
  61. package/dist/scan/files.d.ts +7 -0
  62. package/dist/scan/files.d.ts.map +1 -0
  63. package/dist/scan/files.js +54 -0
  64. package/dist/scan/files.js.map +1 -0
  65. package/dist/services/openai.d.ts +41 -0
  66. package/dist/services/openai.d.ts.map +1 -0
  67. package/dist/services/openai.js +54 -0
  68. package/dist/services/openai.js.map +1 -0
  69. package/dist/types.d.ts +16 -67
  70. package/dist/types.d.ts.map +1 -1
  71. package/dist/utils/convertMarkdownToHtml.d.ts +7 -0
  72. package/dist/utils/convertMarkdownToHtml.d.ts.map +1 -0
  73. package/dist/utils/convertMarkdownToHtml.js +39 -0
  74. package/dist/utils/convertMarkdownToHtml.js.map +1 -0
  75. package/dist/utils/frontmatter.d.ts +6 -0
  76. package/dist/utils/frontmatter.d.ts.map +1 -0
  77. package/dist/utils/frontmatter.js +22 -0
  78. package/dist/utils/frontmatter.js.map +1 -0
  79. package/docs/deployment/github-pages.md +1 -2
  80. package/docs/guides/best-practices.md +4 -4
  81. package/docs/guides/config.md +0 -5
  82. package/package.json +4 -2
  83. package/src/ai/extractMetadataFromMarkdown.ts +95 -0
  84. package/src/ai/translateMarkdown.ts +29 -0
  85. package/src/build/pipeline.ts +211 -0
  86. package/src/cli.ts +10 -132
  87. package/src/findEntries.ts +37 -0
  88. package/src/index.ts +1 -40
  89. package/src/metadata.ts +44 -0
  90. package/src/paths.ts +7 -0
  91. package/src/process/extractMetadataByAI.ts +29 -0
  92. package/src/process/template.ts +201 -0
  93. package/src/scan/files.ts +17 -0
  94. package/src/services/openai.ts +92 -0
  95. package/src/types.ts +18 -72
  96. package/src/utils/convertMarkdownToHtml.ts +32 -0
  97. package/src/utils/frontmatter.ts +18 -0
  98. package/.zen/translations.json +0 -51
  99. package/dist/ai-client.d.ts +0 -34
  100. package/dist/ai-client.d.ts.map +0 -1
  101. package/dist/ai-client.js +0 -180
  102. package/dist/ai-client.js.map +0 -1
  103. package/dist/ai-processor.d.ts +0 -51
  104. package/dist/ai-processor.d.ts.map +0 -1
  105. package/dist/ai-processor.js +0 -215
  106. package/dist/ai-processor.js.map +0 -1
  107. package/dist/ai-service.d.ts +0 -79
  108. package/dist/ai-service.d.ts.map +0 -1
  109. package/dist/ai-service.js +0 -257
  110. package/dist/ai-service.js.map +0 -1
  111. package/dist/builder.d.ts +0 -70
  112. package/dist/builder.d.ts.map +0 -1
  113. package/dist/builder.js +0 -854
  114. package/dist/builder.js.map +0 -1
  115. package/dist/gitignore.d.ts +0 -41
  116. package/dist/gitignore.d.ts.map +0 -1
  117. package/dist/gitignore.js +0 -202
  118. package/dist/gitignore.js.map +0 -1
  119. package/dist/gitignore.test.d.ts +0 -2
  120. package/dist/gitignore.test.d.ts.map +0 -1
  121. package/dist/gitignore.test.js +0 -309
  122. package/dist/gitignore.test.js.map +0 -1
  123. package/dist/markdown.d.ts +0 -35
  124. package/dist/markdown.d.ts.map +0 -1
  125. package/dist/markdown.js +0 -221
  126. package/dist/markdown.js.map +0 -1
  127. package/dist/navigation.d.ts +0 -46
  128. package/dist/navigation.d.ts.map +0 -1
  129. package/dist/navigation.js +0 -196
  130. package/dist/navigation.js.map +0 -1
  131. package/dist/scanner.d.ts +0 -26
  132. package/dist/scanner.d.ts.map +0 -1
  133. package/dist/scanner.js +0 -190
  134. package/dist/scanner.js.map +0 -1
  135. package/dist/template.d.ts +0 -33
  136. package/dist/template.d.ts.map +0 -1
  137. package/dist/template.js +0 -434
  138. package/dist/template.js.map +0 -1
  139. package/dist/translation-service.d.ts +0 -72
  140. package/dist/translation-service.d.ts.map +0 -1
  141. package/dist/translation-service.js +0 -291
  142. package/dist/translation-service.js.map +0 -1
  143. package/src/ai-client.ts +0 -227
  144. package/src/ai-processor.ts +0 -243
  145. package/src/ai-service.ts +0 -281
  146. package/src/builder.ts +0 -991
  147. package/src/gitignore.test.ts +0 -318
  148. package/src/gitignore.ts +0 -193
  149. package/src/markdown.ts +0 -212
  150. package/src/navigation.ts +0 -237
  151. package/src/scanner.ts +0 -180
  152. package/src/template.ts +0 -425
  153. package/src/translation-service.ts +0 -350
@@ -1,318 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from 'node:test';
2
- import assert from 'node:assert';
3
- import * as fs from 'fs/promises';
4
- import * as path from 'path';
5
- import { GitIgnoreProcessor, createGitIgnoreProcessor } from './gitignore.js';
6
-
7
- describe('GitIgnoreProcessor', () => {
8
- let testDir: string;
9
- let gitignorePath: string;
10
-
11
- beforeEach(async () => {
12
- // 创建临时测试目录
13
- testDir = path.join(__dirname, 'test-temp');
14
- gitignorePath = path.join(testDir, '.gitignore');
15
-
16
- try {
17
- await fs.mkdir(testDir, { recursive: true });
18
- } catch (error) {
19
- // 目录可能已存在
20
- }
21
- });
22
-
23
- afterEach(async () => {
24
- // 清理测试目录
25
- try {
26
- await fs.rm(testDir, { recursive: true, force: true });
27
- } catch (error) {
28
- // 忽略清理错误
29
- }
30
- });
31
-
32
- describe('constructor', () => {
33
- it('应该正确设置baseDir', () => {
34
- const processor = new GitIgnoreProcessor('/test/dir');
35
- assert.strictEqual(processor['baseDir'], '/test/dir');
36
- });
37
-
38
- it('应该初始化包含硬编码模式的数组', () => {
39
- const processor = new GitIgnoreProcessor('/test/dir');
40
- const patterns = processor.getPatterns();
41
- // 检查是否包含硬编码模式
42
- assert.ok(patterns.includes('node_modules'));
43
- assert.ok(patterns.includes('**/node_modules'));
44
- assert.ok(patterns.includes('.git'));
45
- assert.ok(patterns.includes('.zen'));
46
- });
47
- });
48
-
49
- describe('loadFromFile', () => {
50
- it('应该从.gitignore文件加载模式', async () => {
51
- const gitignoreContent = `
52
- # 注释行
53
- node_modules/
54
- *.log
55
- dist/
56
- .DS_Store
57
- `;
58
- await fs.writeFile(gitignorePath, gitignoreContent);
59
-
60
- const processor = new GitIgnoreProcessor(testDir);
61
- await processor.loadFromFile('.gitignore');
62
-
63
- const patterns = processor.getPatterns();
64
- // 应该包含硬编码模式和从.gitignore加载的模式
65
- assert.ok(patterns.includes('node_modules')); // 硬编码
66
- assert.ok(patterns.includes('**/node_modules')); // 从.gitignore加载
67
- assert.ok(patterns.includes('*.log')); // 从.gitignore加载
68
- assert.ok(patterns.includes('**/dist')); // 从.gitignore加载
69
- assert.ok(patterns.includes('**/.DS_Store')); // 从.gitignore加载
70
- assert.ok(patterns.includes('.git')); // 硬编码
71
- assert.ok(patterns.includes('.zen')); // 硬编码
72
- });
73
-
74
- it('当.gitignore文件不存在时应该使用硬编码模式', async () => {
75
- const processor = new GitIgnoreProcessor(testDir);
76
- await processor.loadFromFile('non-existent-file');
77
-
78
- const patterns = processor.getPatterns();
79
- // 应该只包含硬编码模式
80
- assert.ok(patterns.includes('node_modules'));
81
- assert.ok(patterns.includes('**/node_modules'));
82
- assert.ok(patterns.includes('.git'));
83
- assert.ok(patterns.includes('.zen'));
84
- // 不应该有用户定义的模式
85
- assert.ok(!patterns.includes('*.log'));
86
- });
87
-
88
- it('应该跳过空行和注释', async () => {
89
- const gitignoreContent = `
90
- # 这是一个注释
91
-
92
- node_modules/
93
-
94
- # 另一个注释
95
- *.log
96
- `;
97
- await fs.writeFile(gitignorePath, gitignoreContent);
98
-
99
- const processor = new GitIgnoreProcessor(testDir);
100
- await processor.loadFromFile('.gitignore');
101
-
102
- const patterns = processor.getPatterns();
103
- // 应该包含硬编码模式和从.gitignore加载的模式
104
- assert.ok(patterns.includes('node_modules')); // 硬编码
105
- assert.ok(patterns.includes('**/node_modules')); // 从.gitignore加载
106
- assert.ok(patterns.includes('*.log')); // 从.gitignore加载
107
- assert.ok(patterns.includes('.git')); // 硬编码
108
- assert.ok(patterns.includes('.zen')); // 硬编码
109
- });
110
-
111
- it('应该跳过否定模式', async () => {
112
- const gitignoreContent = `
113
- node_modules/
114
- !node_modules/special/
115
- *.log
116
- `;
117
- await fs.writeFile(gitignorePath, gitignoreContent);
118
-
119
- const processor = new GitIgnoreProcessor(testDir);
120
- await processor.loadFromFile('.gitignore');
121
-
122
- const patterns = processor.getPatterns();
123
- // 应该包含硬编码模式和从.gitignore加载的模式(不包括否定模式)
124
- assert.ok(patterns.includes('node_modules')); // 硬编码
125
- assert.ok(patterns.includes('**/node_modules')); // 从.gitignore加载
126
- assert.ok(patterns.includes('*.log')); // 从.gitignore加载
127
- assert.ok(patterns.includes('.git')); // 硬编码
128
- assert.ok(patterns.includes('.zen')); // 硬编码
129
- });
130
- });
131
-
132
- describe('parsePatterns', () => {
133
- it('应该正确处理目录模式', () => {
134
- const processor = new GitIgnoreProcessor(testDir);
135
- const content = `
136
- node_modules/
137
- dist/
138
- `;
139
- processor['parsePatterns'](content);
140
-
141
- const patterns = processor.getPatterns();
142
- // 应该包含硬编码模式和解析的模式
143
- assert.ok(patterns.includes('node_modules')); // 硬编码
144
- assert.ok(patterns.includes('**/node_modules')); // 从内容解析
145
- assert.ok(patterns.includes('**/dist')); // 从内容解析
146
- assert.ok(patterns.includes('.git')); // 硬编码
147
- assert.ok(patterns.includes('.zen')); // 硬编码
148
- });
149
-
150
- it('应该正确处理文件扩展名模式', () => {
151
- const processor = new GitIgnoreProcessor(testDir);
152
- const content = `
153
- *.log
154
- *.tmp
155
- `;
156
- processor['parsePatterns'](content);
157
-
158
- const patterns = processor.getPatterns();
159
- // 应该包含硬编码模式和解析的模式
160
- assert.ok(patterns.includes('node_modules')); // 硬编码
161
- assert.ok(patterns.includes('*.log')); // 从内容解析
162
- assert.ok(patterns.includes('*.tmp')); // 从内容解析
163
- assert.ok(patterns.includes('.git')); // 硬编码
164
- assert.ok(patterns.includes('.zen')); // 硬编码
165
- });
166
-
167
- it('应该处理以/开头的模式', () => {
168
- const processor = new GitIgnoreProcessor(testDir);
169
- const content = `
170
- /node_modules
171
- /dist
172
- `;
173
- processor['parsePatterns'](content);
174
-
175
- const patterns = processor.getPatterns();
176
- // 应该包含硬编码模式和解析的模式
177
- assert.ok(patterns.includes('node_modules')); // 硬编码
178
- assert.ok(patterns.includes('dist')); // 从内容解析
179
- assert.ok(patterns.includes('.git')); // 硬编码
180
- assert.ok(patterns.includes('.zen')); // 硬编码
181
- });
182
-
183
- it('应该处理包含通配符的模式', () => {
184
- const processor = new GitIgnoreProcessor(testDir);
185
- const content = `
186
- **/node_modules
187
- **/.vscode
188
- `;
189
- processor['parsePatterns'](content);
190
-
191
- const patterns = processor.getPatterns();
192
- // 应该包含硬编码模式和解析的模式
193
- assert.ok(patterns.includes('node_modules')); // 硬编码
194
- assert.ok(patterns.includes('**/node_modules')); // 从内容解析
195
- assert.ok(patterns.includes('**/.vscode')); // 从内容解析
196
- assert.ok(patterns.includes('.git')); // 硬编码
197
- assert.ok(patterns.includes('.zen')); // 硬编码
198
- });
199
- });
200
-
201
- describe('shouldIgnore', () => {
202
- let processor: GitIgnoreProcessor;
203
-
204
- beforeEach(() => {
205
- processor = new GitIgnoreProcessor(testDir);
206
- });
207
-
208
- it('应该忽略匹配的文件', () => {
209
- processor.addPattern('**/*.log');
210
- processor.addPattern('**/node_modules');
211
-
212
- const logFile = path.join(testDir, 'app.log');
213
- const nodeModulesFile = path.join(testDir, 'node_modules', 'package.json');
214
-
215
- assert.strictEqual(processor.shouldIgnore(logFile), true);
216
- assert.strictEqual(processor.shouldIgnore(nodeModulesFile), true);
217
- });
218
-
219
- it('不应该忽略不匹配的文件', () => {
220
- processor.addPattern('**/*.log');
221
- processor.addPattern('**/node_modules');
222
-
223
- const textFile = path.join(testDir, 'readme.txt');
224
- const srcFile = path.join(testDir, 'src', 'index.ts');
225
-
226
- assert.strictEqual(processor.shouldIgnore(textFile), false);
227
- assert.strictEqual(processor.shouldIgnore(srcFile), false);
228
- });
229
-
230
- it('当文件在baseDir之外时不应该忽略', () => {
231
- processor.addPattern('**/*.log');
232
-
233
- const outsideFile = path.join('/outside', 'dir', 'app.log');
234
- assert.strictEqual(processor.shouldIgnore(outsideFile), false);
235
- });
236
-
237
- it('应该正确处理点文件', () => {
238
- processor.addPattern('**/.DS_Store');
239
- processor.addPattern('**/.vscode');
240
-
241
- const dsStoreFile = path.join(testDir, '.DS_Store');
242
- const vscodeFile = path.join(testDir, '.vscode', 'settings.json');
243
-
244
- assert.strictEqual(processor.shouldIgnore(dsStoreFile), true);
245
- assert.strictEqual(processor.shouldIgnore(vscodeFile), true);
246
- });
247
-
248
- it('应该正确处理目录模式', () => {
249
- processor.addPattern('node_modules/');
250
- processor.addPattern('dist/');
251
-
252
- const nodeModulesFile = path.join(testDir, 'node_modules', 'package.json');
253
- const distFile = path.join(testDir, 'dist', 'index.js');
254
- const srcFile = path.join(testDir, 'src', 'index.ts');
255
-
256
- assert.strictEqual(processor.shouldIgnore(nodeModulesFile), true);
257
- assert.strictEqual(processor.shouldIgnore(distFile), true);
258
- assert.strictEqual(processor.shouldIgnore(srcFile), false);
259
- });
260
- });
261
-
262
- describe('addPattern and clearPatterns', () => {
263
- it('应该能够添加自定义模式', () => {
264
- const processor = new GitIgnoreProcessor(testDir);
265
-
266
- processor.addPattern('custom-pattern');
267
- const patterns = processor.getPatterns();
268
- // 应该包含硬编码模式和自定义模式
269
- assert.ok(patterns.includes('node_modules')); // 硬编码
270
- assert.ok(patterns.includes('custom-pattern')); // 自定义
271
-
272
- processor.addPattern('another-pattern');
273
- const updatedPatterns = processor.getPatterns();
274
- assert.ok(updatedPatterns.includes('node_modules')); // 硬编码
275
- assert.ok(updatedPatterns.includes('custom-pattern')); // 自定义
276
- assert.ok(updatedPatterns.includes('another-pattern')); // 自定义
277
- });
278
-
279
- it('应该能够清除所有用户模式(但保留硬编码模式)', () => {
280
- const processor = new GitIgnoreProcessor(testDir);
281
-
282
- processor.addPattern('pattern1');
283
- processor.addPattern('pattern2');
284
- // 总模式数 = 硬编码模式数 + 用户模式数
285
- const totalPatterns = processor.getPatterns().length;
286
- assert.ok(totalPatterns >= 2); // 至少包含硬编码模式
287
-
288
- processor.clearPatterns();
289
- const patternsAfterClear = processor.getPatterns();
290
- // 清除后应该只包含硬编码模式
291
- assert.ok(patternsAfterClear.includes('node_modules'));
292
- assert.ok(patternsAfterClear.includes('.git'));
293
- assert.ok(patternsAfterClear.includes('.zen'));
294
- assert.ok(!patternsAfterClear.includes('pattern1'));
295
- assert.ok(!patternsAfterClear.includes('pattern2'));
296
- });
297
- });
298
-
299
- describe('createGitIgnoreProcessor', () => {
300
- it('应该创建处理器并加载.gitignore文件', async () => {
301
- const gitignoreContent = `
302
- node_modules/
303
- *.log
304
- `;
305
- await fs.writeFile(gitignorePath, gitignoreContent);
306
-
307
- const processor = await createGitIgnoreProcessor(testDir);
308
- const patterns = processor.getPatterns();
309
-
310
- // 应该包含硬编码模式和从.gitignore加载的模式
311
- assert.ok(patterns.includes('node_modules')); // 硬编码
312
- assert.ok(patterns.includes('**/node_modules')); // 从.gitignore加载
313
- assert.ok(patterns.includes('*.log')); // 从.gitignore加载
314
- assert.ok(patterns.includes('.git')); // 硬编码
315
- assert.ok(patterns.includes('.zen')); // 硬编码
316
- });
317
- });
318
- });
package/src/gitignore.ts DELETED
@@ -1,193 +0,0 @@
1
- import * as fs from 'fs/promises';
2
- import * as path from 'path';
3
- import { minimatch } from 'minimatch';
4
-
5
- /**
6
- * GitIgnore 处理器
7
- * 用于读取和解析 .gitignore 文件,并提供文件过滤功能
8
- */
9
- export class GitIgnoreProcessor {
10
- private patterns: string[] = [];
11
- private baseDir: string;
12
-
13
- // 始终忽略的硬编码模式列表
14
- private readonly hardcodedPatterns: string[] = [
15
- 'node_modules', // Node.js 依赖目录
16
- '**/node_modules', // 任意深度的 node_modules
17
- '**/node_modules/**', // node_modules 中的所有内容
18
- '.git', // Git 目录
19
- '**/.git', // 任意深度的 .git 目录
20
- '**/.git/**', // .git 目录中的所有内容
21
- '.zen', // ZEN 构建输出目录
22
- '**/.zen', // 任意深度的 .zen 目录
23
- '**/.zen/**', // .zen 目录中的所有内容
24
- ];
25
-
26
- constructor(baseDir: string) {
27
- this.baseDir = baseDir;
28
- }
29
-
30
- /**
31
- * 从 .gitignore 文件加载模式
32
- */
33
- async loadFromFile(gitignorePath: string = '.gitignore'): Promise<void> {
34
- try {
35
- const fullPath = path.join(this.baseDir, gitignorePath);
36
- const content = await fs.readFile(fullPath, 'utf-8');
37
- this.parsePatterns(content);
38
- } catch (error) {
39
- // 如果 .gitignore 文件不存在,使用空模式
40
- console.debug(`No .gitignore file found at ${gitignorePath}, using empty patterns`);
41
- }
42
- }
43
-
44
- /**
45
- * 解析 .gitignore 内容为模式数组
46
- */
47
- private parsePatterns(content: string): void {
48
- const lines = content.split('\n');
49
- this.patterns = [];
50
-
51
- for (let line of lines) {
52
- line = line.trim();
53
-
54
- // 跳过空行和注释
55
- if (!line || line.startsWith('#')) {
56
- continue;
57
- }
58
-
59
- // 处理否定模式(以 ! 开头)
60
- if (line.startsWith('!')) {
61
- // 暂时不支持否定模式,可以后续扩展
62
- continue;
63
- }
64
-
65
- // 标准化模式
66
- let pattern = line;
67
-
68
- // 如果模式以 / 结尾,表示目录
69
- if (pattern.endsWith('/')) {
70
- pattern = pattern.slice(0, -1);
71
- }
72
-
73
- // 如果模式不以 * 开头,添加 **/ 前缀以匹配任意子目录
74
- if (!pattern.includes('*') && !pattern.startsWith('/')) {
75
- pattern = `**/${pattern}`;
76
- }
77
-
78
- // 如果模式以 / 开头,从根目录开始匹配
79
- if (pattern.startsWith('/')) {
80
- pattern = pattern.slice(1);
81
- }
82
-
83
- this.patterns.push(pattern);
84
- }
85
-
86
- console.debug(`Loaded ${this.patterns.length} patterns from .gitignore`);
87
- }
88
-
89
- /**
90
- * 检查文件是否应该被忽略
91
- * @param filePath 文件的绝对路径
92
- * @returns 如果应该被忽略返回 true
93
- */
94
- shouldIgnore(filePath: string): boolean {
95
- // 获取相对于 baseDir 的相对路径
96
- const relativePath = path.relative(this.baseDir, filePath);
97
-
98
- // 如果文件在 baseDir 之外,不应用规则
99
- if (relativePath.startsWith('..')) {
100
- return false;
101
- }
102
-
103
- // 标准化路径分隔符为 /
104
- const normalizedPath = relativePath.replace(/\\/g, '/');
105
-
106
- // 首先检查硬编码模式(始终忽略)
107
- for (const pattern of this.hardcodedPatterns) {
108
- if (minimatch(normalizedPath, pattern, { dot: true })) {
109
- return true;
110
- }
111
- }
112
-
113
- // 然后检查用户定义的 .gitignore 模式
114
- for (const pattern of this.patterns) {
115
- // 首先尝试直接匹配
116
- if (minimatch(normalizedPath, pattern, { dot: true })) {
117
- return true;
118
- }
119
-
120
- // 对于目录模式,检查文件是否在该目录下
121
- // 目录模式通常以 / 结尾或没有扩展名
122
- if (pattern.endsWith('/') || (!pattern.includes('.') && !pattern.includes('*'))) {
123
- const dirPattern = pattern.endsWith('/') ? pattern.slice(0, -1) : pattern;
124
-
125
- // 检查文件是否在目录中
126
- if (normalizedPath.startsWith(dirPattern + '/')) {
127
- return true;
128
- }
129
-
130
- // 检查是否就是目录本身
131
- if (normalizedPath === dirPattern) {
132
- return true;
133
- }
134
- }
135
-
136
- // 对于包含通配符的目录模式(如 **/node_modules, **/.vscode)
137
- // 提取目录名并检查
138
- if (pattern.includes('*')) {
139
- // 尝试提取目录名(最后一个非通配符部分)
140
- const parts = pattern.split('/');
141
- const lastPart = parts[parts.length - 1];
142
-
143
- // 如果最后一部分不包含通配符,可能是目录名
144
- // 注意:.vscode 以点开头,但仍然是目录名
145
- if (!lastPart.includes('*')) {
146
- // 检查是否是文件扩展名(包含点但不是以点开头的目录)
147
- const hasFileExtension = lastPart.includes('.') && !lastPart.startsWith('.');
148
-
149
- if (!hasFileExtension) {
150
- if (normalizedPath.startsWith(lastPart + '/')) {
151
- return true;
152
- }
153
- if (normalizedPath === lastPart) {
154
- return true;
155
- }
156
- }
157
- }
158
- }
159
- }
160
-
161
- return false;
162
- }
163
-
164
- /**
165
- * 获取所有忽略模式(包括硬编码模式)
166
- */
167
- getPatterns(): string[] {
168
- return [...this.hardcodedPatterns, ...this.patterns];
169
- }
170
-
171
- /**
172
- * 添加自定义忽略模式
173
- */
174
- addPattern(pattern: string): void {
175
- this.patterns.push(pattern);
176
- }
177
-
178
- /**
179
- * 清除所有模式
180
- */
181
- clearPatterns(): void {
182
- this.patterns = [];
183
- }
184
- }
185
-
186
- /**
187
- * 创建 GitIgnoreProcessor 实例并加载 .gitignore 文件
188
- */
189
- export async function createGitIgnoreProcessor(baseDir: string): Promise<GitIgnoreProcessor> {
190
- const processor = new GitIgnoreProcessor(baseDir);
191
- await processor.loadFromFile();
192
- return processor;
193
- }