@termdock/twlint 1.0.0 → 1.0.1

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 (53) hide show
  1. package/README.md +176 -63
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +49 -10
  4. package/dist/cli.js.map +1 -1
  5. package/dist/core/config-schema.d.ts +1 -0
  6. package/dist/core/config-schema.d.ts.map +1 -1
  7. package/dist/core/config-schema.js +33 -7
  8. package/dist/core/config-schema.js.map +1 -1
  9. package/dist/core/dictionary-loading-strategies.d.ts +45 -0
  10. package/dist/core/dictionary-loading-strategies.d.ts.map +1 -0
  11. package/dist/core/dictionary-loading-strategies.js +75 -0
  12. package/dist/core/dictionary-loading-strategies.js.map +1 -0
  13. package/dist/core/dictionary-manager.d.ts +2 -1
  14. package/dist/core/dictionary-manager.d.ts.map +1 -1
  15. package/dist/core/dictionary-manager.js +51 -16
  16. package/dist/core/dictionary-manager.js.map +1 -1
  17. package/dist/core/linter.d.ts +2 -6
  18. package/dist/core/linter.d.ts.map +1 -1
  19. package/dist/core/linter.js +82 -58
  20. package/dist/core/linter.js.map +1 -1
  21. package/dist/core/lru-cache.d.ts +18 -0
  22. package/dist/core/lru-cache.d.ts.map +1 -0
  23. package/dist/core/lru-cache.js +57 -0
  24. package/dist/core/lru-cache.js.map +1 -0
  25. package/dist/core/matching/match-strategies.d.ts +19 -11
  26. package/dist/core/matching/match-strategies.d.ts.map +1 -1
  27. package/dist/core/matching/match-strategies.js +44 -74
  28. package/dist/core/matching/match-strategies.js.map +1 -1
  29. package/dist/core/rules/mainland-terms.d.ts +3 -1
  30. package/dist/core/rules/mainland-terms.d.ts.map +1 -1
  31. package/dist/core/rules/mainland-terms.js +25 -4
  32. package/dist/core/rules/mainland-terms.js.map +1 -1
  33. package/dist/dictionaries/academic.json +242 -22
  34. package/dist/dictionaries/ai-emerging-tech.json +3209 -0
  35. package/dist/dictionaries/business-finance.json +3449 -0
  36. package/dist/dictionaries/core.json +2902 -248
  37. package/dist/dictionaries/hardware-3c.json +2649 -0
  38. package/dist/dictionaries/index.json +70 -8
  39. package/dist/dictionaries/network-cloud.json +2953 -0
  40. package/dist/dictionaries/operating-system.json +2889 -0
  41. package/dist/dictionaries/social-media.json +2833 -0
  42. package/dist/dictionaries/software-development.json +3809 -0
  43. package/dist/dictionaries/user-interface.json +3225 -0
  44. package/dist/formatters/stylish.d.ts.map +1 -1
  45. package/dist/formatters/stylish.js +5 -15
  46. package/dist/formatters/stylish.js.map +1 -1
  47. package/dist/types.d.ts +20 -8
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/utils/error-utils.d.ts +9 -0
  50. package/dist/utils/error-utils.d.ts.map +1 -0
  51. package/dist/utils/error-utils.js +15 -0
  52. package/dist/utils/error-utils.js.map +1 -0
  53. package/package.json +5 -5
