@better-i18n/cli 0.1.8 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +253 -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 +88 -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 +20 -0
- package/dist/reporters/doctor-eslint.d.ts.map +1 -0
- package/dist/reporters/doctor-eslint.js +175 -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,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON key utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for flattening, counting, and working with nested translation JSON files.
|
|
5
|
+
* Extracted from sync.ts for reuse in doctor, check, and sync commands.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Flatten nested JSON translation file into a namespace-grouped key map.
|
|
9
|
+
*
|
|
10
|
+
* Only first-level key becomes the namespace (Better i18n convention).
|
|
11
|
+
* Returns Record<namespace, fullKey[]>.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```
|
|
15
|
+
* flattenKeys({ common: { title: "Hello", actions: { save: "Save" } } })
|
|
16
|
+
* // => { common: ["common.title", "common.actions.save"] }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function flattenKeys(remoteKeys) {
|
|
20
|
+
const result = {};
|
|
21
|
+
function traverse(obj, prefix = "") {
|
|
22
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj))
|
|
23
|
+
return;
|
|
24
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
25
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
26
|
+
if (typeof value === "object" &&
|
|
27
|
+
value !== null &&
|
|
28
|
+
!Array.isArray(value)) {
|
|
29
|
+
traverse(value, fullKey);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Leaf (string, number, array, boolean, or null)
|
|
33
|
+
const namespace = fullKey.split(".")[0] || "default";
|
|
34
|
+
if (!result[namespace])
|
|
35
|
+
result[namespace] = [];
|
|
36
|
+
result[namespace].push(fullKey);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
traverse(remoteKeys);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Flatten nested JSON to a flat key→value map (all namespaces merged).
|
|
45
|
+
*
|
|
46
|
+
* Unlike flattenKeys() which groups by namespace, this returns a single
|
|
47
|
+
* flat map of dotted-path → leaf-value. Useful for health rules that
|
|
48
|
+
* need to compare source and target translation values.
|
|
49
|
+
*/
|
|
50
|
+
export function flattenToRecord(translations) {
|
|
51
|
+
const result = {};
|
|
52
|
+
function traverse(obj, prefix = "") {
|
|
53
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj))
|
|
54
|
+
return;
|
|
55
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
56
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
57
|
+
if (typeof value === "object" &&
|
|
58
|
+
value !== null &&
|
|
59
|
+
!Array.isArray(value)) {
|
|
60
|
+
traverse(value, fullKey);
|
|
61
|
+
}
|
|
62
|
+
else if (typeof value === "string") {
|
|
63
|
+
result[fullKey] = value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
traverse(translations);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Count total leaf keys in nested translation structure.
|
|
72
|
+
* Only counts string values (not numbers, arrays, booleans).
|
|
73
|
+
*/
|
|
74
|
+
export function countTotalKeys(remoteKeys) {
|
|
75
|
+
let count = 0;
|
|
76
|
+
function traverse(obj) {
|
|
77
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj))
|
|
78
|
+
return;
|
|
79
|
+
for (const value of Object.values(obj)) {
|
|
80
|
+
if (typeof value === "string") {
|
|
81
|
+
count++;
|
|
82
|
+
}
|
|
83
|
+
else if (typeof value === "object" && value !== null) {
|
|
84
|
+
traverse(value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
traverse(remoteKeys);
|
|
89
|
+
return count;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Count total keys from a namespace-grouped string[] map.
|
|
93
|
+
*/
|
|
94
|
+
export function countMissingKeys(keys) {
|
|
95
|
+
return Object.values(keys).reduce((sum, arr) => sum + arr.length, 0);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Count total keys from a namespace-grouped MissingKeyEntry[] map.
|
|
99
|
+
*/
|
|
100
|
+
export function countMissingKeysFromEntries(keys) {
|
|
101
|
+
return Object.values(keys).reduce((sum, arr) => sum + arr.length, 0);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=json-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-keys.js","sourceRoot":"","sources":["../../src/utils/json-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key comparison utilities
|
|
3
|
+
*
|
|
4
|
+
* Core logic for comparing local code keys with remote translation keys.
|
|
5
|
+
* Handles namespace binding resolution, container detection, fuzzy matching,
|
|
6
|
+
* and dynamic pattern matching. Extracted from sync.ts for reuse.
|
|
7
|
+
*/
|
|
8
|
+
import type { Issue } from "../analyzer/types.js";
|
|
9
|
+
import { type MissingKeyEntry, type RemoteTranslations } from "./json-keys.js";
|
|
10
|
+
/** Dynamic key pattern match information */
|
|
11
|
+
export interface DynamicPatternMatch {
|
|
12
|
+
pattern: string;
|
|
13
|
+
file: string;
|
|
14
|
+
line: number;
|
|
15
|
+
matchedKeys: string[];
|
|
16
|
+
}
|
|
17
|
+
/** Scan statistics from code analysis */
|
|
18
|
+
export interface ScanStats {
|
|
19
|
+
dynamicKeys: number;
|
|
20
|
+
dynamicNamespaces: number;
|
|
21
|
+
unboundTranslators: number;
|
|
22
|
+
rootScopedTranslators: number;
|
|
23
|
+
}
|
|
24
|
+
/** Full sync metrics from key comparison */
|
|
25
|
+
export interface SyncMetrics {
|
|
26
|
+
localTotal: number;
|
|
27
|
+
remoteTotal: number;
|
|
28
|
+
intersectionCount: number;
|
|
29
|
+
allLocal: Set<string>;
|
|
30
|
+
allRemoteLeaves: Set<string>;
|
|
31
|
+
missing: Record<string, MissingKeyEntry[]>;
|
|
32
|
+
unused: Record<string, string[]>;
|
|
33
|
+
dynamicReviewRequired: Record<string, string[]>;
|
|
34
|
+
dynamicPatternMatches: DynamicPatternMatch[];
|
|
35
|
+
classification: Record<string, number>;
|
|
36
|
+
filteredKeys: Array<{
|
|
37
|
+
key: string;
|
|
38
|
+
reason: string;
|
|
39
|
+
}>;
|
|
40
|
+
localCoverage: number;
|
|
41
|
+
remoteCoverage: number;
|
|
42
|
+
invariants: {
|
|
43
|
+
local: boolean;
|
|
44
|
+
remote: boolean;
|
|
45
|
+
};
|
|
46
|
+
scanStats?: ScanStats;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Unify all comparison logic to ensure consistent metrics.
|
|
50
|
+
*
|
|
51
|
+
* This is the core comparison engine that:
|
|
52
|
+
* 1. Flattens remote nested JSON to leaf keys
|
|
53
|
+
* 2. Builds container set (paths with children but no direct value)
|
|
54
|
+
* 3. Handles bound-scoped namespace bindings
|
|
55
|
+
* 4. Resolves unknown-scoped partial keys via fuzzy suffix matching
|
|
56
|
+
* 5. Handles container-access keys by expanding to all children
|
|
57
|
+
* 6. Matches dynamic patterns via matchDynamicPattern
|
|
58
|
+
*
|
|
59
|
+
* Returns comprehensive SyncMetrics with missing, unused, coverage percentages.
|
|
60
|
+
*/
|
|
61
|
+
export declare function getSummary(allIssues: Issue[], remoteKeys: RemoteTranslations, verbose?: boolean): SyncMetrics;
|
|
62
|
+
/**
|
|
63
|
+
* Group issues by namespace (first dot-segment).
|
|
64
|
+
* Single-segment keys go to "default" namespace.
|
|
65
|
+
*/
|
|
66
|
+
export declare function groupKeysByNamespace(issues: Issue[]): Record<string, string[]>;
|
|
67
|
+
//# sourceMappingURL=key-comparison.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-comparison.d.ts","sourceRoot":"","sources":["../../src/utils/key-comparison.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,kBAAkB,EAExB,MAAM,gBAAgB,CAAC;AAExB,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACjC,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChD,qBAAqB,EAAE,mBAAmB,EAAE,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,YAAY,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAChD,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,KAAK,EAAE,EAClB,UAAU,EAAE,kBAAkB,EAC9B,OAAO,CAAC,EAAE,OAAO,GAChB,WAAW,CA4Sb;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,KAAK,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAsB1B"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key comparison utilities
|
|
3
|
+
*
|
|
4
|
+
* Core logic for comparing local code keys with remote translation keys.
|
|
5
|
+
* Handles namespace binding resolution, container detection, fuzzy matching,
|
|
6
|
+
* and dynamic pattern matching. Extracted from sync.ts for reuse.
|
|
7
|
+
*/
|
|
8
|
+
import { matchDynamicPattern } from "../analyzer/dynamic-matcher.js";
|
|
9
|
+
import { countMissingKeys, countMissingKeysFromEntries, flattenKeys, } from "./json-keys.js";
|
|
10
|
+
/**
|
|
11
|
+
* Build a set of all dotted paths in a nested JSON object.
|
|
12
|
+
* Includes both leaf paths and container (branch) paths.
|
|
13
|
+
*/
|
|
14
|
+
function buildPathSet(obj, prefix = "", paths) {
|
|
15
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj))
|
|
16
|
+
return;
|
|
17
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
18
|
+
const fullPath = prefix ? `${prefix}.${key}` : key;
|
|
19
|
+
paths.add(fullPath);
|
|
20
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
21
|
+
buildPathSet(value, fullPath, paths);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Unify all comparison logic to ensure consistent metrics.
|
|
27
|
+
*
|
|
28
|
+
* This is the core comparison engine that:
|
|
29
|
+
* 1. Flattens remote nested JSON to leaf keys
|
|
30
|
+
* 2. Builds container set (paths with children but no direct value)
|
|
31
|
+
* 3. Handles bound-scoped namespace bindings
|
|
32
|
+
* 4. Resolves unknown-scoped partial keys via fuzzy suffix matching
|
|
33
|
+
* 5. Handles container-access keys by expanding to all children
|
|
34
|
+
* 6. Matches dynamic patterns via matchDynamicPattern
|
|
35
|
+
*
|
|
36
|
+
* Returns comprehensive SyncMetrics with missing, unused, coverage percentages.
|
|
37
|
+
*/
|
|
38
|
+
export function getSummary(allIssues, remoteKeys, verbose) {
|
|
39
|
+
const remoteFlattened = flattenKeys(remoteKeys);
|
|
40
|
+
// Use unique key sets for all calculations
|
|
41
|
+
const allLocal = new Set();
|
|
42
|
+
const classification = {
|
|
43
|
+
"bound-scoped": 0,
|
|
44
|
+
"root-scoped": 0,
|
|
45
|
+
"unknown-scoped": 0,
|
|
46
|
+
"unbound": 0,
|
|
47
|
+
};
|
|
48
|
+
// Build fast lookup for all remote keys (including paths)
|
|
49
|
+
const remoteKeyPaths = new Set();
|
|
50
|
+
buildPathSet(remoteKeys, "", remoteKeyPaths);
|
|
51
|
+
// Flatten all remote leaves for intersection
|
|
52
|
+
const allRemoteLeaves = new Set();
|
|
53
|
+
for (const keys of Object.values(remoteFlattened)) {
|
|
54
|
+
for (const k of keys)
|
|
55
|
+
allRemoteLeaves.add(k);
|
|
56
|
+
}
|
|
57
|
+
// Build a set of all remote containers (paths that exist but aren't leaves)
|
|
58
|
+
const remoteContainers = new Set();
|
|
59
|
+
for (const path of remoteKeyPaths) {
|
|
60
|
+
if (!allRemoteLeaves.has(path)) {
|
|
61
|
+
remoteContainers.add(path);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Handle namespace-scoped translators
|
|
65
|
+
// When code has: const t = useTranslations("teacher.courses.course_modules")
|
|
66
|
+
// ALL keys under that namespace are accessible, so mark them as used
|
|
67
|
+
const boundNamespaces = new Set();
|
|
68
|
+
for (const issue of allIssues) {
|
|
69
|
+
if (issue.bindingType === "bound-scoped" && issue.namespace) {
|
|
70
|
+
boundNamespaces.add(issue.namespace);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// For each bound namespace, mark all its children as used
|
|
74
|
+
for (const namespace of boundNamespaces) {
|
|
75
|
+
if (remoteContainers.has(namespace) || remoteKeyPaths.has(namespace)) {
|
|
76
|
+
const namespacePrefix = namespace + ".";
|
|
77
|
+
const childrenKeys = Array.from(allRemoteLeaves).filter((k) => k.startsWith(namespacePrefix));
|
|
78
|
+
if (verbose && childrenKeys.length > 0) {
|
|
79
|
+
console.log(`[VERBOSE] Namespace binding detected: "${namespace}" (${childrenKeys.length} children accessible)`);
|
|
80
|
+
console.log(`[VERBOSE] → Marking all children as used:`, childrenKeys.slice(0, 3).join(", "), childrenKeys.length > 3 ? "..." : "");
|
|
81
|
+
}
|
|
82
|
+
childrenKeys.forEach((child) => allLocal.add(child));
|
|
83
|
+
classification["bound-scoped"] =
|
|
84
|
+
(classification["bound-scoped"] || 0) + 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Filter local keys: strictly skip if they refer to a container object in remote
|
|
88
|
+
const rawLocalKeys = Array.from(new Set(allIssues.map((i) => i.key).filter(Boolean)));
|
|
89
|
+
const filteredKeys = [];
|
|
90
|
+
// Separate partial keys (unknown-scoped) for fuzzy matching
|
|
91
|
+
const partialKeys = [];
|
|
92
|
+
const fullyQualifiedKeys = [];
|
|
93
|
+
for (const issue of allIssues) {
|
|
94
|
+
if (!issue.key)
|
|
95
|
+
continue;
|
|
96
|
+
// Check if this local key is accessing a remote container
|
|
97
|
+
if (remoteContainers.has(issue.key)) {
|
|
98
|
+
const containerPrefix = issue.key + ".";
|
|
99
|
+
const childrenKeys = Array.from(allRemoteLeaves).filter((k) => k.startsWith(containerPrefix));
|
|
100
|
+
if (verbose) {
|
|
101
|
+
console.log(`[VERBOSE] Container access detected: "${issue.key}" at ${issue.file}:${issue.line}`);
|
|
102
|
+
console.log(`[VERBOSE] → Marking ${childrenKeys.length} children as used:`, childrenKeys.slice(0, 3).join(", "), childrenKeys.length > 3 ? "..." : "");
|
|
103
|
+
}
|
|
104
|
+
childrenKeys.forEach((child) => allLocal.add(child));
|
|
105
|
+
if (issue.bindingType) {
|
|
106
|
+
classification[issue.bindingType] =
|
|
107
|
+
(classification[issue.bindingType] || 0) + 1;
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Check if this key is a container in remote (has children but no leaf value)
|
|
112
|
+
const isRemoteContainer = remoteKeyPaths.has(issue.key) && !allRemoteLeaves.has(issue.key);
|
|
113
|
+
if (isRemoteContainer) {
|
|
114
|
+
const hasChildrenInLocal = rawLocalKeys.some((other) => other !== issue.key && other.startsWith(issue.key + "."));
|
|
115
|
+
if (hasChildrenInLocal) {
|
|
116
|
+
if (verbose) {
|
|
117
|
+
filteredKeys.push({
|
|
118
|
+
key: issue.key,
|
|
119
|
+
reason: "container with extracted children",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Check if this is a partial key (pattern-matched translator without namespace)
|
|
126
|
+
if (issue.bindingType === "unknown-scoped") {
|
|
127
|
+
partialKeys.push({ key: issue.key, issue });
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
fullyQualifiedKeys.push(issue);
|
|
131
|
+
allLocal.add(issue.key);
|
|
132
|
+
if (issue.bindingType) {
|
|
133
|
+
classification[issue.bindingType] =
|
|
134
|
+
(classification[issue.bindingType] || 0) + 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Fuzzy match partial keys against remote keys
|
|
139
|
+
for (const { key: partialKey, issue } of partialKeys) {
|
|
140
|
+
const matches = Array.from(allRemoteLeaves).filter((remoteKey) => {
|
|
141
|
+
if (remoteKey === partialKey)
|
|
142
|
+
return true;
|
|
143
|
+
if (remoteKey.endsWith(`.${partialKey}`))
|
|
144
|
+
return true;
|
|
145
|
+
if (!partialKey.includes(".") && remoteKey.endsWith(partialKey)) {
|
|
146
|
+
const beforePartial = remoteKey.slice(0, -partialKey.length);
|
|
147
|
+
if (beforePartial.endsWith("."))
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
});
|
|
152
|
+
if (matches.length === 1) {
|
|
153
|
+
allLocal.add(matches[0]);
|
|
154
|
+
if (verbose) {
|
|
155
|
+
console.log(`[VERBOSE] Fuzzy matched partial key: "${partialKey}" → "${matches[0]}"`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (matches.length > 1) {
|
|
159
|
+
if (verbose) {
|
|
160
|
+
console.log(`[VERBOSE] Ambiguous partial key: "${partialKey}" (${matches.length} matches: ${matches.slice(0, 3).join(", ")}${matches.length > 3 ? ", ..." : ""})`);
|
|
161
|
+
}
|
|
162
|
+
matches.forEach((m) => allLocal.add(m));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
allLocal.add(partialKey);
|
|
166
|
+
if (verbose) {
|
|
167
|
+
console.log(`[VERBOSE] No fuzzy match for partial key: "${partialKey}"`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (issue.bindingType) {
|
|
171
|
+
classification[issue.bindingType] =
|
|
172
|
+
(classification[issue.bindingType] || 0) + 1;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Calculate intersection once
|
|
176
|
+
const intersection = new Set();
|
|
177
|
+
for (const k of allLocal) {
|
|
178
|
+
if (allRemoteLeaves.has(k))
|
|
179
|
+
intersection.add(k);
|
|
180
|
+
}
|
|
181
|
+
// Missing: In Local Set but not in Remote Set
|
|
182
|
+
const missing = {};
|
|
183
|
+
for (const issue of allIssues) {
|
|
184
|
+
if (!issue.key || !allLocal.has(issue.key))
|
|
185
|
+
continue;
|
|
186
|
+
if (!allRemoteLeaves.has(issue.key)) {
|
|
187
|
+
const ns = issue.key.split(".")[0] || "default";
|
|
188
|
+
if (!missing[ns])
|
|
189
|
+
missing[ns] = [];
|
|
190
|
+
if (!missing[ns].some((m) => m.key === issue.key)) {
|
|
191
|
+
missing[ns].push({
|
|
192
|
+
key: issue.key,
|
|
193
|
+
value: issue.text || "",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Extract dynamic patterns from issues
|
|
199
|
+
const dynamicPatterns = allIssues
|
|
200
|
+
.filter((i) => i.isDynamic && i.pattern)
|
|
201
|
+
.map((i) => ({ pattern: i.pattern, file: i.file, line: i.line }));
|
|
202
|
+
if (verbose && dynamicPatterns.length > 0) {
|
|
203
|
+
console.log(`[VERBOSE] Found ${dynamicPatterns.length} dynamic patterns`);
|
|
204
|
+
}
|
|
205
|
+
// Match dynamic patterns against remote keys
|
|
206
|
+
const keysMatchedByDynamicPatterns = new Set();
|
|
207
|
+
const dynamicPatternMatches = [];
|
|
208
|
+
for (const { pattern, file, line } of dynamicPatterns) {
|
|
209
|
+
const matches = matchDynamicPattern(pattern, Array.from(allRemoteLeaves));
|
|
210
|
+
if (matches.length > 0) {
|
|
211
|
+
dynamicPatternMatches.push({ pattern, file, line, matchedKeys: matches });
|
|
212
|
+
matches.forEach((k) => {
|
|
213
|
+
keysMatchedByDynamicPatterns.add(k);
|
|
214
|
+
allLocal.add(k);
|
|
215
|
+
});
|
|
216
|
+
if (verbose) {
|
|
217
|
+
console.log(`[VERBOSE] Pattern "${pattern}" matched ${matches.length} keys`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Recalculate intersection after adding dynamic matches
|
|
222
|
+
intersection.clear();
|
|
223
|
+
for (const k of allLocal) {
|
|
224
|
+
if (allRemoteLeaves.has(k))
|
|
225
|
+
intersection.add(k);
|
|
226
|
+
}
|
|
227
|
+
// Unused: In Remote Set but not in Local Set
|
|
228
|
+
const staticUnused = {};
|
|
229
|
+
const dynamicReviewRequired = {};
|
|
230
|
+
for (const k of allRemoteLeaves) {
|
|
231
|
+
if (!allLocal.has(k)) {
|
|
232
|
+
const ns = k.split(".")[0] || "default";
|
|
233
|
+
if (keysMatchedByDynamicPatterns.has(k)) {
|
|
234
|
+
if (!dynamicReviewRequired[ns])
|
|
235
|
+
dynamicReviewRequired[ns] = [];
|
|
236
|
+
dynamicReviewRequired[ns].push(k);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
if (!staticUnused[ns])
|
|
240
|
+
staticUnused[ns] = [];
|
|
241
|
+
staticUnused[ns].push(k);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const localTotal = allLocal.size;
|
|
246
|
+
const remoteTotal = allRemoteLeaves.size;
|
|
247
|
+
const intersectionCount = intersection.size;
|
|
248
|
+
return {
|
|
249
|
+
localTotal,
|
|
250
|
+
remoteTotal,
|
|
251
|
+
intersectionCount,
|
|
252
|
+
allLocal,
|
|
253
|
+
allRemoteLeaves,
|
|
254
|
+
missing,
|
|
255
|
+
unused: staticUnused,
|
|
256
|
+
dynamicReviewRequired,
|
|
257
|
+
dynamicPatternMatches,
|
|
258
|
+
classification,
|
|
259
|
+
filteredKeys,
|
|
260
|
+
localCoverage: localTotal > 0
|
|
261
|
+
? Math.round((intersectionCount / localTotal) * 100)
|
|
262
|
+
: 100,
|
|
263
|
+
remoteCoverage: remoteTotal > 0
|
|
264
|
+
? Math.round((intersectionCount / remoteTotal) * 100)
|
|
265
|
+
: 100,
|
|
266
|
+
invariants: {
|
|
267
|
+
local: localTotal ===
|
|
268
|
+
intersectionCount + countMissingKeysFromEntries(missing),
|
|
269
|
+
remote: remoteTotal ===
|
|
270
|
+
intersectionCount +
|
|
271
|
+
countMissingKeys(staticUnused) +
|
|
272
|
+
countMissingKeys(dynamicReviewRequired),
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Group issues by namespace (first dot-segment).
|
|
278
|
+
* Single-segment keys go to "default" namespace.
|
|
279
|
+
*/
|
|
280
|
+
export function groupKeysByNamespace(issues) {
|
|
281
|
+
const result = {};
|
|
282
|
+
for (const issue of issues) {
|
|
283
|
+
if (!issue.key)
|
|
284
|
+
continue;
|
|
285
|
+
const parts = issue.key.split(".");
|
|
286
|
+
const namespace = parts.length > 1 ? parts[0] : "default";
|
|
287
|
+
const fullKey = issue.key;
|
|
288
|
+
if (!result[namespace]) {
|
|
289
|
+
result[namespace] = new Set();
|
|
290
|
+
}
|
|
291
|
+
result[namespace].add(fullKey);
|
|
292
|
+
}
|
|
293
|
+
const output = {};
|
|
294
|
+
for (const [namespace, keys] of Object.entries(result)) {
|
|
295
|
+
output[namespace] = Array.from(keys).sort();
|
|
296
|
+
}
|
|
297
|
+
return output;
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=key-comparison.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-comparison.js","sourceRoot":"","sources":["../../src/utils/key-comparison.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-i18n/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "CLI tool for detecting hardcoded strings in React/Next.js apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"prepublishOnly": "npm run clean && npm run build"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@inquirer/prompts": "^7.2.0",
|
|
47
48
|
"commander": "^12.1.0",
|
|
48
49
|
"glob": "^11.0.0",
|
|
49
50
|
"ora": "^8.1.1",
|