@termdock/twlint 1.0.0 → 1.0.2
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/README.md +176 -63
- package/bin/twlint +4 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +63 -12
- package/dist/cli.js.map +1 -1
- package/dist/core/config-schema.d.ts +1 -0
- package/dist/core/config-schema.d.ts.map +1 -1
- package/dist/core/config-schema.js +33 -7
- package/dist/core/config-schema.js.map +1 -1
- package/dist/core/dictionary-loading-strategies.d.ts +45 -0
- package/dist/core/dictionary-loading-strategies.d.ts.map +1 -0
- package/dist/core/dictionary-loading-strategies.js +75 -0
- package/dist/core/dictionary-loading-strategies.js.map +1 -0
- package/dist/core/dictionary-manager.d.ts +2 -1
- package/dist/core/dictionary-manager.d.ts.map +1 -1
- package/dist/core/dictionary-manager.js +51 -16
- package/dist/core/dictionary-manager.js.map +1 -1
- package/dist/core/linter.d.ts +2 -6
- package/dist/core/linter.d.ts.map +1 -1
- package/dist/core/linter.js +82 -58
- package/dist/core/linter.js.map +1 -1
- package/dist/core/lru-cache.d.ts +18 -0
- package/dist/core/lru-cache.d.ts.map +1 -0
- package/dist/core/lru-cache.js +57 -0
- package/dist/core/lru-cache.js.map +1 -0
- package/dist/core/matching/match-strategies.d.ts +19 -11
- package/dist/core/matching/match-strategies.d.ts.map +1 -1
- package/dist/core/matching/match-strategies.js +44 -74
- package/dist/core/matching/match-strategies.js.map +1 -1
- package/dist/core/rules/mainland-terms.d.ts +3 -1
- package/dist/core/rules/mainland-terms.d.ts.map +1 -1
- package/dist/core/rules/mainland-terms.js +25 -4
- package/dist/core/rules/mainland-terms.js.map +1 -1
- package/dist/dictionaries/academic.json +242 -22
- package/dist/dictionaries/ai-emerging-tech.json +3209 -0
- package/dist/dictionaries/business-finance.json +3449 -0
- package/dist/dictionaries/core.json +2902 -248
- package/dist/dictionaries/hardware-3c.json +2649 -0
- package/dist/dictionaries/index.json +70 -8
- package/dist/dictionaries/network-cloud.json +2953 -0
- package/dist/dictionaries/operating-system.json +2889 -0
- package/dist/dictionaries/social-media.json +2833 -0
- package/dist/dictionaries/software-development.json +3809 -0
- package/dist/dictionaries/user-interface.json +3225 -0
- package/dist/formatters/stylish.d.ts.map +1 -1
- package/dist/formatters/stylish.js +5 -15
- package/dist/formatters/stylish.js.map +1 -1
- package/dist/types.d.ts +20 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/error-utils.d.ts +9 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +15 -0
- package/dist/utils/error-utils.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 詞庫載入策略 - 消除 linter.ts 中的特殊情況處理
|
|
3
|
+
*/
|
|
4
|
+
import type { TWLintConfig } from '../types.js';
|
|
5
|
+
import type { DictionaryManager } from './dictionary-manager.js';
|
|
6
|
+
export interface DictLoadStrategy {
|
|
7
|
+
getDictionaries(config: TWLintConfig, manager: DictionaryManager): Promise<string[]>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 基本策略:只載入核心詞庫
|
|
11
|
+
*/
|
|
12
|
+
export declare class CoreDictStrategy implements DictLoadStrategy {
|
|
13
|
+
getDictionaries(): Promise<string[]>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 自訂詞庫策略:載入用戶指定的詞庫
|
|
17
|
+
*/
|
|
18
|
+
export declare class CustomDictStrategy implements DictLoadStrategy {
|
|
19
|
+
private dictionaries;
|
|
20
|
+
constructor(dictionaries: string[]);
|
|
21
|
+
getDictionaries(): Promise<string[]>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 領域策略:載入指定領域的詞庫(包含核心詞庫)
|
|
25
|
+
*/
|
|
26
|
+
export declare class DomainDictStrategy implements DictLoadStrategy {
|
|
27
|
+
private domains;
|
|
28
|
+
constructor(domains: string[]);
|
|
29
|
+
getDictionaries(): Promise<string[]>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 深度策略:載入所有可用詞庫
|
|
33
|
+
*/
|
|
34
|
+
export declare class DeepDictStrategy implements DictLoadStrategy {
|
|
35
|
+
private baseStrategy;
|
|
36
|
+
constructor(baseStrategy: DictLoadStrategy);
|
|
37
|
+
getDictionaries(config: TWLintConfig, manager: DictionaryManager): Promise<string[]>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 策略工廠:根據配置選擇適當的策略
|
|
41
|
+
*/
|
|
42
|
+
export declare class DictLoadStrategyFactory {
|
|
43
|
+
static create(config: TWLintConfig, deep?: boolean): DictLoadStrategy;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=dictionary-loading-strategies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary-loading-strategies.d.ts","sourceRoot":"","sources":["../../src/core/dictionary-loading-strategies.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;CACrF;AAED;;GAEG;AACH,qBAAa,gBAAiB,YAAW,gBAAgB;IACjD,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAG3C;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,gBAAgB;IAC7C,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,MAAM,EAAE;IAEpC,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAG3C;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,gBAAgB;IAC7C,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM,EAAE;IAE/B,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAO3C;AAED;;GAEG;AACH,qBAAa,gBAAiB,YAAW,gBAAgB;IAC3C,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,gBAAgB;IAE5C,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAK3F;AAED;;GAEG;AACH,qBAAa,uBAAuB;IAClC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,gBAAgB;CAiBtE"}
|
|
@@ -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,
|
|
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
|
|
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
|
-
|
|
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
|
|
41
|
+
const processedRanges = new Map(); // 改為 Map 來追蹤最佳匹配
|
|
39
42
|
for (const dict of this.cache.values()) {
|
|
40
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AAEnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"dictionary-manager.js","sourceRoot":"","sources":["../../src/core/dictionary-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/core/linter.d.ts
CHANGED
|
@@ -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,
|
|
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":"
|
|
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"}
|
package/dist/core/linter.js
CHANGED
|
@@ -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 {
|
|
7
|
-
import {
|
|
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: ${
|
|
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,
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
84
|
+
result = await rule.fix(result);
|
|
105
85
|
}
|
|
106
86
|
catch (error) {
|
|
107
|
-
|
|
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
|
|
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
|
-
|
|
117
|
-
|
|
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
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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
|
*/
|
package/dist/core/linter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linter.js","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;
|
|
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
|