@better-i18n/cli 0.2.0 → 0.2.3

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 (45) hide show
  1. package/README.md +53 -0
  2. package/dist/analyzer/index.d.ts.map +1 -1
  3. package/dist/analyzer/index.js +25 -0
  4. package/dist/analyzer/index.js.map +1 -1
  5. package/dist/analyzer/types.d.ts +1 -0
  6. package/dist/analyzer/types.d.ts.map +1 -1
  7. package/dist/commands/doctor.d.ts +2 -0
  8. package/dist/commands/doctor.d.ts.map +1 -1
  9. package/dist/commands/doctor.js +3 -2
  10. package/dist/commands/doctor.js.map +1 -1
  11. package/dist/context/detector.js +16 -0
  12. package/dist/context/detector.js.map +1 -1
  13. package/dist/doctor/index.d.ts +2 -0
  14. package/dist/doctor/index.d.ts.map +1 -1
  15. package/dist/doctor/index.js +113 -12
  16. package/dist/doctor/index.js.map +1 -1
  17. package/dist/doctor/score.d.ts +23 -17
  18. package/dist/doctor/score.d.ts.map +1 -1
  19. package/dist/doctor/score.js +85 -77
  20. package/dist/doctor/score.js.map +1 -1
  21. package/dist/index.js +3 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/reporters/doctor-eslint.d.ts +4 -1
  24. package/dist/reporters/doctor-eslint.d.ts.map +1 -1
  25. package/dist/reporters/doctor-eslint.js +108 -28
  26. package/dist/reporters/doctor-eslint.js.map +1 -1
  27. package/dist/reporters/doctor-report.d.ts +9 -4
  28. package/dist/reporters/doctor-report.d.ts.map +1 -1
  29. package/dist/reporters/doctor-report.js +69 -9
  30. package/dist/reporters/doctor-report.js.map +1 -1
  31. package/dist/rules/categories.d.ts.map +1 -1
  32. package/dist/rules/categories.js +9 -0
  33. package/dist/rules/categories.js.map +1 -1
  34. package/dist/rules/health/missing-translations.js +2 -2
  35. package/dist/rules/health/missing-translations.js.map +1 -1
  36. package/dist/rules/health/orphan-keys.js +2 -2
  37. package/dist/rules/health/orphan-keys.js.map +1 -1
  38. package/dist/rules/health/placeholder-mismatch.js +3 -3
  39. package/dist/rules/health/placeholder-mismatch.js.map +1 -1
  40. package/dist/rules/registry.d.ts +2 -0
  41. package/dist/rules/registry.d.ts.map +1 -1
  42. package/dist/utils/key-comparison.d.ts.map +1 -1
  43. package/dist/utils/key-comparison.js +5 -1
  44. package/dist/utils/key-comparison.js.map +1 -1
  45. package/package.json +1 -1
@@ -1,20 +1,27 @@
1
1
  /**
2
2
  * Health Score Calculator
3
3
  *
4
- * Calculates a weighted health score (0-100) from diagnostics.
4
+ * Calculates an occurrence-based health score (0-100) from diagnostics.
5
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
6
+ * Unlike react-doctor (which counts unique rules), i18n doctor penalizes
7
+ * per occurrence because each hardcoded string is an independent task
8
+ * that requires its own t() wrapping.
11
9
  *
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)
10
+ * Overall score: 100 - (errors x 3.0) - Σ min(ruleWarnings x 0.15, 20)
11
+ * Category score: 100 - (errors x 5.0) - Σ min(ruleWarnings x 0.5, 80)
12
+ *
13
+ * Per-rule warning cap: Each rule can penalize the overall score by at most
14
+ * MAX_RULE_WARNING_PENALTY (20) points, and each category by at most
15
+ * MAX_RULE_CAT_PENALTY (80) points. This prevents a single rule with
16
+ * thousands of warnings (e.g. missing-in-remote) from zeroing the score.
17
+ * Errors are NOT capped.
18
+ *
19
+ * Calibration targets:
20
+ * 0E, 0W → 100
21
+ * 0E, 104W → 84 (single rule, cap threshold = 133)
22
+ * 10E, 20W → 67
23
+ * 5E, 0W → 85
24
+ * 1E, 0W → 97
18
25
  */
19
26
  import type { I18nDiagnostic } from "../rules/registry.js";
