@better-i18n/cli 0.1.8 → 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.
- package/dist/analyzer/dynamic-matcher.d.ts +53 -0
- package/dist/analyzer/dynamic-matcher.d.ts.map +1 -0
- package/dist/analyzer/dynamic-matcher.js +93 -0
- package/dist/analyzer/dynamic-matcher.js.map +1 -0
- package/dist/analyzer/index.d.ts +13 -4
- package/dist/analyzer/index.d.ts.map +1 -1
- package/dist/analyzer/index.js +165 -22
- package/dist/analyzer/index.js.map +1 -1
- package/dist/analyzer/rules/data-structure.d.ts +13 -0
- package/dist/analyzer/rules/data-structure.d.ts.map +1 -0
- package/dist/analyzer/rules/data-structure.js +264 -0
- package/dist/analyzer/rules/data-structure.js.map +1 -0
- package/dist/analyzer/rules/index.d.ts +10 -7
- package/dist/analyzer/rules/index.d.ts.map +1 -1
- package/dist/analyzer/rules/index.js +10 -7
- package/dist/analyzer/rules/index.js.map +1 -1
- package/dist/analyzer/rules/jsx-text.js +1 -1
- package/dist/analyzer/rules/jsx-text.js.map +1 -1
- package/dist/analyzer/rules/translation-function.d.ts.map +1 -1
- package/dist/analyzer/rules/translation-function.js +94 -6
- package/dist/analyzer/rules/translation-function.js.map +1 -1
- package/dist/analyzer/types.d.ts +28 -3
- package/dist/analyzer/types.d.ts.map +1 -1
- package/dist/commands/check.d.ts +14 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +70 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/doctor.d.ts +20 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +77 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +158 -272
- package/dist/commands/sync.js.map +1 -1
- package/dist/context/detector.js +1 -1
- package/dist/context/detector.js.map +1 -1
- package/dist/context/oidc.d.ts +33 -0
- package/dist/context/oidc.d.ts.map +1 -0
- package/dist/context/oidc.js +63 -0
- package/dist/context/oidc.js.map +1 -0
- package/dist/doctor/index.d.ts +65 -0
- package/dist/doctor/index.d.ts.map +1 -0
- package/dist/doctor/index.js +252 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/doctor/project-discovery.d.ts +37 -0
- package/dist/doctor/project-discovery.d.ts.map +1 -0
- package/dist/doctor/project-discovery.js +140 -0
- package/dist/doctor/project-discovery.js.map +1 -0
- package/dist/doctor/score.d.ts +41 -0
- package/dist/doctor/score.d.ts.map +1 -0
- package/dist/doctor/score.js +107 -0
- package/dist/doctor/score.js.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -1
- package/dist/reporters/doctor-eslint.d.ts +17 -0
- package/dist/reporters/doctor-eslint.d.ts.map +1 -0
- package/dist/reporters/doctor-eslint.js +139 -0
- package/dist/reporters/doctor-eslint.js.map +1 -0
- package/dist/reporters/doctor-json.d.ts +12 -0
- package/dist/reporters/doctor-json.d.ts.map +1 -0
- package/dist/reporters/doctor-json.js +21 -0
- package/dist/reporters/doctor-json.js.map +1 -0
- package/dist/reporters/doctor-report.d.ts +23 -0
- package/dist/reporters/doctor-report.d.ts.map +1 -0
- package/dist/reporters/doctor-report.js +62 -0
- package/dist/reporters/doctor-report.js.map +1 -0
- package/dist/reporters/eslint-style.js +4 -4
- package/dist/reporters/eslint-style.js.map +1 -1
- package/dist/rules/categories.d.ts +36 -0
- package/dist/rules/categories.d.ts.map +1 -0
- package/dist/rules/categories.js +80 -0
- package/dist/rules/categories.js.map +1 -0
- package/dist/rules/code/index.d.ts +9 -0
- package/dist/rules/code/index.d.ts.map +1 -0
- package/dist/rules/code/index.js +9 -0
- package/dist/rules/code/index.js.map +1 -0
- package/dist/rules/code/jsx-attribute.d.ts +12 -0
- package/dist/rules/code/jsx-attribute.d.ts.map +1 -0
- package/dist/rules/code/jsx-attribute.js +78 -0
- package/dist/rules/code/jsx-attribute.js.map +1 -0
- package/dist/rules/code/jsx-text.d.ts +12 -0
- package/dist/rules/code/jsx-text.d.ts.map +1 -0
- package/dist/rules/code/jsx-text.js +47 -0
- package/dist/rules/code/jsx-text.js.map +1 -0
- package/dist/rules/code/string-variable.d.ts +13 -0
- package/dist/rules/code/string-variable.d.ts.map +1 -0
- package/dist/rules/code/string-variable.js +185 -0
- package/dist/rules/code/string-variable.js.map +1 -0
- package/dist/rules/code/ternary-locale.d.ts +12 -0
- package/dist/rules/code/ternary-locale.d.ts.map +1 -0
- package/dist/rules/code/ternary-locale.js +53 -0
- package/dist/rules/code/ternary-locale.js.map +1 -0
- package/dist/rules/code/toast-message.d.ts +13 -0
- package/dist/rules/code/toast-message.d.ts.map +1 -0
- package/dist/rules/code/toast-message.js +101 -0
- package/dist/rules/code/toast-message.js.map +1 -0
- package/dist/rules/extraction/data-structure.d.ts +13 -0
- package/dist/rules/extraction/data-structure.d.ts.map +1 -0
- package/dist/rules/extraction/data-structure.js +212 -0
- package/dist/rules/extraction/data-structure.js.map +1 -0
- package/dist/rules/extraction/index.d.ts +6 -0
- package/dist/rules/extraction/index.d.ts.map +1 -0
- package/dist/rules/extraction/index.js +6 -0
- package/dist/rules/extraction/index.js.map +1 -0
- package/dist/rules/extraction/translation-function.d.ts +12 -0
- package/dist/rules/extraction/translation-function.d.ts.map +1 -0
- package/dist/rules/extraction/translation-function.js +153 -0
- package/dist/rules/extraction/translation-function.js.map +1 -0
- package/dist/rules/health/index.d.ts +16 -0
- package/dist/rules/health/index.d.ts.map +1 -0
- package/dist/rules/health/index.js +22 -0
- package/dist/rules/health/index.js.map +1 -0
- package/dist/rules/health/missing-translations.d.ts +13 -0
- package/dist/rules/health/missing-translations.d.ts.map +1 -0
- package/dist/rules/health/missing-translations.js +48 -0
- package/dist/rules/health/missing-translations.js.map +1 -0
- package/dist/rules/health/orphan-keys.d.ts +16 -0
- package/dist/rules/health/orphan-keys.d.ts.map +1 -0
- package/dist/rules/health/orphan-keys.js +50 -0
- package/dist/rules/health/orphan-keys.js.map +1 -0
- package/dist/rules/health/placeholder-mismatch.d.ts +32 -0
- package/dist/rules/health/placeholder-mismatch.d.ts.map +1 -0
- package/dist/rules/health/placeholder-mismatch.js +120 -0
- package/dist/rules/health/placeholder-mismatch.js.map +1 -0
- package/dist/rules/registry.d.ts +84 -0
- package/dist/rules/registry.d.ts.map +1 -0
- package/dist/rules/registry.js +11 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/utils/cdn-client.d.ts +30 -0
- package/dist/utils/cdn-client.d.ts.map +1 -0
- package/dist/utils/cdn-client.js +59 -0
- package/dist/utils/cdn-client.js.map +1 -0
- package/dist/utils/json-keys.d.ts +60 -0
- package/dist/utils/json-keys.d.ts.map +1 -0
- package/dist/utils/json-keys.js +103 -0
- package/dist/utils/json-keys.js.map +1 -0
- package/dist/utils/key-comparison.d.ts +67 -0
- package/dist/utils/key-comparison.d.ts.map +1 -0
- package/dist/utils/key-comparison.js +299 -0
- package/dist/utils/key-comparison.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Score Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates a weighted health score (0-100) from diagnostics.
|
|
5
|
+
*
|
|
6
|
+
* Scoring follows react-doctor's approach:
|
|
7
|
+
* - Start at 100
|
|
8
|
+
* - Deduct penalties per UNIQUE rule violation per category
|
|
9
|
+
* - Counting unique rules (not occurrences) prevents a single noisy rule
|
|
10
|
+
* from tanking the entire score
|
|
11
|
+
*
|
|
12
|
+
* Category weights (penalty per unique error/warning):
|
|
13
|
+
* Coverage: 3.0 (error), 1.5 (warning)
|
|
14
|
+
* Quality: 2.5 (error), 1.25 (warning)
|
|
15
|
+
* Code: 1.5 (error), 0.75 (warning)
|
|
16
|
+
* Structure: 1.0 (error), 0.5 (warning)
|
|
17
|
+
* Performance: 0.75 (error), 0.4 (warning)
|
|
18
|
+
*/
|
|
19
|
+
import type { I18nDiagnostic } from "../rules/registry.js";
|
|
20
|
+
export interface HealthScore {
|
|
21
|
+
/** Overall score 0-100 */
|
|
22
|
+
total: number;
|
|
23
|
+
/** Per-category scores 0-100 */
|
|
24
|
+
categories: Record<string, number>;
|
|
25
|
+
/** Whether the project passes the threshold */
|
|
26
|
+
passed: boolean;
|
|
27
|
+
/** Pass threshold (configurable, default 70) */
|
|
28
|
+
passThreshold: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Calculate health score from diagnostics.
|
|
32
|
+
*
|
|
33
|
+
* Algorithm:
|
|
34
|
+
* 1. Group diagnostics by category
|
|
35
|
+
* 2. For each category, count unique rule IDs with errors and warnings
|
|
36
|
+
* 3. Apply penalty per unique rule: score = 100 - Σ(penalties)
|
|
37
|
+
* 4. Clamp to [0, 100]
|
|
38
|
+
* 5. Overall = weighted average of category scores
|
|
39
|
+
*/
|
|
40
|
+
export declare function calculateHealthScore(diagnostics: I18nDiagnostic[], passThreshold?: number): HealthScore;
|
|
41
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/doctor/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAmB3D,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,+CAA+C;IAC/C,MAAM,EAAE,OAAO,CAAC;IAChB,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,cAAc,EAAE,EAC7B,aAAa,SAAK,GACjB,WAAW,CA+Eb"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Score Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates a weighted health score (0-100) from diagnostics.
|
|
5
|
+
*
|
|
6
|
+
* Scoring follows react-doctor's approach:
|
|
7
|
+
* - Start at 100
|
|
8
|
+
* - Deduct penalties per UNIQUE rule violation per category
|
|
9
|
+
* - Counting unique rules (not occurrences) prevents a single noisy rule
|
|
10
|
+
* from tanking the entire score
|
|
11
|
+
*
|
|
12
|
+
* Category weights (penalty per unique error/warning):
|
|
13
|
+
* Coverage: 3.0 (error), 1.5 (warning)
|
|
14
|
+
* Quality: 2.5 (error), 1.25 (warning)
|
|
15
|
+
* Code: 1.5 (error), 0.75 (warning)
|
|
16
|
+
* Structure: 1.0 (error), 0.5 (warning)
|
|
17
|
+
* Performance: 0.75 (error), 0.4 (warning)
|
|
18
|
+
*/
|
|
19
|
+
/** Penalty per unique rule in a category */
|
|
20
|
+
const ERROR_PENALTIES = {
|
|
21
|
+
Coverage: 3.0,
|
|
22
|
+
Quality: 2.5,
|
|
23
|
+
Code: 1.5,
|
|
24
|
+
Structure: 1.0,
|
|
25
|
+
Performance: 0.75,
|
|
26
|
+
};
|
|
27
|
+
const WARNING_PENALTIES = {
|
|
28
|
+
Coverage: 1.5,
|
|
29
|
+
Quality: 1.25,
|
|
30
|
+
Code: 0.75,
|
|
31
|
+
Structure: 0.5,
|
|
32
|
+
Performance: 0.4,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Calculate health score from diagnostics.
|
|
36
|
+
*
|
|
37
|
+
* Algorithm:
|
|
38
|
+
* 1. Group diagnostics by category
|
|
39
|
+
* 2. For each category, count unique rule IDs with errors and warnings
|
|
40
|
+
* 3. Apply penalty per unique rule: score = 100 - Σ(penalties)
|
|
41
|
+
* 4. Clamp to [0, 100]
|
|
42
|
+
* 5. Overall = weighted average of category scores
|
|
43
|
+
*/
|
|
44
|
+
export function calculateHealthScore(diagnostics, passThreshold = 70) {
|
|
45
|
+
// Group by category
|
|
46
|
+
const byCategory = new Map();
|
|
47
|
+
for (const d of diagnostics) {
|
|
48
|
+
const existing = byCategory.get(d.category) || [];
|
|
49
|
+
existing.push(d);
|
|
50
|
+
byCategory.set(d.category, existing);
|
|
51
|
+
}
|
|
52
|
+
// All possible categories
|
|
53
|
+
const allCategories = [
|
|
54
|
+
"Coverage",
|
|
55
|
+
"Quality",
|
|
56
|
+
"Code",
|
|
57
|
+
"Structure",
|
|
58
|
+
"Performance",
|
|
59
|
+
];
|
|
60
|
+
const categoryScores = {};
|
|
61
|
+
for (const category of allCategories) {
|
|
62
|
+
const diags = byCategory.get(category) || [];
|
|
63
|
+
if (diags.length === 0) {
|
|
64
|
+
categoryScores[category] = 100;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Count unique rules by severity
|
|
68
|
+
const errorRules = new Set();
|
|
69
|
+
const warningRules = new Set();
|
|
70
|
+
for (const d of diags) {
|
|
71
|
+
if (d.severity === "error") {
|
|
72
|
+
errorRules.add(d.rule);
|
|
73
|
+
}
|
|
74
|
+
else if (d.severity === "warning") {
|
|
75
|
+
warningRules.add(d.rule);
|
|
76
|
+
}
|
|
77
|
+
// "info" diagnostics don't affect score
|
|
78
|
+
}
|
|
79
|
+
const errorPenalty = errorRules.size * (ERROR_PENALTIES[category] || 1.0);
|
|
80
|
+
const warningPenalty = warningRules.size * (WARNING_PENALTIES[category] || 0.5);
|
|
81
|
+
categoryScores[category] = Math.max(0, Math.round(100 - errorPenalty - warningPenalty));
|
|
82
|
+
}
|
|
83
|
+
// Overall score = weighted average
|
|
84
|
+
// Weights match category importance
|
|
85
|
+
const weights = {
|
|
86
|
+
Coverage: 40,
|
|
87
|
+
Quality: 25,
|
|
88
|
+
Code: 15,
|
|
89
|
+
Structure: 15,
|
|
90
|
+
Performance: 5,
|
|
91
|
+
};
|
|
92
|
+
let weightedSum = 0;
|
|
93
|
+
let totalWeight = 0;
|
|
94
|
+
for (const category of allCategories) {
|
|
95
|
+
const weight = weights[category] || 10;
|
|
96
|
+
weightedSum += categoryScores[category] * weight;
|
|
97
|
+
totalWeight += weight;
|
|
98
|
+
}
|
|
99
|
+
const total = Math.round(weightedSum / totalWeight);
|
|
100
|
+
return {
|
|
101
|
+
total,
|
|
102
|
+
categories: categoryScores,
|
|
103
|
+
passed: total >= passThreshold,
|
|
104
|
+
passThreshold,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/doctor/score.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import { program } from "commander";
|
|
9
9
|
import { scanCommand } from "./commands/scan.js";
|
|
10
10
|
import { syncCommand } from "./commands/sync.js";
|
|
11
|
+
import { checkCommand, checkMissingCommand, checkUnusedCommand, } from "./commands/check.js";
|
|
12
|
+
import { doctorCommand } from "./commands/doctor.js";
|
|
11
13
|
program
|
|
12
14
|
.name("better-i18n")
|
|
13
15
|
.description("Detect hardcoded strings and sync translation keys in your React app")
|
|
@@ -31,5 +33,38 @@ program
|
|
|
31
33
|
.option("--summary", "Show only the high-level metrics summary")
|
|
32
34
|
.option("--verbose", "Show detailed output")
|
|
33
35
|
.action(syncCommand);
|
|
36
|
+
// New check commands with interactive prompts
|
|
37
|
+
program
|
|
38
|
+
.command("check")
|
|
39
|
+
.description("Interactive checker for missing and unused translation keys")
|
|
40
|
+
.option("-d, --dir <path>", "Directory to scan (default: current directory)")
|
|
41
|
+
.option("-f, --format <type>", "Output format: eslint, json", "eslint")
|
|
42
|
+
.option("--verbose", "Show detailed output")
|
|
43
|
+
.action(checkCommand);
|
|
44
|
+
program
|
|
45
|
+
.command("check:missing")
|
|
46
|
+
.description("Check for missing translation keys (in code but not in remote)")
|
|
47
|
+
.option("-d, --dir <path>", "Directory to scan (default: current directory)")
|
|
48
|
+
.option("-f, --format <type>", "Output format: eslint, json", "eslint")
|
|
49
|
+
.option("--verbose", "Show detailed output")
|
|
50
|
+
.action(checkMissingCommand);
|
|
51
|
+
program
|
|
52
|
+
.command("check:unused")
|
|
53
|
+
.description("Check for unused translation keys (in remote but not detected in code)")
|
|
54
|
+
.option("-d, --dir <path>", "Directory to scan (default: current directory)")
|
|
55
|
+
.option("-f, --format <type>", "Output format: eslint, json", "eslint")
|
|
56
|
+
.option("--verbose", "Show detailed output")
|
|
57
|
+
.action(checkUnusedCommand);
|
|
58
|
+
program
|
|
59
|
+
.command("doctor")
|
|
60
|
+
.description("Analyze i18n health: missing translations, orphan keys, placeholder mismatches")
|
|
61
|
+
.option("-d, --dir <path>", "Directory to scan (default: current directory)")
|
|
62
|
+
.option("-f, --format <type>", "Output format: eslint, json", "eslint")
|
|
63
|
+
.option("--ci", "CI mode: exit with error code if health score below threshold")
|
|
64
|
+
.option("--report", "Upload results to Better i18n portal (requires GitHub Actions OIDC)")
|
|
65
|
+
.option("--skip-code", "Skip AST code analysis (hardcoded strings)")
|
|
66
|
+
.option("--skip-health", "Skip translation file health checks")
|
|
67
|
+
.option("--verbose", "Show detailed output")
|
|
68
|
+
.action(doctorCommand);
|
|
34
69
|
program.parse();
|
|
35
70
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint-style Terminal Reporter for i18n Doctor
|
|
3
|
+
*
|
|
4
|
+
* Renders a framed summary box with health score bar,
|
|
5
|
+
* category breakdown, and per-file diagnostic listing.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by react-doctor's FramedLine pattern:
|
|
8
|
+
* - Dual-track: plainText (width calc) + renderedText (ANSI colors)
|
|
9
|
+
* - Box-drawing characters for consistent alignment
|
|
10
|
+
* - Score bar with emoji indicators
|
|
11
|
+
*/
|
|
12
|
+
import type { DoctorReport } from "../doctor/index.js";
|
|
13
|
+
/**
|
|
14
|
+
* Print ESLint-style report to stdout.
|
|
15
|
+
*/
|
|
16
|
+
export declare function reportEslint(report: DoctorReport): void;
|
|
17
|
+
//# sourceMappingURL=doctor-eslint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-eslint.d.ts","sourceRoot":"","sources":["../../src/reporters/doctor-eslint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAuEvD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAwEvD"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint-style Terminal Reporter for i18n Doctor
|
|
3
|
+
*
|
|
4
|
+
* Renders a framed summary box with health score bar,
|
|
5
|
+
* category breakdown, and per-file diagnostic listing.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by react-doctor's FramedLine pattern:
|
|
8
|
+
* - Dual-track: plainText (width calc) + renderedText (ANSI colors)
|
|
9
|
+
* - Box-drawing characters for consistent alignment
|
|
10
|
+
* - Score bar with emoji indicators
|
|
11
|
+
*/
|
|
12
|
+
import { bold, cyan, dim, green, red, yellow } from "../utils/colors.js";
|
|
13
|
+
// ── Score Bar ────────────────────────────────────────────────────────
|
|
14
|
+
function renderScoreBar(score) {
|
|
15
|
+
const width = 20;
|
|
16
|
+
const filled = Math.round((score / 100) * width);
|
|
17
|
+
const empty = width - filled;
|
|
18
|
+
let color;
|
|
19
|
+
let emoji;
|
|
20
|
+
if (score >= 90) {
|
|
21
|
+
color = green;
|
|
22
|
+
emoji = "A+";
|
|
23
|
+
}
|
|
24
|
+
else if (score >= 80) {
|
|
25
|
+
color = green;
|
|
26
|
+
emoji = "A";
|
|
27
|
+
}
|
|
28
|
+
else if (score >= 70) {
|
|
29
|
+
color = cyan;
|
|
30
|
+
emoji = "B";
|
|
31
|
+
}
|
|
32
|
+
else if (score >= 50) {
|
|
33
|
+
color = yellow;
|
|
34
|
+
emoji = "C";
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
color = red;
|
|
38
|
+
emoji = "F";
|
|
39
|
+
}
|
|
40
|
+
const bar = color("█".repeat(filled)) + dim("░".repeat(empty));
|
|
41
|
+
return `${bar} ${bold(String(score))} ${dim(`/ 100`)} ${bold(emoji)}`;
|
|
42
|
+
}
|
|
43
|
+
// ── Category Table ──────────────────────────────────────────────────
|
|
44
|
+
function renderCategoryLine(category, score, count) {
|
|
45
|
+
const padded = category.padEnd(12);
|
|
46
|
+
const scoreStr = String(score).padStart(3);
|
|
47
|
+
let colorFn;
|
|
48
|
+
if (score >= 90)
|
|
49
|
+
colorFn = green;
|
|
50
|
+
else if (score >= 70)
|
|
51
|
+
colorFn = cyan;
|
|
52
|
+
else if (score >= 50)
|
|
53
|
+
colorFn = yellow;
|
|
54
|
+
else
|
|
55
|
+
colorFn = red;
|
|
56
|
+
const countStr = count > 0 ? dim(` (${count} issues)`) : dim(" (clean)");
|
|
57
|
+
return ` ${dim(padded)} ${colorFn(scoreStr)}${countStr}`;
|
|
58
|
+
}
|
|
59
|
+
// ── Diagnostic Listing ──────────────────────────────────────────────
|
|
60
|
+
function severityIcon(severity) {
|
|
61
|
+
if (severity === "error")
|
|
62
|
+
return red("✖");
|
|
63
|
+
if (severity === "warning")
|
|
64
|
+
return yellow("⚠");
|
|
65
|
+
return dim("ℹ");
|
|
66
|
+
}
|
|
67
|
+
function renderDiagnostic(d) {
|
|
68
|
+
const location = d.line > 0 ? `:${d.line}:${d.column}` : "";
|
|
69
|
+
const file = dim(`${d.filePath}${location}`);
|
|
70
|
+
const rule = dim(`[${d.rule}]`);
|
|
71
|
+
return ` ${severityIcon(d.severity)} ${d.message} ${rule}\n ${file}`;
|
|
72
|
+
}
|
|
73
|
+
// ── Main Reporter ───────────────────────────────────────────────────
|
|
74
|
+
/**
|
|
75
|
+
* Print ESLint-style report to stdout.
|
|
76
|
+
*/
|
|
77
|
+
export function reportEslint(report) {
|
|
78
|
+
const { score, summary, diagnostics } = report;
|
|
79
|
+
// ── Header Box ──────────────────────────────────────────────────
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(bold("┌─────────────────────────────────────────────┐"));
|
|
82
|
+
console.log(bold("│") + " i18n Doctor Report" + " ".repeat(25) + bold("│"));
|
|
83
|
+
console.log(bold("├─────────────────────────────────────────────┤"));
|
|
84
|
+
console.log(bold("│") + " " + renderScoreBar(score.total) + " " + bold("│"));
|
|
85
|
+
console.log(bold("│") + " " + (score.passed ? green("PASSED") : red("FAILED")) + dim(` (threshold: ${score.passThreshold})`) + " ".repeat(10) + bold("│"));
|
|
86
|
+
console.log(bold("└─────────────────────────────────────────────┘"));
|
|
87
|
+
console.log();
|
|
88
|
+
// ── Category Breakdown ──────────────────────────────────────────
|
|
89
|
+
console.log(bold("Category Scores:"));
|
|
90
|
+
const categories = ["Coverage", "Quality", "Code", "Structure", "Performance"];
|
|
91
|
+
for (const cat of categories) {
|
|
92
|
+
const catScore = score.categories[cat] ?? 100;
|
|
93
|
+
const count = summary.byCategory[cat] ?? 0;
|
|
94
|
+
console.log(renderCategoryLine(cat, catScore, count));
|
|
95
|
+
}
|
|
96
|
+
console.log();
|
|
97
|
+
// ── Summary Line ────────────────────────────────────────────────
|
|
98
|
+
const parts = [];
|
|
99
|
+
if (summary.errors > 0)
|
|
100
|
+
parts.push(red(`${summary.errors} errors`));
|
|
101
|
+
if (summary.warnings > 0)
|
|
102
|
+
parts.push(yellow(`${summary.warnings} warnings`));
|
|
103
|
+
if (summary.infos > 0)
|
|
104
|
+
parts.push(dim(`${summary.infos} info`));
|
|
105
|
+
if (parts.length > 0) {
|
|
106
|
+
console.log(` ${parts.join(", ")}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log(green(" No issues found!"));
|
|
110
|
+
}
|
|
111
|
+
console.log(dim(` ${summary.filesScanned} files scanned, ${summary.keysChecked} keys checked, ${summary.localesChecked} locales`));
|
|
112
|
+
console.log(dim(` Completed in ${(report.durationMs / 1000).toFixed(2)}s`));
|
|
113
|
+
console.log();
|
|
114
|
+
// ── Diagnostic Listing (errors and warnings only) ───────────────
|
|
115
|
+
const actionable = diagnostics.filter((d) => d.severity === "error" || d.severity === "warning");
|
|
116
|
+
if (actionable.length > 0) {
|
|
117
|
+
// Group by rule for readability
|
|
118
|
+
const byRule = new Map();
|
|
119
|
+
for (const d of actionable) {
|
|
120
|
+
const existing = byRule.get(d.rule) || [];
|
|
121
|
+
existing.push(d);
|
|
122
|
+
byRule.set(d.rule, existing);
|
|
123
|
+
}
|
|
124
|
+
for (const [rule, diags] of byRule) {
|
|
125
|
+
const maxShow = 10;
|
|
126
|
+
const shown = diags.slice(0, maxShow);
|
|
127
|
+
const hidden = diags.length - maxShow;
|
|
128
|
+
console.log(bold(`${rule} (${diags.length}):`));
|
|
129
|
+
for (const d of shown) {
|
|
130
|
+
console.log(renderDiagnostic(d));
|
|
131
|
+
}
|
|
132
|
+
if (hidden > 0) {
|
|
133
|
+
console.log(dim(` ... and ${hidden} more`));
|
|
134
|
+
}
|
|
135
|
+
console.log();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=doctor-eslint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-eslint.js","sourceRoot":"","sources":["../../src/reporters/doctor-eslint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Reporter for i18n Doctor
|
|
3
|
+
*
|
|
4
|
+
* Outputs the full DoctorReport as JSON.
|
|
5
|
+
* Used for CI pipelines, machine parsing, and API submission.
|
|
6
|
+
*/
|
|
7
|
+
import type { DoctorReport } from "../doctor/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Print full DoctorReport as formatted JSON to stdout.
|
|
10
|
+
*/
|
|
11
|
+
export declare function reportJson(report: DoctorReport): void;
|
|
12
|
+
//# sourceMappingURL=doctor-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-json.d.ts","sourceRoot":"","sources":["../../src/reporters/doctor-json.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAWrD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Reporter for i18n Doctor
|
|
3
|
+
*
|
|
4
|
+
* Outputs the full DoctorReport as JSON.
|
|
5
|
+
* Used for CI pipelines, machine parsing, and API submission.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Print full DoctorReport as formatted JSON to stdout.
|
|
9
|
+
*/
|
|
10
|
+
export function reportJson(report) {
|
|
11
|
+
// Convert Set-like data structures if any (shouldn't be in report, but safety)
|
|
12
|
+
const serializable = JSON.parse(JSON.stringify(report, (_key, value) => {
|
|
13
|
+
if (value instanceof Set)
|
|
14
|
+
return Array.from(value);
|
|
15
|
+
if (value instanceof Map)
|
|
16
|
+
return Object.fromEntries(value);
|
|
17
|
+
return value;
|
|
18
|
+
}));
|
|
19
|
+
console.log(JSON.stringify(serializable, null, 2));
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=doctor-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-json.js","sourceRoot":"","sources":["../../src/reporters/doctor-json.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,+EAA+E;IAC/E,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAC7B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACrC,IAAI,KAAK,YAAY,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,KAAK,YAAY,GAAG;YAAE,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor Report — API Reporter
|
|
3
|
+
*
|
|
4
|
+
* Sends a DoctorReport to the Better i18n API for storage and trend tracking.
|
|
5
|
+
* Authentication is via GitHub Actions OIDC — no API keys needed.
|
|
6
|
+
*
|
|
7
|
+
* Graceful degradation: if OIDC is unavailable (running locally, missing
|
|
8
|
+
* permissions), it warns and returns null instead of failing.
|
|
9
|
+
*/
|
|
10
|
+
import type { DoctorReport } from "../doctor/index.js";
|
|
11
|
+
interface ReportResult {
|
|
12
|
+
reportId: string;
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* POST a doctor report to the Better i18n API.
|
|
17
|
+
*
|
|
18
|
+
* @param report - The DoctorReport to upload
|
|
19
|
+
* @returns Report ID and dashboard URL, or null if reporting failed/unavailable
|
|
20
|
+
*/
|
|
21
|
+
export declare function reportToApi(report: DoctorReport): Promise<ReportResult | null>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=doctor-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-report.d.ts","sourceRoot":"","sources":["../../src/reporters/doctor-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA4D9B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor Report — API Reporter
|
|
3
|
+
*
|
|
4
|
+
* Sends a DoctorReport to the Better i18n API for storage and trend tracking.
|
|
5
|
+
* Authentication is via GitHub Actions OIDC — no API keys needed.
|
|
6
|
+
*
|
|
7
|
+
* Graceful degradation: if OIDC is unavailable (running locally, missing
|
|
8
|
+
* permissions), it warns and returns null instead of failing.
|
|
9
|
+
*/
|
|
10
|
+
import { fetchGitHubOidcToken, isGitHubActionsWithOidc } from "../context/oidc.js";
|
|
11
|
+
const DEFAULT_API_URL = "https://api.better-i18n.com";
|
|
12
|
+
/**
|
|
13
|
+
* POST a doctor report to the Better i18n API.
|
|
14
|
+
*
|
|
15
|
+
* @param report - The DoctorReport to upload
|
|
16
|
+
* @returns Report ID and dashboard URL, or null if reporting failed/unavailable
|
|
17
|
+
*/
|
|
18
|
+
export async function reportToApi(report) {
|
|
19
|
+
// 1. Check if we can get an OIDC token
|
|
20
|
+
if (!isGitHubActionsWithOidc()) {
|
|
21
|
+
console.warn(" Warning: --report requires GitHub Actions with OIDC.\n" +
|
|
22
|
+
" Add `permissions: id-token: write` to your workflow.\n" +
|
|
23
|
+
" Skipping report upload.");
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const token = await fetchGitHubOidcToken("better-i18n");
|
|
27
|
+
if (!token) {
|
|
28
|
+
console.warn(" Warning: Failed to fetch OIDC token. Skipping report upload.");
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
// 2. Send report to API
|
|
32
|
+
const apiUrl = process.env.BETTER_I18N_API_URL || DEFAULT_API_URL;
|
|
33
|
+
try {
|
|
34
|
+
const response = await fetch(`${apiUrl}/api/doctor/report`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
Authorization: `Bearer ${token}`,
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify(report),
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
44
|
+
console.warn(` Warning: Report upload failed (${response.status}): ${errorText}`);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const data = (await response.json());
|
|
48
|
+
if (!data.reportId) {
|
|
49
|
+
console.warn(" Warning: Unexpected API response. Skipping.");
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
reportId: data.reportId,
|
|
54
|
+
url: data.url || `${apiUrl}/doctor/${data.reportId}`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.warn(` Warning: Report upload failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=doctor-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-report.js","sourceRoot":"","sources":["../../src/reporters/doctor-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAEnF,MAAM,eAAe,GAAG,6BAA6B,CAAC;AAOtD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAoB;IAEpB,uCAAuC;IACvC,IAAI,CAAC,uBAAuB,EAAE,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CACV,0DAA0D;YAC1D,0DAA0D;YAC1D,2BAA2B,CAC5B,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,aAAa,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CACV,gEAAgE,CACjE,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wBAAwB;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,eAAe,CAAC;IAElE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,oBAAoB,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,EAAE;aACjC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAC7B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,CACV,oCAAoC,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CACrE,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGlC,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,WAAW,IAAI,CAAC,QAAQ,EAAE;SACrD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CACV,oCAAoC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC7F,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -21,8 +21,8 @@ export function reportEslintStyle(issues, rootDir, maxIssues) {
|
|
|
21
21
|
existing.push(issue);
|
|
22
22
|
byFile.set(issue.file, existing);
|
|
23
23
|
}
|
|
24
|
-
let
|
|
25
|
-
let
|
|
24
|
+
let _errorCount = 0;
|
|
25
|
+
let _missingCount = 0;
|
|
26
26
|
// Print each file's issues grouped by file
|
|
27
27
|
for (const [file, fileIssues] of byFile.entries()) {
|
|
28
28
|
const relPath = relative(rootDir, file);
|
|
@@ -39,10 +39,10 @@ export function reportEslintStyle(issues, rootDir, maxIssues) {
|
|
|
39
39
|
const rule = dim(`i18n/${issue.type}`);
|
|
40
40
|
console.log(` ${loc} ${severity} ${text} ${rule}`);
|
|
41
41
|
if (issue.severity === "error") {
|
|
42
|
-
|
|
42
|
+
_errorCount++;
|
|
43
43
|
}
|
|
44
44
|
else {
|
|
45
|
-
|
|
45
|
+
_missingCount++;
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-style.js","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAElE;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAe,EACf,OAAe,EACf,SAAkB;IAElB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEhC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,MAAM,OAAO,GAAG,SAAS,IAAI,WAAW,GAAG,SAAS,CAAC;IAErD,gBAAgB;IAChB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,
|
|
1
|
+
{"version":3,"file":"eslint-style.js","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAElE;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAe,EACf,OAAe,EACf,SAAkB;IAElB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEhC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,MAAM,OAAO,GAAG,SAAS,IAAI,WAAW,GAAG,SAAS,CAAC;IAErD,gBAAgB;IAChB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,2CAA2C;IAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAExC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,2CAA2C;QAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QAEzC,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,gDAAgD;YAChD,wCAAwC;YACxC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACjD,MAAM,QAAQ,GACZ,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChE,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAEvC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;YAEvD,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBAC/B,WAAW,EAAE,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,aAAa,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;QAC1C,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CACT,GAAG,CAAC,WAAW,SAAS,gBAAgB,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACpE,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAChC,CAAC,MAAM,CAAC;IACT,MAAM,KAAK,GAAG,eAAe,GAAG,iBAAiB,CAAC;IAClD,MAAM,OAAO,GAAG,EAAE,CAAC;IACnB,IAAI,eAAe,GAAG,CAAC;QACrB,OAAO,CAAC,IAAI,CACV,GAAG,CAAC,GAAG,eAAe,SAAS,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACjE,CAAC;IACJ,IAAI,iBAAiB,GAAG,CAAC;QACvB,OAAO,CAAC,IAAI,CACV,MAAM,CACJ,GAAG,iBAAiB,uBAAuB,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9E,CACF,CAAC;IAEJ,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,KAAK,KAAK,WAAW,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,GAAW,EAAE,MAAc;IACrD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,IAAI,OAAO,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,IAAI,OAAO,GAAG,CAAC;IACpD,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule Metadata — Category and Help Maps
|
|
3
|
+
*
|
|
4
|
+
* Centralized metadata for all i18n Doctor rules.
|
|
5
|
+
* Following react-doctor's pattern: rules produce only `message`,
|
|
6
|
+
* category and help text are external for central management.
|
|
7
|
+
*
|
|
8
|
+
* To add a new rule:
|
|
9
|
+
* 1. Add entry to RULE_CATEGORY_MAP
|
|
10
|
+
* 2. Add entry to RULE_HELP_MAP
|
|
11
|
+
* 3. Implement the rule in src/rules/health/ or src/rules/code/
|
|
12
|
+
*/
|
|
13
|
+
import type { I18nDiagnostic } from "./registry.js";
|
|
14
|
+
/**
|
|
15
|
+
* Maps rule ID → category.
|
|
16
|
+
*
|
|
17
|
+
* react-doctor uses RULE_CATEGORY_MAP + PLUGIN_CATEGORY_MAP with fallback.
|
|
18
|
+
* We simplify to a single map since all rules are "better-i18n" plugin.
|
|
19
|
+
*/
|
|
20
|
+
export declare const RULE_CATEGORY_MAP: Record<string, I18nDiagnostic["category"]>;
|
|
21
|
+
/**
|
|
22
|
+
* Maps rule ID → actionable fix suggestion.
|
|
23
|
+
*
|
|
24
|
+
* react-doctor stores these in RULE_HELP_MAP in run-oxlint.ts.
|
|
25
|
+
* We centralize them here alongside categories.
|
|
26
|
+
*/
|
|
27
|
+
export declare const RULE_HELP_MAP: Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* Default severity for code rules.
|
|
30
|
+
*
|
|
31
|
+
* Health rules define defaultSeverity on the rule object itself.
|
|
32
|
+
* Code rules (from the analyzer) have severity embedded in their output,
|
|
33
|
+
* but this map provides fallback/override capability.
|
|
34
|
+
*/
|
|
35
|
+
export declare const RULE_DEFAULT_SEVERITY: Record<string, I18nDiagnostic["severity"]>;
|
|
36
|
+
//# sourceMappingURL=categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/rules/categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAgBxE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA4BhD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAgB5E,CAAC"}
|