@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.
Files changed (142) hide show
  1. package/dist/analyzer/dynamic-matcher.d.ts +53 -0
  2. package/dist/analyzer/dynamic-matcher.d.ts.map +1 -0
  3. package/dist/analyzer/dynamic-matcher.js +93 -0
  4. package/dist/analyzer/dynamic-matcher.js.map +1 -0
  5. package/dist/analyzer/index.d.ts +13 -4
  6. package/dist/analyzer/index.d.ts.map +1 -1
  7. package/dist/analyzer/index.js +165 -22
  8. package/dist/analyzer/index.js.map +1 -1
  9. package/dist/analyzer/rules/data-structure.d.ts +13 -0
  10. package/dist/analyzer/rules/data-structure.d.ts.map +1 -0
  11. package/dist/analyzer/rules/data-structure.js +264 -0
  12. package/dist/analyzer/rules/data-structure.js.map +1 -0
  13. package/dist/analyzer/rules/index.d.ts +10 -7
  14. package/dist/analyzer/rules/index.d.ts.map +1 -1
  15. package/dist/analyzer/rules/index.js +10 -7
  16. package/dist/analyzer/rules/index.js.map +1 -1
  17. package/dist/analyzer/rules/jsx-text.js +1 -1
  18. package/dist/analyzer/rules/jsx-text.js.map +1 -1
  19. package/dist/analyzer/rules/translation-function.d.ts.map +1 -1
  20. package/dist/analyzer/rules/translation-function.js +94 -6
  21. package/dist/analyzer/rules/translation-function.js.map +1 -1
  22. package/dist/analyzer/types.d.ts +28 -3
  23. package/dist/analyzer/types.d.ts.map +1 -1
  24. package/dist/commands/check.d.ts +14 -0
  25. package/dist/commands/check.d.ts.map +1 -0
  26. package/dist/commands/check.js +70 -0
  27. package/dist/commands/check.js.map +1 -0
  28. package/dist/commands/doctor.d.ts +20 -0
  29. package/dist/commands/doctor.d.ts.map +1 -0
  30. package/dist/commands/doctor.js +77 -0
  31. package/dist/commands/doctor.js.map +1 -0
  32. package/dist/commands/sync.d.ts +1 -0
  33. package/dist/commands/sync.d.ts.map +1 -1
  34. package/dist/commands/sync.js +158 -272
  35. package/dist/commands/sync.js.map +1 -1
  36. package/dist/context/detector.js +1 -1
  37. package/dist/context/detector.js.map +1 -1
  38. package/dist/context/oidc.d.ts +33 -0
  39. package/dist/context/oidc.d.ts.map +1 -0
  40. package/dist/context/oidc.js +63 -0
  41. package/dist/context/oidc.js.map +1 -0
  42. package/dist/doctor/index.d.ts +65 -0
  43. package/dist/doctor/index.d.ts.map +1 -0
  44. package/dist/doctor/index.js +252 -0
  45. package/dist/doctor/index.js.map +1 -0
  46. package/dist/doctor/project-discovery.d.ts +37 -0
  47. package/dist/doctor/project-discovery.d.ts.map +1 -0
  48. package/dist/doctor/project-discovery.js +140 -0
  49. package/dist/doctor/project-discovery.js.map +1 -0
  50. package/dist/doctor/score.d.ts +41 -0
  51. package/dist/doctor/score.d.ts.map +1 -0
  52. package/dist/doctor/score.js +107 -0
  53. package/dist/doctor/score.js.map +1 -0
  54. package/dist/index.js +35 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/reporters/doctor-eslint.d.ts +17 -0
  57. package/dist/reporters/doctor-eslint.d.ts.map +1 -0
  58. package/dist/reporters/doctor-eslint.js +139 -0
  59. package/dist/reporters/doctor-eslint.js.map +1 -0
  60. package/dist/reporters/doctor-json.d.ts +12 -0
  61. package/dist/reporters/doctor-json.d.ts.map +1 -0
  62. package/dist/reporters/doctor-json.js +21 -0
  63. package/dist/reporters/doctor-json.js.map +1 -0
  64. package/dist/reporters/doctor-report.d.ts +23 -0
  65. package/dist/reporters/doctor-report.d.ts.map +1 -0
  66. package/dist/reporters/doctor-report.js +62 -0
  67. package/dist/reporters/doctor-report.js.map +1 -0
  68. package/dist/reporters/eslint-style.js +4 -4
  69. package/dist/reporters/eslint-style.js.map +1 -1
  70. package/dist/rules/categories.d.ts +36 -0
  71. package/dist/rules/categories.d.ts.map +1 -0
  72. package/dist/rules/categories.js +80 -0
  73. package/dist/rules/categories.js.map +1 -0
  74. package/dist/rules/code/index.d.ts +9 -0
  75. package/dist/rules/code/index.d.ts.map +1 -0
  76. package/dist/rules/code/index.js +9 -0
  77. package/dist/rules/code/index.js.map +1 -0
  78. package/dist/rules/code/jsx-attribute.d.ts +12 -0
  79. package/dist/rules/code/jsx-attribute.d.ts.map +1 -0
  80. package/dist/rules/code/jsx-attribute.js +78 -0
  81. package/dist/rules/code/jsx-attribute.js.map +1 -0
  82. package/dist/rules/code/jsx-text.d.ts +12 -0
  83. package/dist/rules/code/jsx-text.d.ts.map +1 -0
  84. package/dist/rules/code/jsx-text.js +47 -0
  85. package/dist/rules/code/jsx-text.js.map +1 -0
  86. package/dist/rules/code/string-variable.d.ts +13 -0
  87. package/dist/rules/code/string-variable.d.ts.map +1 -0
  88. package/dist/rules/code/string-variable.js +185 -0
  89. package/dist/rules/code/string-variable.js.map +1 -0
  90. package/dist/rules/code/ternary-locale.d.ts +12 -0
  91. package/dist/rules/code/ternary-locale.d.ts.map +1 -0
  92. package/dist/rules/code/ternary-locale.js +53 -0
  93. package/dist/rules/code/ternary-locale.js.map +1 -0
  94. package/dist/rules/code/toast-message.d.ts +13 -0
  95. package/dist/rules/code/toast-message.d.ts.map +1 -0
  96. package/dist/rules/code/toast-message.js +101 -0
  97. package/dist/rules/code/toast-message.js.map +1 -0
  98. package/dist/rules/extraction/data-structure.d.ts +13 -0
  99. package/dist/rules/extraction/data-structure.d.ts.map +1 -0
  100. package/dist/rules/extraction/data-structure.js +212 -0
  101. package/dist/rules/extraction/data-structure.js.map +1 -0
  102. package/dist/rules/extraction/index.d.ts +6 -0
  103. package/dist/rules/extraction/index.d.ts.map +1 -0
  104. package/dist/rules/extraction/index.js +6 -0
  105. package/dist/rules/extraction/index.js.map +1 -0
  106. package/dist/rules/extraction/translation-function.d.ts +12 -0
  107. package/dist/rules/extraction/translation-function.d.ts.map +1 -0
  108. package/dist/rules/extraction/translation-function.js +153 -0
  109. package/dist/rules/extraction/translation-function.js.map +1 -0
  110. package/dist/rules/health/index.d.ts +16 -0
  111. package/dist/rules/health/index.d.ts.map +1 -0
  112. package/dist/rules/health/index.js +22 -0
  113. package/dist/rules/health/index.js.map +1 -0
  114. package/dist/rules/health/missing-translations.d.ts +13 -0
  115. package/dist/rules/health/missing-translations.d.ts.map +1 -0
  116. package/dist/rules/health/missing-translations.js +48 -0
  117. package/dist/rules/health/missing-translations.js.map +1 -0
  118. package/dist/rules/health/orphan-keys.d.ts +16 -0
  119. package/dist/rules/health/orphan-keys.d.ts.map +1 -0
  120. package/dist/rules/health/orphan-keys.js +50 -0
  121. package/dist/rules/health/orphan-keys.js.map +1 -0
  122. package/dist/rules/health/placeholder-mismatch.d.ts +32 -0
  123. package/dist/rules/health/placeholder-mismatch.d.ts.map +1 -0
  124. package/dist/rules/health/placeholder-mismatch.js +120 -0
  125. package/dist/rules/health/placeholder-mismatch.js.map +1 -0
  126. package/dist/rules/registry.d.ts +84 -0
  127. package/dist/rules/registry.d.ts.map +1 -0
  128. package/dist/rules/registry.js +11 -0
  129. package/dist/rules/registry.js.map +1 -0
  130. package/dist/utils/cdn-client.d.ts +30 -0
  131. package/dist/utils/cdn-client.d.ts.map +1 -0
  132. package/dist/utils/cdn-client.js +59 -0
  133. package/dist/utils/cdn-client.js.map +1 -0
  134. package/dist/utils/json-keys.d.ts +60 -0
  135. package/dist/utils/json-keys.d.ts.map +1 -0
  136. package/dist/utils/json-keys.js +103 -0
  137. package/dist/utils/json-keys.js.map +1 -0
  138. package/dist/utils/key-comparison.d.ts +67 -0
  139. package/dist/utils/key-comparison.d.ts.map +1 -0
  140. package/dist/utils/key-comparison.js +299 -0
  141. package/dist/utils/key-comparison.js.map +1 -0
  142. 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;AAEjD,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CACV,sEAAsE,CACvE;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CACL,uBAAuB,EACvB,oDAAoD,EACpD,QAAQ,CACT;KACA,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC;KACzD,MAAM,CAAC,MAAM,EAAE,+CAA+C,CAAC;KAC/D,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC;KAChD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;KAC/D,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO,CAAC,KAAK,EAAE,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 errorCount = 0;
25
- let missingCount = 0;
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
- errorCount++;
42
+ _errorCount++;
43
43
  }
44
44
  else {
45
- missingCount++;
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":"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"}
1
+ {"version":3,"file":"eslint-style.js","sourceRoot":"","sources":["../../src/reporters/eslint-style.ts"],"names":[],"mappings":"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"}
@@ -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"}