20
27
  export interface HealthScore {
@@ -31,11 +38,10 @@ export interface HealthScore {
31
38
  * Calculate health score from diagnostics.
32
39
  *
33
40
  * 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
41
+ * 1. Count total errors and per-rule warnings (info ignored)
42
+ * 2. Overall = 100 - (errors x 3.0) - Σ min(ruleWarnings x 0.15, 20), clamped [0,100]
43
+ * 3. Per category = 100 - (catErrors x 5.0) - Σ min(ruleWarnings x 0.5, 80), clamped [0,100]
44
+ * 4. passed = overall >= threshold
39
45
  */
40
46
  export declare function calculateHealthScore(diagnostics: I18nDiagnostic[], passThreshold?: number): HealthScore;
41
47
  //# sourceMappingURL=score.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/doctor/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAyB3D,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;AAID;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,cAAc,EAAE,EAC7B,aAAa,SAAiB,GAC7B,WAAW,CA0Eb"}
@@ -1,55 +1,85 @@
1
1
  /**
2
2
  * Health Score Calculator
3
3
  *
4
- * Calculates a weighted health score (0-100) from diagnostics.
4
+ * Calculates an occurrence-based health score (0-100) from diagnostics.
5
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
6
+ * Unlike react-doctor (which counts unique rules), i18n doctor penalizes
7
+ * per occurrence because each hardcoded string is an independent task
8
+ * that requires its own t() wrapping.
11
9
  *
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)
10
+ * Overall score: 100 - (errors x 3.0) - Σ min(ruleWarnings x 0.15, 20)
11
+ * Category score: 100 - (errors x 5.0) - Σ min(ruleWarnings x 0.5, 80)
12
+ *
13
+ * Per-rule warning cap: Each rule can penalize the overall score by at most
14
+ * MAX_RULE_WARNING_PENALTY (20) points, and each category by at most
15
+ * MAX_RULE_CAT_PENALTY (80) points. This prevents a single rule with
16
+ * thousands of warnings (e.g. missing-in-remote) from zeroing the score.
17
+ * Errors are NOT capped.
18
+ *
19
+ * Calibration targets:
20
+ * 0E, 0W → 100
21
+ * 0E, 104W → 84 (single rule, cap threshold = 133)
22
+ * 10E, 20W → 67
23
+ * 5E, 0W → 85
24
+ * 1E, 0W → 97
18
25
  */
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
- };
26
+ // ── Penalty Constants ───────────────────────────────────────────────
27
+ /** Per-occurrence penalty for errors on the overall score */
28
+ const ERROR_PENALTY = 3.0;
29
+ /** Per-occurrence penalty for warnings on the overall score */
30
+ const WARNING_PENALTY = 0.15;
31
+ /** Max penalty any single rule's warnings can contribute to the overall score */
32
+ const MAX_RULE_WARNING_PENALTY = 20;
33
+ /** Per-occurrence penalty for errors within a category */
34
+ const CAT_ERROR_PENALTY = 5.0;
35
+ /** Per-occurrence penalty for warnings within a category */
36
+ const CAT_WARNING_PENALTY = 0.5;
37
+ /** Max penalty any single rule's warnings can contribute to a category score */
38
+ const MAX_RULE_CAT_PENALTY = 80;
39
+ /** Default pass/fail threshold */
40
+ const PASS_THRESHOLD = 70;
41
+ // ── Calculator ──────────────────────────────────────────────────────
34
42
  /**
35
43
  * Calculate health score from diagnostics.
36
44
  *
37
45
  * 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
46
+ * 1. Count total errors and per-rule warnings (info ignored)
47
+ * 2. Overall = 100 - (errors x 3.0) - Σ min(ruleWarnings x 0.15, 20), clamped [0,100]
48
+ * 3. Per category = 100 - (catErrors x 5.0) - Σ min(ruleWarnings x 0.5, 80), clamped [0,100]
49
+ * 4. passed = overall >= threshold
43
50
  */
44
- export function calculateHealthScore(diagnostics, passThreshold = 70) {
45
- // Group by category
46
- const byCategory = new Map();
51
+ export function calculateHealthScore(diagnostics, passThreshold = PASS_THRESHOLD) {
52
+ // Count totals
53
+ let totalErrors = 0;
54
+ // Per-rule warning counts (for capped overall penalty)
55
+ const ruleWarningCounts = new Map();
56
+ // Count per category
57
+ const catErrors = new Map();
58
+ // Per-category, per-rule warning counts (for capped category penalty)
59
+ const catRuleWarnings = new Map();
47
60
  for (const d of diagnostics) {
48
- const existing = byCategory.get(d.category) || [];
49
- existing.push(d);
50
- byCategory.set(d.category, existing);
61
+ if (d.severity === "error") {
62
+ totalErrors++;
63
+ catErrors.set(d.category, (catErrors.get(d.category) || 0) + 1);
64
+ }
65
+ else if (d.severity === "warning") {
66
+ ruleWarningCounts.set(d.rule, (ruleWarningCounts.get(d.rule) || 0) + 1);
67
+ if (!catRuleWarnings.has(d.category)) {
68
+ catRuleWarnings.set(d.category, new Map());
69
+ }
70
+ const ruleMap = catRuleWarnings.get(d.category);
71
+ ruleMap.set(d.rule, (ruleMap.get(d.rule) || 0) + 1);
72
+ }
73
+ // "info" diagnostics don't affect score
74
+ }
75
+ // Overall score — per-rule capped warning penalty
76
+ let totalWarningPenalty = 0;
77
+ for (const count of ruleWarningCounts.values()) {
78
+ totalWarningPenalty += Math.min(count * WARNING_PENALTY, MAX_RULE_WARNING_PENALTY);
51
79
  }
52
- // All possible categories
80
+ const rawTotal = 100 - totalErrors * ERROR_PENALTY - totalWarningPenalty;
81
+ const total = clamp(Math.round(rawTotal));
82
+ // Per-category scores
53
83
  const allCategories = [
54
84
  "Coverage",
55
85
  "Quality",
@@ -57,51 +87,29 @@ export function calculateHealthScore(diagnostics, passThreshold = 70) {
57
87
  "Structure",
58
88
  "Performance",
59
89
  ];
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);
90
+ const categories = {};
91
+ for (const cat of allCategories) {
92
+ const errors = catErrors.get(cat) || 0;
93
+ // Sum per-rule capped warning penalties for this category
94
+ let catWarningPenalty = 0;
95
+ const ruleMap = catRuleWarnings.get(cat);
96
+ if (ruleMap) {
97
+ for (const count of ruleMap.values()) {
98
+ catWarningPenalty += Math.min(count * CAT_WARNING_PENALTY, MAX_RULE_CAT_PENALTY);
76
99
  }
77
- // "info" diagnostics don't affect score
78
100
  }
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));
101
+ const rawCat = 100 - errors * CAT_ERROR_PENALTY - catWarningPenalty;
102
+ categories[cat] = clamp(Math.round(rawCat));
82
103
  }
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
104
  return {
101
105
  total,
102
- categories: categoryScores,
106
+ categories,
103
107
  passed: total >= passThreshold,
104
108
  passThreshold,
105
109
  };
106
110
  }