@@ -0,0 +1,75 @@
1
+ /**
2
+ * 詞庫載入策略 - 消除 linter.ts 中的特殊情況處理
3
+ */
4
+ /**
5
+ * 基本策略:只載入核心詞庫
6
+ */
7
+ export class CoreDictStrategy {
8
+ async getDictionaries() {
9
+ return ['core'];
10
+ }
11
+ }
12
+ /**
13
+ * 自訂詞庫策略:載入用戶指定的詞庫
14
+ */
15
+ export class CustomDictStrategy {
16
+ dictionaries;
17
+ constructor(dictionaries) {
18
+ this.dictionaries = dictionaries;
19
+ }
20
+ async getDictionaries() {
21
+ return this.dictionaries;
22
+ }
23
+ }
24
+ /**
25
+ * 領域策略:載入指定領域的詞庫(包含核心詞庫)
26
+ */
27
+ export class DomainDictStrategy {
28
+ domains;
29
+ constructor(domains) {
30
+ this.domains = domains;
31
+ }
32
+ async getDictionaries() {
33
+ const dictNames = [...this.domains];
34
+ if (!dictNames.includes('core')) {
35
+ dictNames.unshift('core');
36
+ }
37
+ return dictNames;
38
+ }
39
+ }
40
+ /**
41
+ * 深度策略:載入所有可用詞庫
42
+ */
43
+ export class DeepDictStrategy {
44
+ baseStrategy;
45
+ constructor(baseStrategy) {
46
+ this.baseStrategy = baseStrategy;
47
+ }
48
+ async getDictionaries(config, manager) {
49
+ const baseDicts = await this.baseStrategy.getDictionaries(config, manager);
50
+ const availableDicts = await manager.scanAvailableDictionaries();
51
+ return [...new Set([...baseDicts, ...availableDicts])];
52
+ }
53
+ }
54
+ /**
55
+ * 策略工廠:根據配置選擇適當的策略
56
+ */
57
+ export class DictLoadStrategyFactory {
58
+ static create(config, deep) {
59
+ let baseStrategy;
60
+ if (config.domains) {
61
+ baseStrategy = new DomainDictStrategy(config.domains);
62
+ }
63
+ else if (config.dictionaries) {
64
+ baseStrategy = new CustomDictStrategy(config.dictionaries);
65
+ }
66
+ else {
67
+ baseStrategy = new CoreDictStrategy();
68
+ }
69
+ if (deep) {
70
+ return new DeepDictStrategy(baseStrategy);
71
+ }
72
+ return baseStrategy;
73
+ }
74
+ }
75
+ //# sourceMappingURL=dictionary-loading-strategies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictionary-loading-strategies.js","sourceRoot":"","sources":["../../src/core/dictionary-loading-strategies.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAC3B,KAAK,CAAC,eAAe;QACnB,OAAO,CAAC,MAAM,CAAC,CAAA;IACjB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,kBAAkB;IACT;IAApB,YAAoB,YAAsB;QAAtB,iBAAY,GAAZ,YAAY,CAAU;IAAG,CAAC;IAE9C,KAAK,CAAC,eAAe;QACnB,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,kBAAkB;IACT;IAApB,YAAoB,OAAiB;QAAjB,YAAO,GAAP,OAAO,CAAU;IAAG,CAAC;IAEzC,KAAK,CAAC,eAAe;QACnB,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;QACnC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAC3B,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACP;IAApB,YAAoB,YAA8B;QAA9B,iBAAY,GAAZ,YAAY,CAAkB;IAAG,CAAC;IAEtD,KAAK,CAAC,eAAe,CAAC,MAAoB,EAAE,OAA0B;QACpE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC1E,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,yBAAyB,EAAE,CAAA;QAChE,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAAA;IACxD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,uBAAuB;IAClC,MAAM,CAAC,MAAM,CAAC,MAAoB,EAAE,IAAc;QAChD,IAAI,YAA8B,CAAA;QAElC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,YAAY,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACvD,CAAC;aAAM,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YAC/B,YAAY,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QAC5D,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,IAAI,gBAAgB,EAAE,CAAA;QACvC,CAAC;QAED,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,IAAI,gBAAgB,CAAC,YAAY,CAAC,CAAA;QAC3C,CAAC;QAED,OAAO,YAAY,CAAA;IACrB,CAAC;CACF"}
@@ -3,9 +3,10 @@ export declare class DictionaryManager {
3
3
  private cache;
4
4
  private readonly dictionariesPath;
5
5
  private readonly strategyRegistry;
6
- constructor(dictionariesPath?: string);
6
+ constructor(dictionariesPath?: string, maxCacheSize?: number);
7
7
  loadDictionary(name: string): Promise<CompiledDict>;
8
8
  findMatches(text: string): MatchResult[];
9
+ private addMatchWithPriority;
9
10
  scanAvailableDictionaries(): Promise<string[]>;
10
11
  getLoadedDictionaries(): string[];
11
12
  clearCache(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"dictionary-manager.d.ts","sourceRoot":"","sources":["../../src/core/dictionary-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAa,WAAW,EAAE,MAAM,aAAa,CAAA;AAGvE,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuB;gBAE5C,gBAAgB,CAAC,EAAE,MAAM;IAW/B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBzD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE;IAsClC,yBAAyB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAepD,qBAAqB,IAAI,MAAM,EAAE;IAIjC,UAAU,IAAI,IAAI;IAKlB,wBAAwB,IAAI,MAAM,EAAE;CAIrC"}
1
+ {"version":3,"file":"dictionary-manager.d.ts","sourceRoot":"","sources":["../../src/core/dictionary-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAA;AAK7E,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAyC;IACtD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuB;gBAE5C,gBAAgB,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IActD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiBzD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE;IAmDxC,OAAO,CAAC,oBAAoB;IAkCtB,yBAAyB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAepD,qBAAqB,IAAI,MAAM,EAAE;IAIjC,UAAU,IAAI,IAAI;IAKlB,wBAAwB,IAAI,MAAM,EAAE;CAIrC"}
@@ -1,12 +1,16 @@
1
1
  import { readFile } from 'fs/promises';
2
2
  import { join, dirname } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { formatError } from '../utils/error-utils.js';
4
5
  import { MatchStrategyRegistry } from './matching/match-strategies.js';
6
+ import { LRUCache } from './lru-cache.js';
5
7
  export class DictionaryManager {
6
- cache = new Map();
8
+ cache = new LRUCache(20); // 限制快取 20 個詞庫
7
9
  dictionariesPath;
8
10
  strategyRegistry;
9
- constructor(dictionariesPath) {
11
+ constructor(dictionariesPath, maxCacheSize) {
12
+ // 初始化快取,支援自定義大小
13
+ this.cache = new LRUCache(maxCacheSize || 20);
10
14
  if (dictionariesPath) {
11
15
  this.dictionariesPath = dictionariesPath;
12
16
  }
@@ -29,30 +33,38 @@ export class DictionaryManager {
29
33
  return dict;
30
34
  }
31
35
  catch (error) {
32
- const message = error instanceof Error ? error.message : String(error);
33
- throw new Error(`Failed to load dictionary "${name}": ${message}`);
36
+ throw new Error(`Failed to load dictionary "${name}": ${formatError(error)}`);
34
37
  }
35
38
  }
36
39
  findMatches(text) {
37
40
  const allMatches = [];
38
- const processedRanges = new Set();
41
+ const processedRanges = new Map(); // 改為 Map 來追蹤最佳匹配
39
42
  for (const dict of this.cache.values()) {
40
- for (const [term, entry] of Object.entries(dict.lookup)) {
43
+ // 先處理所有基本詞彙匹配
44
+ const basicTerms = Object.keys(dict.lookup).filter(term => !term.includes('_'));
45
+ const contextVariants = Object.keys(dict.lookup).filter(term => term.includes('_'));
46
+ // 處理基本詞彙
47
+ for (const term of basicTerms) {
48
+ const entry = dict.lookup[term];
41
49
  const strategy = this.strategyRegistry.getStrategy(entry.match_type || 'exact');
42
50
  if (!strategy)
43
51
  continue;
44
52
  const matches = strategy.match(text, term, entry.context);
45
53
  for (const match of matches) {
46
- const rangeKey = `${match.start}-${match.end}`;
47
- // 避免重複匹配同一個位置
48
- if (!processedRanges.has(rangeKey)) {
49
- processedRanges.add(rangeKey);
50
- allMatches.push({
51
- ...match,
52
- replacement: entry.taiwan,
53
- confidence: entry.confidence,
54
- rule: `${dict.metadata.name}-${entry.match_type}`
55
- });
54
+ this.addMatchWithPriority(allMatches, processedRanges, match, entry, dict.metadata.name);
55
+ }
56
+ // 對於語境敏感詞彙,同時檢查其變體
57
+ if (entry.match_type === 'context_sensitive') {
58
+ const variants = contextVariants.filter(variant => variant.startsWith(term + '_') || variant.startsWith(term.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '') + '_'));
59
+ for (const variant of variants) {
60
+ const variantEntry = dict.lookup[variant];
61
+ const variantStrategy = this.strategyRegistry.getStrategy(variantEntry.match_type || 'exact');
62
+ if (!variantStrategy)
63
+ continue;
64
+ const variantMatches = variantStrategy.match(text, term, variantEntry.context);
65
+ for (const match of variantMatches) {
66
+ this.addMatchWithPriority(allMatches, processedRanges, match, variantEntry, dict.metadata.name, true);
67
+ }
56
68
  }
57
69
  }
58
70
  }
@@ -65,6 +77,29 @@ export class DictionaryManager {
65
77
  return a.start - b.start;
66
78
  });
67
79
  }
80
+ addMatchWithPriority(allMatches, processedRanges, match, entry, dictName, isVariant = false) {
81
+ const rangeKey = `${match.start}-${match.end}`;
82
+ const newMatch = {
83
+ ...match,
84
+ replacement: entry.taiwan,
85
+ confidence: entry.confidence,
86
+ rule: `${dictName}-${entry.match_type || 'exact'}${isVariant ? '-variant' : ''}`,
87
+ autofix_safe: entry.autofix_safe || false
88
+ };
89
+ // 如果這個範圍還沒有匹配,或者新匹配的信心度更高
90
+ const existingMatch = processedRanges.get(rangeKey);
91
+ if (!existingMatch || newMatch.confidence > existingMatch.confidence) {
92
+ if (existingMatch) {
93
+ // 移除舊的匹配
94
+ const index = allMatches.indexOf(existingMatch);
95
+ if (index > -1) {
96
+ allMatches.splice(index, 1);
97
+ }
98
+ }
99
+ processedRanges.set(rangeKey, newMatch);
100
+ allMatches.push(newMatch);
101
+ }
102
+ }
68
103
  async scanAvailableDictionaries() {
69
104
  try {
70
105
  const { readdir } = await import('fs/promises');
@@ -1 +1 @@
1
- {"version":3,"file":"dictionary-manager.js","sourceRoot":"","sources":["../../src/core/dictionary-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dictionary-manager.js","sourceRoot":"","sources":["../../src/core/dictionary-manager.ts"],"names":[],"mappings":"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"}
@@ -4,21 +4,17 @@ export declare class TWLinter {
4
4
  private rules;
5
5
  private config;
6
6
  private deepMode;
7
- private converter;
8
7
  constructor(config: TWLintConfig, options?: {
9
8
  deep?: boolean;
10
9
  });
11
10
  private initializeRules;
12
11
  lintFiles(patterns: string[]): Promise<LintResult[]>;
13
- lintText(text: string, filePath?: string): Promise<Issue[]>;
12
+ lintText(text: string, _filePath?: string): Promise<Issue[]>;
14
13
  fixText(text: string): Promise<string>;
15
14
  private expandFilePatterns;
15
+ private getIgnorePatterns;
16
16
  private loadDictionaries;
17
17
  private getActiveRules;
18
- /**
19
- * 使用 opencc-js 將簡體中文轉換為繁體中文
20
- */
21
- private convertToTraditional;
22
18
  /**
23
19
  * 檢查規則是否啟用
24
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAQ,MAAM,aAAa,CAAA;AAExE,qBAAa,QAAQ;IACnB,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,SAAS,CAA8B;gBAEnC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE;IAQ9D,OAAO,CAAC,eAAe;IAQjB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IA+BpD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAoC3D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAgC9B,kBAAkB;YAWlB,gBAAgB;IAoB9B,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,yBAAyB;CAUlC"}
1
+ {"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAQ,MAAM,aAAa,CAAA;AAIxE,qBAAa,QAAQ;IACnB,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE;IAO9D,OAAO,CAAC,eAAe;IAQjB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IA8BpD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IA8B5D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAkB9B,kBAAkB;YAwBlB,iBAAiB;YA8CjB,gBAAgB;IAe9B,OAAO,CAAC,cAAc;IAoBtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,yBAAyB;CAUlC"}
@@ -3,19 +3,17 @@ import { readFile } from 'fs/promises';
3
3
  import { DictionaryManager } from './dictionary-manager.js';
4
4
  import { SimplifiedCharsRule } from './rules/simplified-chars.js';
5
5
  import { MainlandTermsRule } from './rules/mainland-terms.js';
6
- import { PositionMapper } from './position-mapper.js';
7
- import { Converter } from 'opencc-js';
6
+ import { formatError, ErrorHandler } from '../utils/error-utils.js';
7
+ import { DictLoadStrategyFactory } from './dictionary-loading-strategies.js';
8
8
  export class TWLinter {
9
9
  dictManager;
10
10
  rules = new Map();
11
11
  config;
12
12
  deepMode = false;
13
- converter;
14
13
  constructor(config, options) {
15
14
  this.config = config;
16
15
  this.deepMode = options?.deep || false;
17
16
  this.dictManager = new DictionaryManager();
18
- this.converter = Converter({ from: 'cn', to: 'tw' });
19
17
  this.initializeRules();
20
18
  }
21
19
  initializeRules() {
@@ -37,13 +35,12 @@ export class TWLinter {
37
35
  });
38
36
  }
39
37
  catch (error) {
40
- const message = error instanceof Error ? error.message : String(error);
41
38
  results.push({
42
39
  filePath,
43
40
  messages: [{
44
41
  line: 1,
45
42
  column: 1,
46
- message: `Failed to read file: ${message}`,
43
+ message: `Failed to read file: ${formatError(error)}`,
47
44
  severity: 'error',
48
45
  rule: 'file-read-error',
49
46
  fixable: false
@@ -53,86 +50,119 @@ export class TWLinter {
53
50
  }
54
51
  return results;
55
52
  }
56
- async lintText(text, filePath) {
53
+ async lintText(text, _filePath) {
57
54
  await this.loadDictionaries(this.deepMode);
58
55
  const issues = [];
59
56
  const activeRules = this.getActiveRules();
60
- // Process all active rules
57
+ // Process all active rules with unified preprocessing
61
58
  for (const rule of activeRules) {
62
59
  try {
63
- let textToCheck = text;
64
- let positionMapper;
65
- // Apply text conversion if needed (for mainland-terms rule)
66
- if (rule.name === 'mainland-terms') {
67
- const convertedText = this.convertToTraditional(text);
68
- textToCheck = convertedText;
69
- positionMapper = new PositionMapper(text, convertedText);
70
- }
71
- const ruleIssues = await rule.check(textToCheck);
72
- // Adjust positions if we used converted text
73
- const adjustedIssues = positionMapper
74
- ? this.adjustPositionsWithMapper(ruleIssues, positionMapper)
60
+ // Let rule handle its own text preprocessing
61
+ const context = rule.preprocess
62
+ ? await rule.preprocess(text)
63
+ : { originalText: text, processedText: text };
64
+ const ruleIssues = await rule.check(context.processedText);
65
+ // Adjust positions if rule used text conversion
66
+ const adjustedIssues = context.positionMapper
67
+ ? this.adjustPositionsWithMapper(ruleIssues, context.positionMapper)
75
68
  : ruleIssues;
76
69
  issues.push(...adjustedIssues);
77
70
  }
78
71
  catch (error) {
79
- const message = error instanceof Error ? error.message : String(error);
80
- console.warn(`Warning: Rule "${rule.name}" failed: ${message}`);
72
+ ErrorHandler.handle(error, `Rule "${rule.name}"`);
81
73
  }
82
74
  }
83
75
  return issues;
84
76
  }
85
77
  async fixText(text) {
86
- // 確保詞庫已載入
87
78
  await this.loadDictionaries(this.deepMode);
88
- let fixedText = text;
89
- // 階段1:簡繁轉換修復
90
- const simplifiedRule = this.rules.get('simplified-chars');
91
- if (simplifiedRule && this.isRuleActive('simplified-chars') && simplifiedRule.fix) {
92
- try {
93
- fixedText = await simplifiedRule.fix(fixedText);
94
- }
95
- catch (error) {
96
- const message = error instanceof Error ? error.message : String(error);
97
- console.warn(`Warning: Failed to apply simplified-chars fix: ${message}`);
98
- }
99
- }
100
- // 階段2:大陸用語修復(在轉換後的文本上進行)
101
- const mainlandRule = this.rules.get('mainland-terms');
102
- if (mainlandRule && this.isRuleActive('mainland-terms') && mainlandRule.fix) {
79
+ const activeRules = this.getActiveRules().filter(rule => rule.fix);
80
+ let result = text;
81
+ // 按規則順序依次應用修復
82
+ for (const rule of activeRules) {
103
83
  try {
104
- fixedText = await mainlandRule.fix(fixedText);
84
+ result = await rule.fix(result);
105
85
  }
106
86
  catch (error) {
107
- const message = error instanceof Error ? error.message : String(error);
108
- console.warn(`Warning: Failed to apply mainland-terms fix: ${message}`);
87
+ ErrorHandler.handle(error, `Rule ${rule.name} fix`);
109
88
  }
110
89
  }
111
- return fixedText;
90
+ return result;
112
91
  }
113
92
  async expandFilePatterns(patterns) {
114
93
  const files = [];
94
+ const ignorePatterns = await this.getIgnorePatterns();
115
95
  for (const pattern of patterns) {
116
- const matches = await glob(pattern, { ignore: 'node_modules/**' });
117
- files.push(...matches);
96
+ // 檢查是否為明確的檔案路徑(沒有萬用字元)
97
+ const hasWildcards = pattern.includes('*') || pattern.includes('?') || pattern.includes('[');
98
+ if (!hasWildcards) {
99
+ // 明確的檔案路徑:直接加入,讓後續的檔案讀取來處理錯誤
100
+ files.push(pattern);
101
+ }
102
+ else {
103
+ // 萬用字元模式:使用 glob 擴展,遵循 .gitignore 規則
104
+ const matches = await glob(pattern, {
105
+ ignore: ignorePatterns,
106
+ dot: false // 預設不包含隱藏檔案
107
+ });
108
+ files.push(...matches);
109
+ }
118
110
  }
119
111
  return [...new Set(files)]; // Remove duplicates
120
112
  }
121
- async loadDictionaries(deep) {
122
- let dictNames = this.config.dictionaries || ['core'];
123
- // 深度模式:載入所有可用詞庫
124
- if (deep) {
125
- const availableDicts = this.dictManager.getAvailableDictionaries();
126
- dictNames = [...new Set([...dictNames, ...availableDicts])];
113
+ async getIgnorePatterns() {
114
+ const defaultIgnores = [
115
+ 'node_modules/**',
116
+ '.git/**',
117
+ '.next/**',
118
+ '.nuxt/**',
119
+ 'dist/**',
120
+ 'build/**',
121
+ 'coverage/**',
122
+ 'logs/**',
123
+ '*.log',
124
+ '.env*',
125
+ '.DS_Store',
126
+ '.vscode/**',
127
+ '.idea/**',
128
+ 'test-temp/**',
129
+ '*.tmp'
130
+ ];
131
+ try {
132
+ const { readFile } = await import('fs/promises');
133
+ const gitignoreContent = await readFile('.gitignore', 'utf-8');
134
+ const gitignorePatterns = gitignoreContent
135
+ .split('\n')
136
+ .map(line => line.trim())
137
+ .filter(line => line && !line.startsWith('#')) // 排除空行和註解
138
+ .map(line => {
139
+ // 處理目錄模式
140
+ if (line.endsWith('/')) {
141
+ return line + '**';
142
+ }
143
+ // 處理檔案模式
144
+ if (!line.includes('*') && !line.includes('/')) {
145
+ return '**/' + line;
146
+ }
147
+ return line;
148
+ });
149
+ return [...defaultIgnores, ...gitignorePatterns];
127
150
  }
151
+ catch {
152
+ // 沒有 .gitignore 或讀取失敗,使用預設規則
153
+ return defaultIgnores;
154
+ }
155
+ }
156
+ async loadDictionaries(deep) {
157
+ const strategy = DictLoadStrategyFactory.create(this.config, deep);
158
+ const dictNames = await strategy.getDictionaries(this.config, this.dictManager);
128
159
  for (const name of dictNames) {
129
160
  try {
130
161
  await this.dictManager.loadDictionary(name);
131
162
  }
132
163
  catch (error) {
133
164
  // 忽略無法載入的詞庫,但記錄警告
134
- const message = error instanceof Error ? error.message : String(error);
135
- console.warn(`Warning: Failed to load dictionary "${name}": ${message}`);
165
+ ErrorHandler.handle(error, `Failed to load dictionary "${name}"`);
136
166
  }
137
167
  }
138
168
  }
@@ -152,12 +182,6 @@ export class TWLinter {
152
182
  }
153
183
  return activeRules;
154
184
  }
155
- /**
156
- * 使用 opencc-js 將簡體中文轉換為繁體中文
157
- */
158
- convertToTraditional(text) {
159
- return this.converter(text);
160
- }
161
185
  /**
162
186
  * 檢查規則是否啟用
163
187
  */
@@ -1 +1 @@
1
- {"version":3,"file":"linter.js","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"linter.js","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 簡單的 LRU 快取實現
3
+ * 避免記憶體洩漏,限制快取大小
4
+ */
5
+ export declare class LRUCache<K, V> {
6
+ private readonly maxSize;
7
+ private readonly cache;
8
+ constructor(maxSize?: number);
9
+ get(key: K): V | undefined;
10
+ set(key: K, value: V): void;
11
+ has(key: K): boolean;
12
+ delete(key: K): boolean;
13
+ clear(): void;
14
+ get size(): number;
15
+ keys(): IterableIterator<K>;
16
+ values(): IterableIterator<V>;
17
+ }
18
+ //# sourceMappingURL=lru-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru-cache.d.ts","sourceRoot":"","sources":["../../src/core/lru-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;gBAE5B,OAAO,GAAE,MAAW;IAIhC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAU1B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAkB3B,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIpB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIvB,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,IAAI,gBAAgB,CAAC,CAAC,CAAC;IAI3B,MAAM,IAAI,gBAAgB,CAAC,CAAC,CAAC;CAG9B"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 簡單的 LRU 快取實現
3
+ * 避免記憶體洩漏,限制快取大小
4
+ */
5
+ export class LRUCache {
6
+ maxSize;
7
+ cache = new Map();
8
+ constructor(maxSize = 10) {
9
+ this.maxSize = maxSize;
10
+ }
11
+ get(key) {
12
+ const value = this.cache.get(key);
13
+ if (value !== undefined) {
14
+ // 移動到最後(最近使用)
15
+ this.cache.delete(key);
16
+ this.cache.set(key, value);
17
+ }
18
+ return value;
19
+ }
20
+ set(key, value) {
21
+ if (this.cache.has(key)) {
22
+ // 更新現有值
23
+ this.cache.delete(key);
24
+ this.cache.set(key, value);
25
+ }
26
+ else {
27
+ // 新增值,檢查大小限制
28
+ if (this.cache.size >= this.maxSize) {
29
+ // 刪除最舊的項目(第一個)
30
+ const firstKey = this.cache.keys().next().value;
31
+ if (firstKey !== undefined) {
32
+ this.cache.delete(firstKey);
33
+ }
34
+ }
35
+ this.cache.set(key, value);
36
+ }
37
+ }
38
+ has(key) {
39
+ return this.cache.has(key);
40
+ }
41
+ delete(key) {
42
+ return this.cache.delete(key);
43
+ }
44
+ clear() {
45
+ this.cache.clear();
46
+ }
47
+ get size() {
48
+ return this.cache.size;
49
+ }
50
+ keys() {
51
+ return this.cache.keys();
52
+ }
53
+ values() {
54
+ return this.cache.values();
55
+ }
56
+ }
57
+ //# sourceMappingURL=lru-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru-cache.js","sourceRoot":"","sources":["../../src/core/lru-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,QAAQ;IACF,OAAO,CAAQ;IACf,KAAK,GAAG,IAAI,GAAG,EAAQ,CAAA;IAExC,YAAY,UAAkB,EAAE;QAC9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,GAAG,CAAC,GAAM;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACjC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,cAAc;YACd,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACtB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,GAAG,CAAC,GAAM,EAAE,KAAQ;QAClB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ;YACR,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACtB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,aAAa;YACb,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpC,eAAe;gBACf,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA;gBAC/C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBAC7B,CAAC;YACH,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED,MAAM,CAAC,GAAM;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC/B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAA;IACxB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAA;IAC5B,CAAC;CACF"}