111
+ // ── Helpers ─────────────────────────────────────────────────────────
112
+ function clamp(value, min = 0, max = 100) {
113
+ return Math.max(min, Math.min(max, value));
114
+ }
107
115
  //# sourceMappingURL=score.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/doctor/score.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/doctor/score.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -61,9 +61,11 @@ program
61
61
  .option("-d, --dir <path>", "Directory to scan (default: current directory)")
62
62
  .option("-f, --format <type>", "Output format: eslint, json", "eslint")
63
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)")
64
+ .option("--report", "Upload results to Better i18n portal (requires GitHub Actions OIDC or --api-key)")
65
+ .option("--api-key <key>", "Better Auth API key for non-GitHub CI (local dev, GitLab, Jenkins)")
65
66
  .option("--skip-code", "Skip AST code analysis (hardcoded strings)")
66
67
  .option("--skip-health", "Skip translation file health checks")
68
+ .option("--skip-sync", "Skip remote CDN comparison")
67
69
  .option("--verbose", "Show detailed output")
68
70
  .action(doctorCommand);
69
71
  program.parse();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,9 @@
12
12
  import type { DoctorReport } from "../doctor/index.js";
13
13
  /**
14
14
  * Print ESLint-style report to stdout.
15
+ *
16
+ * When verbose is true, file:line listings are shown under each rule group
17
+ * (react-doctor pattern). Without verbose, only rule summary + count is shown.
15
18
  */
16
- export declare function reportEslint(report: DoctorReport): void;
19
+ export declare function reportEslint(report: DoctorReport, verbose?: boolean): void;
17
20
  //# sourceMappingURL=doctor-eslint.d.ts.map
@@ -1 +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"}
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;AAqHvD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,UAAQ,GAAG,IAAI,CA2HxE"}
@@ -56,34 +56,77 @@ function renderCategoryLine(category, score, count) {
56
56
  const countStr = count > 0 ? dim(` (${count} issues)`) : dim(" (clean)");
57
57
  return ` ${dim(padded)} ${colorFn(scoreStr)}${countStr}`;
58
58
  }
59
- // ── Diagnostic Listing ──────────────────────────────────────────────
60
- function severityIcon(severity) {
59
+ // ── Display Limits ──────────────────────────────────────────────────
60
+ const MAX_RULE_GROUPS = 5;
61
+ const MAX_ITEMS_PER_GROUP = 5;
62
+ const MAX_ITEMS_PER_GROUP_VERBOSE = 20;
63
+ // ── Diagnostic Helpers (react-doctor pattern) ───────────────────────
64
+ const SEVERITY_ORDER = {
65
+ error: 0,
66
+ warning: 1,
67
+ info: 2,
68
+ };
69
+ /** Rules that produce key-based diagnostics (namespace/key format) */
70
+ const KEY_BASED_RULES = new Set([
71
+ "missing-in-remote",
72
+ "unused-remote-key",
73
+ ]);
74
+ function colorizeBySeverity(text, severity) {
61
75
  if (severity === "error")
62
- return red("✖");
76
+ return red(text);
63
77
  if (severity === "warning")
64
- return yellow("⚠");
65
- return dim("ℹ");
78
+ return yellow(text);
79
+ return dim(text);
66
80
  }
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}`;
81
+ function sortBySeverityAndCount(groups) {
82
+ return [...groups].sort(([, a], [, b]) => {
83
+ const sevDiff = (SEVERITY_ORDER[a[0].severity] ?? 2) -
84
+ (SEVERITY_ORDER[b[0].severity] ?? 2);
85
+ if (sevDiff !== 0)
86
+ return sevDiff;
87
+ return b.length - a.length; // more issues first
88
+ });
89
+ }
90
+ function buildFileLineMap(diagnostics) {
91
+ const fileLines = new Map();
92
+ for (const d of diagnostics) {
93
+ const lines = fileLines.get(d.filePath) ?? [];
94
+ if (d.line > 0)
95
+ lines.push(d.line);
96
+ fileLines.set(d.filePath, lines);
97
+ }
98
+ return fileLines;
99
+ }
100
+ function buildKeyEntries(diagnostics) {
101
+ const entries = [];
102
+ for (const d of diagnostics) {
103
+ if (d.key) {
104
+ const prefix = d.namespace ? `${d.namespace}/` : "";
105
+ entries.push(`${prefix}${d.key}`);
106
+ }
107
+ }
108
+ return entries;
72
109
  }
73
110
  // ── Main Reporter ───────────────────────────────────────────────────
74
111
  /**
75
112
  * Print ESLint-style report to stdout.
113
+ *
114
+ * When verbose is true, file:line listings are shown under each rule group
115
+ * (react-doctor pattern). Without verbose, only rule summary + count is shown.
76
116
  */
77
- export function reportEslint(report) {
117
+ export function reportEslint(report, verbose = false) {
78
118
  const { score, summary, diagnostics } = report;
79
119
  // ── Header Box ──────────────────────────────────────────────────
80
120
  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("└─────────────────────────────────────────────┘"));
121
+ console.log(bold("╭──────────────────────────────────────────────╮"));
122
+ console.log(bold("│") + " " + bold("│"));
123
+ console.log(bold("") + " 🌐 " + bold("better-i18n") + dim(" · i18n Doctor Report") + " " + bold("│"));
124
+ console.log(bold("│") + dim(" hello · hola · 你好 · こんにちは · 안녕") + " " + bold("│"));
125
+ console.log(bold("│") + " " + bold("│"));
126
+ console.log(bold("├──────────────────────────────────────────────┤"));
127
+ console.log(bold("│") + " " + renderScoreBar(score.total) + " " + bold("│"));
128
+ console.log(bold("│") + " " + (score.passed ? green("PASSED") : red("FAILED")) + dim(` (threshold: ${score.passThreshold})`) + " ".repeat(11) + bold("│"));
129
+ console.log(bold("╰──────────────────────────────────────────────╯"));
87
130
  console.log();
88
131
  // ── Category Breakdown ──────────────────────────────────────────
89
132
  console.log(bold("Category Scores:"));
@@ -111,29 +154,66 @@ export function reportEslint(report) {
111
154
  console.log(dim(` ${summary.filesScanned} files scanned, ${summary.keysChecked} keys checked, ${summary.localesChecked} locales`));
112
155
  console.log(dim(` Completed in ${(report.durationMs / 1000).toFixed(2)}s`));
113
156
  console.log();
114
- // ── Diagnostic Listing (errors and warnings only) ───────────────
157
+ // ── Diagnostic Listing (grouped by rule, react-doctor style) ────
115
158
  const actionable = diagnostics.filter((d) => d.severity === "error" || d.severity === "warning");
116
159
  if (actionable.length > 0) {
117
- // Group by rule for readability
160
+ // Group by rule
118
161
  const byRule = new Map();
119
162
  for (const d of actionable) {
120
163
  const existing = byRule.get(d.rule) || [];
121
164
  existing.push(d);
122
165
  byRule.set(d.rule, existing);
123
166
  }
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));
167
+ // Sort: errors first, then by count descending
168
+ const sortedGroups = sortBySeverityAndCount([...byRule.entries()]);
169
+ const visibleGroups = sortedGroups.slice(0, MAX_RULE_GROUPS);
170
+ const hiddenGroupCount = sortedGroups.length - visibleGroups.length;
171
+ const maxItems = verbose ? MAX_ITEMS_PER_GROUP_VERBOSE : MAX_ITEMS_PER_GROUP;
172
+ for (const [rule, diags] of visibleGroups) {
173
+ const first = diags[0];
174
+ const icon = colorizeBySeverity(first.severity === "error" ? "✗" : "⚠", first.severity);
175
+ const count = diags.length;
176
+ const countLabel = count > 1
177
+ ? colorizeBySeverity(` (${count})`, first.severity)
178
+ : "";
179
+ // Rule message line
180
+ console.log(` ${icon} ${first.message}${countLabel}`);
181
+ // Help text (indented)
182
+ if (first.help) {
183
+ console.log(dim(` ${first.help}`));
184
+ }
185
+ // Key-based rules: show namespace/key entries
186
+ if (KEY_BASED_RULES.has(rule)) {
187
+ const keys = buildKeyEntries(diags);
188
+ const shown = keys.slice(0, maxItems);
189
+ const hiddenKeys = keys.length - shown.length;
190
+ for (const key of shown) {
191
+ console.log(dim(` ${key}`));
192
+ }
193
+ if (hiddenKeys > 0) {
194
+ console.log(dim(` ... and ${hiddenKeys} more`));
195
+ }
131
196
  }
132
- if (hidden > 0) {
133
- console.log(dim(` ... and ${hidden} more`));
197
+ else {
198
+ // File-based rules: show file:line entries
199
+ const fileLines = buildFileLineMap(diags);
200
+ const entries = [...fileLines.entries()];
201
+ const shown = entries.slice(0, maxItems);
202
+ const hiddenFiles = entries.length - shown.length;
203
+ for (const [filePath, lines] of shown) {
204
+ const lineLabel = lines.length > 0 ? `: ${lines.join(", ")}` : "";
205
+ console.log(dim(` ${filePath}${lineLabel}`));
206
+ }
207
+ if (hiddenFiles > 0) {
208
+ console.log(dim(` ... and ${hiddenFiles} more files`));
209
+ }
134
210
  }
135
211
  console.log();
136
212
  }
213
+ if (hiddenGroupCount > 0) {
214
+ console.log(dim(` ... and ${hiddenGroupCount} more rules`));
215
+ console.log();
216
+ }
137
217
  }
138
218
  }
139
219
  //# sourceMappingURL=doctor-eslint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor-eslint.js","sourceRoot":"","sources":["../../src/reporters/doctor-eslint.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor-eslint.js","sourceRoot":"","sources":["../../src/reporters/doctor-eslint.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,14 @@
2
2
  * Doctor Report — API Reporter
3
3
  *
4
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
5
  *
7
- * Graceful degradation: if OIDC is unavailable (running locally, missing
8
- * permissions), it warns and returns null instead of failing.
6
+ * Two auth paths:
7
+ * 1. API key (--api-key flag) for local dev, GitLab, Jenkins, etc.
8
+ * Uses Better Auth API key via x-api-key header.
9
+ * Reads project context from i18n.config.ts to build X-Doctor-Project header.
10
+ * 2. GitHub Actions OIDC (default) — no API keys needed in GitHub Actions.
11
+ *
12
+ * Graceful degradation: if auth is unavailable, it warns and returns null.
9
13
  */
10
14
  import type { DoctorReport } from "../doctor/index.js";
11
15
  interface ReportResult {
@@ -16,8 +20,9 @@ interface ReportResult {
16
20
  * POST a doctor report to the Better i18n API.
17
21
  *
18
22
  * @param report - The DoctorReport to upload
23
+ * @param apiKey - Optional Better Auth API key for non-OIDC auth (--api-key flag)
19
24
  * @returns Report ID and dashboard URL, or null if reporting failed/unavailable
20
25
  */
21
- export declare function reportToApi(report: DoctorReport): Promise<ReportResult | null>;
26
+ export declare function reportToApi(report: DoctorReport, apiKey?: string): Promise<ReportResult | null>;
22
27
  export {};
23
28
  //# sourceMappingURL=doctor-report.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"doctor-report.d.ts","sourceRoot":"","sources":["../../src/reporters/doctor-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAU9B"}