i18n-sharpen 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/README.md +270 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1599 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +191 -0
- package/dist/index.js +1513 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/schema.ts","../src/core/errors.ts","../src/config/loader.ts","../src/core/scanner/regex.ts","../src/core/scanner/text.ts","../src/core/scanner/files.ts","../src/core/scanner/index.ts","../src/utils.ts","../src/core/locale-io/transform.ts","../src/core/locale-io/io.ts","../src/commands/validate/checks.ts","../src/commands/validate/output.ts","../src/commands/validate/report.ts","../src/commands/validate.ts","../src/commands/extract.ts","../src/commands/prune/plans.ts","../src/commands/prune.ts"],"names":["path","fs2","path2","fs3","pc","path3","fs4","path5","fs5","getBaseKey","path6","fs6","path7","fs7","path8","path9","fs8"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from \"zod\"\nimport type { I18nSharpenConfig } from \"@/types\"\n\n/**\n * Single source of truth for every default value used by the CLI.\n *\n * This object intentionally consolidates what would otherwise be scattered\n * magic strings. When adding a new tunable, add it here and reference\n * `DEFAULT_CONFIG.<field>` from other modules.\n */\nexport const DEFAULT_CONFIG = {\n scanDirs: [\"src\"],\n localesDir: \"src/locales\",\n excludeDirs: [\n \"node_modules\",\n \"dist\",\n \".git\",\n \".next\",\n \"build\",\n \"coverage\",\n \".agent\",\n \".claude\"\n ],\n fileExtensions: [\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \".svelte\", \".astro\"],\n matchFunctions: [\"t\", \"getTranslation\"],\n outputReport: \"i18n-coverage.md\",\n defaultLanguage: \"en\",\n supportedLanguages: [\"en\"],\n matchAttributes: [\"i18nKey\", \"id\", \"i18n\", \":label\", \"v-t\", \"t:\"],\n ignoreKeys: [],\n pluralSuffixes: [\n \"_zero\",\n \"_one\",\n \"_two\",\n \"_few\",\n \"_many\",\n \"_other\",\n \"_male\",\n \"_female\"\n ],\n localesLayout: \"flat\"\n} satisfies Partial<I18nSharpenConfig>\n\n// Restrict matchFunctions / matchAttributes to plain identifier-like tokens\n// so they are safe to splice into a generated regex.\nconst identifierLikePattern = /^[A-Za-z_$][A-Za-z0-9_$.]*$/\nexport const identifierLike = z\n .string()\n .regex(\n identifierLikePattern,\n \"must be an identifier-like token matching /^[A-Za-z_$][A-Za-z0-9_$.]*$/\"\n )\n\n// Attribute names are looser — can start with ':' (Vue v-bind), end with ':'\n// (Astro directives), and contain '-' (HTML data attrs).\nconst attributeNamePattern = /^[:]?[A-Za-z_$][A-Za-z0-9_$.\\-:]*$/\nexport const attributeName = z\n .string()\n .regex(\n attributeNamePattern,\n \"must match /^[:]?[A-Za-z_$][A-Za-z0-9_$.\\\\-:]*$/ (HTML/Vue/Astro-style attribute)\"\n )\n\n// Language codes must be filesystem-safe identifier-like strings.\nconst languageCodePattern = /^[a-zA-Z0-9_-]+$/\nexport const languageCode = z\n .string()\n .regex(\n languageCodePattern,\n \"must match /^[a-zA-Z0-9_-]+$/ (no path separators)\"\n )\n\nexport const I18nSharpenConfigSchema = z.object({\n scanDirs: z\n .array(z.string())\n .nonempty(\"scanDirs must contain at least one directory path\"),\n localesDir: z.string().nonempty(\"localesDir must be a non-empty string\"),\n defaultLanguage: languageCode,\n supportedLanguages: z\n .array(languageCode)\n .nonempty(\"supportedLanguages must contain at least one language\"),\n excludeDirs: z.array(z.string()).optional(),\n fileExtensions: z.array(z.string()).optional(),\n matchFunctions: z.array(identifierLike).optional(),\n outputReport: z.string().optional(),\n matchAttributes: z.array(attributeName).optional(),\n ignoreKeys: z.array(z.string()).optional(),\n pluralSuffixes: z.array(z.string()).optional(),\n looseKeyMatch: z.boolean().optional(),\n localesLayout: z.enum([\"flat\", \"namespaced\"]).optional(),\n prune: z\n .object({\n force: z.boolean().optional()\n })\n .optional()\n})\n","/**\n * Structured error type for i18n-sharpen.\n *\n * The library only ever throws `I18nSharpenError`. The `error` discriminated\n * union carries the machine-readable kind + context so the CLI (and\n * programmatic callers) can route the failure correctly without parsing\n * message strings.\n */\nexport type I18nError =\n | { kind: \"config\"; message: string; path?: string }\n | { kind: \"filesystem\"; message: string; path: string; cause?: unknown }\n | { kind: \"parse\"; message: string; path: string; line?: number }\n | { kind: \"validation\"; message: string; details?: unknown }\n\n/**\n * Single error class thrown by i18n-sharpen. `error` is a discriminated\n * union (see {@link I18nError}); use `err.error.kind` to switch on it.\n *\n * Only `src/cli.ts` should catch this and translate it into an exit\n * code — everywhere else, let it propagate.\n */\nexport class I18nSharpenError extends Error {\n constructor(\n public readonly error: I18nError,\n message?: string\n ) {\n super(message ?? error.message)\n this.name = \"I18nSharpenError\"\n }\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport { I18nSharpenError } from \"@/core/errors\"\nimport type { I18nSharpenConfig } from \"@/types\"\nimport { DEFAULT_CONFIG, I18nSharpenConfigSchema } from \"./schema\"\n\n/**\n * Load i18n-sharpen configuration.\n *\n * Resolution order:\n * 1. If `configPath` is provided, load that file (JSON). Errors are\n * fatal — the user explicitly asked for this file.\n * 2. Otherwise, look for `i18n-sharpen.json` in `cwd`.\n * 3. Otherwise, look for an `i18nSharpen` field in `cwd/package.json`.\n * 4. Otherwise, use defaults only.\n *\n * `configPath` may be absolute or relative; relative paths are resolved\n * against `cwd`.\n */\nexport function loadConfig(\n cwd: string = process.cwd(),\n configPath?: string\n): I18nSharpenConfig {\n if (!fs.existsSync(cwd)) {\n throw new I18nSharpenError({\n kind: \"config\",\n message: `cwd does not exist: ${cwd}`,\n path: cwd\n })\n }\n if (!fs.statSync(cwd).isDirectory()) {\n throw new I18nSharpenError({\n kind: \"config\",\n message: `cwd is not a directory: ${cwd}`,\n path: cwd\n })\n }\n\n const configPathJson = path.join(cwd, \"i18n-sharpen.json\")\n const packageJsonPath = path.join(cwd, \"package.json\")\n\n let fileConfig: Partial<I18nSharpenConfig> = {}\n\n if (configPath) {\n const resolved = path.isAbsolute(configPath)\n ? configPath\n : path.resolve(cwd, configPath)\n if (!fs.existsSync(resolved)) {\n throw new I18nSharpenError({\n kind: \"config\",\n message: `Config file not found: ${resolved}`,\n path: resolved\n })\n }\n if (!fs.statSync(resolved).isFile()) {\n throw new I18nSharpenError({\n kind: \"config\",\n message: `Config path is not a file: ${resolved}`,\n path: resolved\n })\n }\n try {\n const content = fs.readFileSync(resolved, \"utf8\")\n fileConfig = JSON.parse(content) as Partial<I18nSharpenConfig>\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"parse\",\n message: `Failed to parse config file '${resolved}': ${(error as Error).message}`,\n path: resolved\n })\n }\n } else if (fs.existsSync(configPathJson)) {\n try {\n const content = fs.readFileSync(configPathJson, \"utf8\")\n fileConfig = JSON.parse(content) as Partial<I18nSharpenConfig>\n } catch (error) {\n console.warn(\n `⚠️ Failed to parse i18n-sharpen.json: ${(error as Error).message}`\n )\n }\n } else if (fs.existsSync(packageJsonPath)) {\n try {\n const content = fs.readFileSync(packageJsonPath, \"utf8\")\n const pkg = JSON.parse(content) as {\n i18nSharpen?: Partial<I18nSharpenConfig>\n }\n if (pkg.i18nSharpen) {\n fileConfig = pkg.i18nSharpen\n }\n } catch (error) {\n console.warn(\n `⚠️ Failed to read package.json for i18nSharpen config: ${(error as Error).message}`\n )\n }\n }\n\n // Merge with defaults\n const rawConfig = {\n scanDirs: fileConfig.scanDirs ?? DEFAULT_CONFIG.scanDirs,\n localesDir: fileConfig.localesDir ?? DEFAULT_CONFIG.localesDir,\n defaultLanguage:\n fileConfig.defaultLanguage ?? DEFAULT_CONFIG.defaultLanguage,\n supportedLanguages:\n fileConfig.supportedLanguages ?? DEFAULT_CONFIG.supportedLanguages,\n excludeDirs: fileConfig.excludeDirs ?? DEFAULT_CONFIG.excludeDirs,\n fileExtensions: fileConfig.fileExtensions ?? DEFAULT_CONFIG.fileExtensions,\n matchFunctions: fileConfig.matchFunctions ?? DEFAULT_CONFIG.matchFunctions,\n outputReport: fileConfig.outputReport ?? DEFAULT_CONFIG.outputReport,\n matchAttributes:\n fileConfig.matchAttributes ?? DEFAULT_CONFIG.matchAttributes,\n ignoreKeys: fileConfig.ignoreKeys ?? DEFAULT_CONFIG.ignoreKeys,\n pluralSuffixes: fileConfig.pluralSuffixes ?? DEFAULT_CONFIG.pluralSuffixes,\n looseKeyMatch: fileConfig.looseKeyMatch ?? false,\n localesLayout: fileConfig.localesLayout ?? DEFAULT_CONFIG.localesLayout,\n prune: fileConfig.prune ?? { force: false }\n }\n\n // Zod validation\n const result = I18nSharpenConfigSchema.safeParse(rawConfig)\n if (!result.success) {\n const errors = result.error.issues\n .map((err) => ` - ${err.path.join(\".\")}: ${err.message}`)\n .join(\"\\n\")\n throw new I18nSharpenError({\n kind: \"config\",\n message: `Invalid configuration:\\n${errors}`\n })\n }\n\n const config = result.data\n\n // Warn when localesDir / scanDirs / outputReport resolve outside cwd.\n const cwdResolved = path.resolve(cwd)\n const isInsideCwd = (p: string): boolean => {\n const rel = path.relative(cwdResolved, path.resolve(cwdResolved, p))\n return !rel.startsWith(\"..\") && !path.isAbsolute(rel)\n }\n if (!isInsideCwd(config.localesDir)) {\n console.warn(\n `⚠️ localesDir '${config.localesDir}' resolves outside cwd ('${cwdResolved}').`\n )\n }\n for (const dir of config.scanDirs) {\n if (!isInsideCwd(dir)) {\n console.warn(\n `⚠️ scanDirs entry '${dir}' resolves outside cwd ('${cwdResolved}').`\n )\n }\n }\n if (config.outputReport && !isInsideCwd(config.outputReport)) {\n console.warn(\n `⚠️ outputReport '${config.outputReport}' resolves outside cwd ('${cwdResolved}').`\n )\n }\n\n if (!config.supportedLanguages.includes(config.defaultLanguage)) {\n config.supportedLanguages = Array.from(\n new Set([config.defaultLanguage, ...config.supportedLanguages])\n )\n }\n\n return config\n}\n","/**\n * Escape a string so it can be safely embedded in a regular expression.\n * Used to defend against regex-injection / ReDoS via user-controlled\n * matchFunctions / matchAttributes config entries.\n */\nexport function escapeRegex(input: string): string {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/**\n * Build the regex that matches `<fn>(\"key\")` / `<fn>('key')` /\n * `` <fn>(`key`) `` calls. `matchFunctions` entries are regex-escaped\n * before being spliced in as an alternation group.\n */\nexport function buildKeyRegex(matchFunctions: string[]): RegExp {\n const functionsJoined = matchFunctions.map(escapeRegex).join(\"|\")\n return new RegExp(\n \"\\\\b(?:\" + functionsJoined + \")\\\\s*\\\\(\\\\s*(['\\\"`])([a-zA-Z0-9_\\\\-.:]+)\\\\1\",\n \"g\"\n )\n}\n\n/**\n * Build the regex that matches `attr=\"key\"` / `attr='key'` /\n * `` attr=`key` `` JSX/HTML attributes. `matchAttributes` entries are\n * regex-escaped before being spliced in.\n *\n * Phase 8: framework attribute names can start with ':' (Vue v-bind)\n * or end with ':' (Astro directives), so we can't rely on \\b at the\n * start of the alternation. Use a non-attribute-name lookbehind /\n * start-of-string anchor instead so partial matches like `mi18n` for\n * `i18n` are still rejected.\n */\nexport function buildAttrRegex(matchAttributes: string[]): RegExp {\n const attrsJoined = matchAttributes.map(escapeRegex).join(\"|\")\n return new RegExp(\n \"(?:^|[\\\\s/{(>])(?:\" +\n attrsJoined +\n \")\\\\s*=\\\\s*(['\\\"`])([a-zA-Z0-9_\\\\-.:]+)\\\\1\",\n \"g\"\n )\n}\n\n/**\n * Build the regex used by validate to capture the first argument of\n * every `<fn>(...)` call regardless of whether it starts with a quote.\n * The caller post-classifies via `isStaticStringLiteral` to flag\n * dynamic references.\n */\nexport function buildDynamicCallRegex(matchFunctions: string[]): RegExp {\n const functionsJoined = matchFunctions.map(escapeRegex).join(\"|\")\n return new RegExp(\"\\\\b(?:\" + functionsJoined + \")\\\\s*\\\\(\\\\s*([^)]*)\\\\)\", \"g\")\n}\n","/**\n * Remove single-line and multi-line comments from JS/TS code without\n * corrupting string contents.\n *\n * State machine that tracks string contexts ('...', \"...\", `...` including\n * ${} interpolation depth) so that:\n * - `//` inside a string is preserved\n * - `*` `/` inside a string does not terminate a block comment\n * - URLs like \"https://x\" survive intact\n * - escapes (`\\\"`, `\\\\`, etc.) inside strings are respected\n *\n * Comments are replaced with a single space so token boundaries are preserved.\n */\nexport function stripComments(code: string): string {\n interface StackFrame {\n kind: \"single\" | \"double\" | \"template\"\n templateDepth: number\n }\n const out: string[] = []\n const stack: StackFrame[] = []\n let i = 0\n const n = code.length\n\n while (i < n) {\n const ch = code[i]\n const next = i + 1 < n ? code[i + 1] : \"\"\n const top = stack.length > 0 ? stack[stack.length - 1] : null\n\n if (top) {\n if (top.kind === \"template\" && ch === \"$\" && next === \"{\") {\n top.templateDepth++\n out.push(\"${\")\n i += 2\n continue\n }\n if (top.kind === \"template\" && top.templateDepth > 0 && ch === \"}\") {\n top.templateDepth--\n out.push(\"}\")\n i++\n continue\n }\n if (top.kind === \"template\" && top.templateDepth > 0) {\n // Fall through to non-string handling below\n } else {\n if (ch === \"\\\\\" && i + 1 < n) {\n out.push(ch, code[i + 1])\n i += 2\n continue\n }\n if (\n (top.kind === \"single\" && ch === \"'\") ||\n (top.kind === \"double\" && ch === '\"') ||\n (top.kind === \"template\" && ch === \"`\")\n ) {\n stack.pop()\n out.push(ch)\n i++\n continue\n }\n out.push(ch)\n i++\n continue\n }\n }\n\n if (ch === \"/\" && next === \"*\") {\n i += 2\n while (i < n && !(code[i] === \"*\" && i + 1 < n && code[i + 1] === \"/\")) {\n i++\n }\n i += 2\n out.push(\" \")\n continue\n }\n if (ch === \"/\" && next === \"/\") {\n i += 2\n while (i < n && code[i] !== \"\\n\") {\n i++\n }\n out.push(\" \")\n continue\n }\n if (ch === \"'\") {\n stack.push({ kind: \"single\", templateDepth: 0 })\n out.push(ch)\n i++\n continue\n }\n if (ch === '\"') {\n stack.push({ kind: \"double\", templateDepth: 0 })\n out.push(ch)\n i++\n continue\n }\n if (ch === \"`\") {\n stack.push({ kind: \"template\", templateDepth: 0 })\n out.push(ch)\n i++\n continue\n }\n\n out.push(ch)\n i++\n }\n\n return out.join(\"\")\n}\n\n/**\n * Return true if `arg` is a single static string literal — i.e. a quoted\n * literal that consumes the whole argument with no concatenation, no\n * template interpolation, and no trailing tokens.\n */\nexport function isStaticStringLiteral(arg: string): boolean {\n const trimmed = arg.trim()\n if (trimmed.length < 2) return false\n const quote = trimmed[0]\n if (quote !== \"'\" && quote !== '\"' && quote !== \"`\") return false\n let i = 1\n while (i < trimmed.length) {\n const ch = trimmed[i]\n if (ch === \"\\\\\" && i + 1 < trimmed.length) {\n i += 2\n continue\n }\n if (quote === \"`\" && ch === \"$\" && trimmed[i + 1] === \"{\") {\n return false\n }\n if (ch === quote) {\n return i === trimmed.length - 1\n }\n i++\n }\n return false\n}\n\n/**\n * Strip the first matching plural / context suffix off `key`. Returns\n * `key` unchanged when no suffix matches.\n */\nexport function getBaseKey(key: string, suffixes: string[]): string {\n for (const suffix of suffixes) {\n if (key.endsWith(suffix)) {\n return key.slice(0, -suffix.length)\n }\n }\n return key\n}\n\n/**\n * Test if a string matches a wildcard pattern (e.g. \"status.*\" matches\n * \"status.success\"). `?` is treated as a literal character, not a regex\n * quantifier.\n */\nexport function matchWildcard(pattern: string, key: string): boolean {\n if (pattern === \"*\") return true\n const escaped = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n const regex = new RegExp(`^${escaped}$`)\n return regex.test(key)\n}\n\n/**\n * Test whether `key` should be considered used given the set of keys\n * found in source, the user's ignoreKeys wildcards, and the configured\n * plural suffixes.\n */\nexport function isKeyUsed(\n key: string,\n usedKeys: Set<string>,\n ignoreKeys: string[] | undefined,\n pluralSuffixes: string[]\n): boolean {\n if (usedKeys.has(key)) return true\n\n if (ignoreKeys) {\n for (const pattern of ignoreKeys) {\n if (matchWildcard(pattern, key)) {\n return true\n }\n }\n }\n\n const baseKey = getBaseKey(key, pluralSuffixes)\n if (baseKey !== key && usedKeys.has(baseKey)) {\n return true\n }\n\n return false\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport type { I18nSharpenConfig } from \"@/types\"\n\n/**\n * Recursively find all source files in a directory matching specific\n * extensions, ignoring specified directories.\n *\n * Uses readdirSync({ withFileTypes: true }) so each entry's type is known\n * without an extra statSync call. Symlinks are skipped to avoid infinite\n * recursion on symlink cycles or junction points.\n *\n * `excludeDirs` matches against the bare directory name (entry.name),\n * not the full path and not as a glob.\n */\nexport function getFiles(\n dir: string,\n extensions: string[],\n excludeDirs: string[]\n): string[] {\n const results: string[] = []\n if (!fs.existsSync(dir)) return results\n\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return results\n }\n for (const entry of entries) {\n if (entry.isSymbolicLink()) continue\n\n const filePath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n if (!excludeDirs.includes(entry.name)) {\n results.push(...getFiles(filePath, extensions, excludeDirs))\n }\n } else if (entry.isFile()) {\n if (extensions.includes(path.extname(entry.name))) {\n results.push(filePath)\n }\n }\n }\n return results\n}\n\n/**\n * Walk every configured `scanDirs` entry and collect absolute paths of\n * files whose extension matches `config.fileExtensions`. Missing entries\n * are silently skipped; the caller decides whether to warn.\n */\nexport function scanSourceFiles(\n config: I18nSharpenConfig,\n cwd: string\n): string[] {\n const filesToScan: string[] = []\n for (const scanDir of config.scanDirs) {\n const scanDirAbs = path.resolve(cwd, scanDir)\n if (fs.existsSync(scanDirAbs)) {\n filesToScan.push(\n ...getFiles(\n scanDirAbs,\n config.fileExtensions ?? [],\n config.excludeDirs ?? []\n )\n )\n }\n }\n return filesToScan\n}\n","import * as fs from \"fs\"\nimport { buildKeyRegex, buildAttrRegex } from \"./regex\"\nimport { stripComments } from \"./text\"\n\nexport * from \"./files\"\nexport * from \"./regex\"\nexport * from \"./text\"\n\n/**\n * Read every file in `files`, strip comments, then run the function/attr\n * regex over each cleaned source. Returns:\n * - `usedKeys`: the set of statically-resolvable translation keys\n * - `fileContents`: the cleaned source per file (parallel to `files`),\n * useful for the optional looseKeyMatch second pass\n *\n * Keys that end in `.` are skipped — they indicate dynamic prefixes\n * (e.g. `t('status.' + code)` -> `t('status.'`) and would otherwise\n * pollute the used-key set.\n */\nexport function detectUsedKeys(\n files: string[],\n matchFunctions: string[],\n matchAttributes: string[]\n): { usedKeys: Set<string>; fileContents: string[] } {\n const keyRegex = buildKeyRegex(matchFunctions)\n const attrRegex = buildAttrRegex(matchAttributes)\n\n const fileContents = files.map((file) => {\n try {\n const content = fs.readFileSync(file, \"utf8\")\n return stripComments(content)\n } catch {\n return \"\"\n }\n })\n\n const usedKeys = new Set<string>()\n for (const cleanContent of fileContents) {\n for (const match of cleanContent.matchAll(keyRegex)) {\n const key = match[2]\n if (key.endsWith(\".\")) continue\n usedKeys.add(key)\n }\n for (const match of cleanContent.matchAll(attrRegex)) {\n const key = match[2]\n if (key.endsWith(\".\")) continue\n usedKeys.add(key)\n }\n }\n\n return { usedKeys, fileContents }\n}\n","import pc from \"picocolors\"\n\n// Re-export scanner primitives from core/scanner for back-compat. New\n// code should import from `./core/scanner` directly.\nexport {\n /** @deprecated Import from `./core/scanner` instead. */\n getFiles,\n /** @deprecated Import from `./core/scanner` instead. */\n stripComments,\n /** @deprecated Import from `./core/scanner` instead. */\n isStaticStringLiteral,\n /** @deprecated Import from `./core/scanner` instead. */\n getBaseKey,\n /** @deprecated Import from `./core/scanner` instead. */\n isKeyUsed,\n /** @deprecated Import from `./core/scanner` instead. */\n matchWildcard,\n /** @deprecated Import from `./core/scanner` instead. */\n escapeRegex\n} from \"./core/scanner\"\n\n// Re-export locale-io primitives from core/locale-io for back-compat.\n// New code should import from `./core/locale-io` directly.\nexport {\n /** @deprecated Import from `./core/locale-io` instead. */\n flattenObject,\n /** @deprecated Import from `./core/locale-io` instead. */\n unflattenObject,\n /** @deprecated Import from `./core/locale-io` instead. */\n setNestedValue,\n /** @deprecated Import from `./core/locale-io` instead. */\n getNestedValue,\n /** @deprecated Import from `./core/locale-io` instead. */\n findLocaleFile,\n /** @deprecated Import from `./core/locale-io` instead. */\n readLocaleFile,\n /** @deprecated Import from `./core/locale-io` instead. */\n writeLocaleFile,\n /** @deprecated Import from `./core/locale-io` instead. */\n normalizeDisplayPath\n} from \"./core/locale-io\"\n\n/**\n * Logging helper utilities.\n *\n * Emoji can render as `?` on Windows cmd.exe and on some CI log viewers.\n * Set the `NO_EMOJI` environment variable (any truthy value) to fall back\n * to plain-text glyphs.\n */\nconst emojiDisabled =\n typeof process !== \"undefined\" &&\n !!process.env.NO_EMOJI &&\n process.env.NO_EMOJI !== \"0\" &&\n process.env.NO_EMOJI.toLowerCase() !== \"false\"\n\nconst glyphs = {\n ok: emojiDisabled ? \"[OK]\" : \"✅\",\n warn: emojiDisabled ? \"[WARN]\" : \"⚠️ \",\n err: emojiDisabled ? \"[ERR]\" : \"❌\"\n}\n\nexport const log = {\n header(title: string): void {\n console.log(`\\n${pc.bold(pc.cyan(`=== ${title} ===`))}`)\n },\n info(msg: string): void {\n console.log(msg)\n },\n success(msg: string): void {\n console.log(`${pc.green(glyphs.ok)} ${msg}`)\n },\n warn(msg: string): void {\n console.log(`${pc.yellow(`${glyphs.warn} Warning:`)} ${msg}`)\n },\n error(msg: string): void {\n console.error(`${pc.red(`${glyphs.err} Error:`)} ${msg}`)\n }\n}\n","import * as path from \"path\"\nimport { log } from \"@/utils\"\n\n/**\n * Forbidden path segments that could lead to prototype pollution\n * when used as keys in `setNestedValue` / `flattenObject`. Exported so\n * other modules can reuse the same guard list.\n */\nexport const FORBIDDEN_KEY_SEGMENTS = new Set([\n \"__proto__\",\n \"prototype\",\n \"constructor\"\n])\n\n/**\n * Flatten a nested JSON/YAML object into a flat key-value map using\n * dot notation.\n *\n * `.` is the path separator AND a permitted character in a key. A locale\n * containing both `{ \"user.name\": \"X\", \"user\": { \"name\": \"Y\" } }` produces\n * the same flat key `user.name`; whichever iteration order wins overwrites\n * the other. A warning is emitted when this happens.\n */\nexport function flattenObject(\n obj: Record<string, unknown>,\n prefix = \"\"\n): Record<string, string> {\n const map: Record<string, string> = {}\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n if (FORBIDDEN_KEY_SEGMENTS.has(key)) continue\n const value = obj[key]\n const newKey = prefix ? `${prefix}.${key}` : key\n if (Object.prototype.hasOwnProperty.call(map, newKey)) {\n log.warn(\n `Key collision in locale: '${newKey}' is produced both as a flat key and as a nested path. The later definition wins.`\n )\n }\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value)\n ) {\n Object.assign(\n map,\n flattenObject(value as Record<string, unknown>, newKey)\n )\n } else {\n map[newKey] = String(value)\n }\n }\n }\n return map\n}\n\n/**\n * Set a value in a nested object based on a dot-separated key path.\n *\n * Rejects path segments equal to `__proto__`, `prototype`, or\n * `constructor` to prevent prototype-pollution via untrusted key strings.\n */\nexport function setNestedValue(\n obj: Record<string, unknown>,\n keyPath: string,\n value: unknown\n): void {\n const parts = keyPath.split(\".\")\n for (const part of parts) {\n if (FORBIDDEN_KEY_SEGMENTS.has(part)) {\n return\n }\n }\n let current: Record<string, unknown> = obj\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]\n if (i === parts.length - 1) {\n current[part] = value\n } else {\n if (\n current[part] === undefined ||\n typeof current[part] !== \"object\" ||\n current[part] === null\n ) {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n }\n}\n\n/**\n * Get a value from a nested object based on a dot-separated key path.\n */\nexport function getNestedValue(\n obj: Record<string, unknown>,\n keyPath: string\n): unknown {\n const parts = keyPath.split(\".\")\n let current: unknown = obj\n for (const part of parts) {\n if (\n current === undefined ||\n current === null ||\n typeof current !== \"object\"\n ) {\n return undefined\n }\n current = (current as Record<string, unknown>)[part]\n }\n return current\n}\n\n/**\n * Build a nested object from a flat dot-notation key-value map. Alias\n * kept as `buildNestedObject` for clarity in callers that don't want to\n * read this as \"unflatten\".\n */\nexport function buildNestedObject(\n flatObj: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const key in flatObj) {\n if (Object.prototype.hasOwnProperty.call(flatObj, key)) {\n setNestedValue(result, key, flatObj[key])\n }\n }\n return result\n}\n\n/** Alias for {@link buildNestedObject}. */\nexport const unflattenObject = buildNestedObject\n\n/**\n * Normalize a (possibly platform-specific) path for display in reports\n * and console output. Converts Windows backslashes to forward slashes\n * so reports are platform-independent.\n */\nexport function normalizeDisplayPath(p: string): string {\n return p.split(path.sep).join(\"/\")\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport YAML from \"yaml\"\nimport { log } from \"@/utils\"\nimport { flattenObject } from \"./transform\"\n\n/**\n * Find the path of a locale file for a given language.\n *\n * Checks for .json, .yaml, .yml in that order. If multiple files with\n * the same base name exist (e.g. `en.json` and `en.yaml`), a warning\n * is emitted and the first match wins.\n */\nexport function findLocaleFile(\n localesDir: string,\n lang: string\n): string | null {\n const extensions = [\".json\", \".yaml\", \".yml\"]\n const found = extensions\n .map((ext) => path.join(localesDir, `${lang}${ext}`))\n .filter((p) => fs.existsSync(p))\n if (found.length === 0) return null\n if (found.length > 1) {\n log.warn(\n `Multiple locale files found for '${lang}' in ${localesDir}: ${found\n .map((p) => path.basename(p))\n .join(\n \", \"\n )}. Using '${path.basename(found[0])}'. Remove the duplicates to silence this warning.`\n )\n }\n return found[0]\n}\n\n/**\n * Load and parse a locale file (JSON or YAML).\n *\n * Tolerates real-world edge cases that previously crashed the tool:\n * - UTF-8 BOM prefix (\\\\uFEFF)\n * - whitespace-only content\n * - empty content\n * Returns an empty object instead of throwing in those cases.\n */\nexport function readLocaleFile(filePath: string): Record<string, unknown> {\n const ext = path.extname(filePath).toLowerCase()\n let content = fs.readFileSync(filePath, \"utf8\")\n if (content.charCodeAt(0) === 0xfeff) {\n content = content.slice(1)\n }\n const trimmed = content.trim()\n if (trimmed.length === 0) {\n return {}\n }\n\n if (ext === \".yaml\" || ext === \".yml\") {\n const parsed = YAML.parse(trimmed) as unknown\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {}\n }\n const parsedJson = JSON.parse(trimmed) as unknown\n return parsedJson &&\n typeof parsedJson === \"object\" &&\n !Array.isArray(parsedJson)\n ? (parsedJson as Record<string, unknown>)\n : {}\n}\n\n/**\n * Write a locale object to a file (JSON or YAML format).\n *\n * Uses a write-then-rename strategy: data is first written to\n * `<filePath>.tmp` and then atomically renamed into place. This prevents\n * truncation of the destination file if the process is killed mid-write.\n */\nexport function writeLocaleFile(\n filePath: string,\n obj: Record<string, unknown>\n): void {\n const ext = path.extname(filePath).toLowerCase()\n let content = \"\"\n\n if (ext === \".yaml\" || ext === \".yml\") {\n content = YAML.stringify(obj, { indent: 2 })\n } else {\n content = JSON.stringify(obj, null, 2)\n }\n\n if (!content.endsWith(\"\\n\")) {\n content += \"\\n\"\n }\n\n const tmpPath = `${filePath}.tmp`\n fs.writeFileSync(tmpPath, content, \"utf8\")\n try {\n fs.renameSync(tmpPath, filePath)\n } catch (error) {\n try {\n fs.unlinkSync(tmpPath)\n } catch {\n // ignore secondary failure\n }\n throw error\n }\n}\n\n/**\n * Load every supported language's locale file into a flat map.\n *\n * Returns:\n * - `locales`: parsed nested object per language\n * - `localesFlat`: dot-flat map per language\n * - `localeKeySets`: Set of dot-flat keys per language\n * - `localePaths`: resolved file path per language (null when missing)\n *\n * Missing locale files are reported via `onMissing` (defaults to a no-op).\n * Parse errors are thrown to the caller — they're never recoverable.\n */\nexport function loadAllLocales(\n localesDir: string,\n supportedLanguages: string[],\n onMissing: (lang: string, localesDir: string) => void = () => {\n /* no-op */\n }\n): {\n locales: Record<string, Record<string, unknown>>\n localesFlat: Record<string, Record<string, string>>\n localeKeySets: Record<string, Set<string>>\n localePaths: Record<string, string | null>\n} {\n const locales: Record<string, Record<string, unknown>> = {}\n const localesFlat: Record<string, Record<string, string>> = {}\n const localeKeySets: Record<string, Set<string>> = {}\n const localePaths: Record<string, string | null> = {}\n\n for (const lang of supportedLanguages) {\n const langPath = findLocaleFile(localesDir, lang)\n localePaths[lang] = langPath\n\n if (!langPath) {\n onMissing(lang, localesDir)\n locales[lang] = {}\n localesFlat[lang] = {}\n localeKeySets[lang] = new Set()\n continue\n }\n\n const parsed = readLocaleFile(langPath)\n locales[lang] = parsed\n localesFlat[lang] = flattenObject(parsed)\n localeKeySets[lang] = new Set(Object.keys(localesFlat[lang]))\n }\n\n return { locales, localesFlat, localeKeySets, localePaths }\n}\n\n/**\n * Phase 7: load every namespace file under `<localesDir>/<lang>/` and\n * merge into a single flat map per language using `namespace:` prefix.\n *\n * Example layout:\n * locales/en/common.json -> keys load as \"common:greeting\", ...\n * locales/en/auth.json -> keys load as \"auth:login.title\", ...\n *\n * Languages without a directory (or with an empty one) load as empty\n * maps; the caller's `onMissing` callback is invoked once per missing\n * language.\n */\nexport function loadNamespacedLocales(\n localesDir: string,\n supportedLanguages: string[],\n onMissing: (lang: string, localesDir: string) => void = () => {\n /* no-op */\n }\n): {\n locales: Record<string, Record<string, unknown>>\n localesFlat: Record<string, Record<string, string>>\n localeKeySets: Record<string, Set<string>>\n localeNamespaces: Record<string, Record<string, string>>\n} {\n const locales: Record<string, Record<string, unknown>> = {}\n const localesFlat: Record<string, Record<string, string>> = {}\n const localeKeySets: Record<string, Set<string>> = {}\n const localeNamespaces: Record<string, Record<string, string>> = {}\n\n for (const lang of supportedLanguages) {\n const langDir = path.join(localesDir, lang)\n localeNamespaces[lang] = {}\n if (!fs.existsSync(langDir) || !fs.statSync(langDir).isDirectory()) {\n onMissing(lang, localesDir)\n locales[lang] = {}\n localesFlat[lang] = {}\n localeKeySets[lang] = new Set()\n continue\n }\n\n const entries = fs.readdirSync(langDir, { withFileTypes: true })\n const merged: Record<string, unknown> = {}\n const mergedFlat: Record<string, string> = {}\n\n for (const entry of entries) {\n if (!entry.isFile()) continue\n const ext = path.extname(entry.name).toLowerCase()\n if (ext !== \".json\" && ext !== \".yaml\" && ext !== \".yml\") continue\n const ns = path.basename(entry.name, ext)\n const filePath = path.join(langDir, entry.name)\n localeNamespaces[lang][ns] = filePath\n\n const parsed = readLocaleFile(filePath)\n merged[ns] = parsed\n const nsFlat = flattenObject(parsed)\n for (const [k, v] of Object.entries(nsFlat)) {\n mergedFlat[`${ns}:${k}`] = v\n }\n }\n\n locales[lang] = merged\n localesFlat[lang] = mergedFlat\n localeKeySets[lang] = new Set(Object.keys(mergedFlat))\n }\n\n return { locales, localesFlat, localeKeySets, localeNamespaces }\n}\n","import { isKeyUsed, getBaseKey } from \"@/core/scanner\"\nimport type { I18nSharpenConfig, LocaleAlignmentMismatch } from \"@/types\"\n\n/**\n * Find keys used in source code that are absent from the default locale.\n * A key is considered present when it or any of its plural-suffix variants\n * exist in the default locale key set.\n */\nexport function findMissingKeys(\n usedKeys: Set<string>,\n defaultKeySet: Set<string>,\n config: Pick<I18nSharpenConfig, \"pluralSuffixes\">\n): string[] {\n const suffixes = config.pluralSuffixes ?? []\n const missing: string[] = []\n\n for (const key of usedKeys) {\n let exists = defaultKeySet.has(key)\n if (!exists) {\n for (const suffix of suffixes) {\n if (defaultKeySet.has(key + suffix)) {\n exists = true\n break\n }\n }\n }\n if (!exists) {\n missing.push(key)\n }\n }\n\n return missing\n}\n\n/**\n * Find keys defined in the default locale that are never referenced in\n * source code (accounting for ignoreKeys wildcards and plural suffixes).\n */\nexport function findUnusedKeys(\n defaultKeys: string[],\n usedKeys: Set<string>,\n config: Pick<I18nSharpenConfig, \"pluralSuffixes\" | \"ignoreKeys\">\n): string[] {\n const suffixes = config.pluralSuffixes ?? []\n const unused: string[] = []\n\n for (const key of defaultKeys) {\n if (!isKeyUsed(key, usedKeys, config.ignoreKeys, suffixes)) {\n unused.push(key)\n }\n }\n\n return unused\n}\n\n/**\n * Find cross-locale alignment mismatches: keys present in one language\n * file but absent from another. Returns one entry per (from, to) pair\n * that has at least one missing key.\n */\nexport function findAlignmentMismatches(\n config: Pick<I18nSharpenConfig, \"defaultLanguage\" | \"supportedLanguages\">,\n defaultKeys: string[],\n defaultKeySet: Set<string>,\n localesFlat: Record<string, Record<string, string>>,\n localeKeySets: Record<string, Set<string>>\n): LocaleAlignmentMismatch[] {\n const mismatches: LocaleAlignmentMismatch[] = []\n\n for (const lang of config.supportedLanguages) {\n if (lang === config.defaultLanguage) continue\n const langKeySet = localeKeySets[lang]\n\n const onlyInDefault = defaultKeys.filter((key) => !langKeySet.has(key))\n const onlyInTarget = Object.keys(localesFlat[lang]).filter(\n (key) => !defaultKeySet.has(key)\n )\n\n if (onlyInDefault.length > 0) {\n mismatches.push({\n from: config.defaultLanguage,\n to: lang,\n keys: onlyInDefault\n })\n }\n if (onlyInTarget.length > 0) {\n mismatches.push({\n from: lang,\n to: config.defaultLanguage,\n keys: onlyInTarget\n })\n }\n }\n\n return mismatches\n}\n\n/**\n * Find placeholder keys (where the translation value equals the key path)\n * split into active (used in code) and unused buckets.\n */\nexport function findPlaceholderKeys(\n config: Pick<\n I18nSharpenConfig,\n \"supportedLanguages\" | \"pluralSuffixes\" | \"ignoreKeys\"\n >,\n usedKeys: Set<string>,\n localesFlat: Record<string, Record<string, string>>\n): {\n activePlaceholderKeys: { key: string; lang: string }[]\n unusedPlaceholderKeys: { key: string; lang: string }[]\n} {\n const suffixes = config.pluralSuffixes ?? []\n const activePlaceholderKeys: { key: string; lang: string }[] = []\n const unusedPlaceholderKeys: { key: string; lang: string }[] = []\n\n for (const lang of config.supportedLanguages) {\n const flatMap = localesFlat[lang]\n for (const key in flatMap) {\n if (flatMap[key] === key) {\n if (isKeyUsed(key, usedKeys, config.ignoreKeys, suffixes)) {\n activePlaceholderKeys.push({ key, lang })\n } else {\n unusedPlaceholderKeys.push({ key, lang })\n }\n }\n }\n }\n\n return { activePlaceholderKeys, unusedPlaceholderKeys }\n}\n\n/**\n * Re-export getBaseKey with a bound suffixes array for use by output/report modules.\n */\nexport { getBaseKey }\n","import pc from \"picocolors\"\nimport { getBaseKey } from \"@/core/scanner\"\nimport type { ValidationResults } from \"@/types\"\nimport { log } from \"@/utils\"\n\nexport interface KeyToFilesLookup {\n has(key: string): boolean\n get(key: string): string[] | undefined\n}\n\n/**\n * Print all validation results to the console. Separated from the\n * orchestrator so the pure check functions stay side-effect-free.\n */\nexport function printValidationResults(\n results: ValidationResults,\n keyToFilesMap: KeyToFilesLookup,\n pluralSuffixes: string[]\n): void {\n const {\n missingKeys,\n activePlaceholderKeys,\n unusedKeys,\n unusedPlaceholderKeys,\n keysOnlyInLanguages\n } = results\n\n const getBK = (key: string): string => getBaseKey(key, pluralSuffixes)\n\n log.header(\"VALIDATION RESULTS\")\n\n // 1. Missing keys\n if (missingKeys.length > 0) {\n log.info(pc.bold(pc.red(`❌ Missing Keys (${missingKeys.length}):`)))\n missingKeys.sort().forEach((key) => {\n const files = keyToFilesMap.get(key) ?? []\n log.info(` - ${pc.red(key)} (referenced in: ${files.join(\", \")})`)\n })\n } else {\n log.success(\"Zero missing keys detected in the source code!\")\n }\n\n // 2. Active placeholders\n if (activePlaceholderKeys.length > 0) {\n log.info(\n `\\n${pc.bold(pc.red(`❌ Active Placeholder/Untranslated Keys Used in Code (${activePlaceholderKeys.length}):`))}`\n )\n activePlaceholderKeys\n .sort((a, b) => a.key.localeCompare(b.key))\n .forEach(({ key, lang }) => {\n const direct = keyToFilesMap.get(key)\n const baseKey = getBK(key)\n const baseFiles =\n baseKey !== key ? keyToFilesMap.get(baseKey) : undefined\n const files = direct ?? baseFiles ?? []\n log.info(\n ` - [${lang.toUpperCase()}] ${pc.red(key)} ${files.length > 0 ? `(referenced in: ${files.join(\", \")})` : \"\"}`\n )\n })\n } else {\n log.success(\"Zero active placeholder keys detected in the source code!\")\n }\n\n // 3. Locale alignment\n if (keysOnlyInLanguages.length > 0) {\n log.info(`\\n${pc.bold(pc.red(\"❌ Locale Alignment Mismatches:\"))}`)\n for (const mismatch of keysOnlyInLanguages) {\n log.info(\n ` ${pc.yellow(`Keys present in ${mismatch.from} but missing in ${mismatch.to} (${mismatch.keys.length}):`)}`\n )\n mismatch.keys\n .slice()\n .sort()\n .forEach((k) => {\n log.info(` - ${k}`)\n })\n }\n } else {\n log.success(\"Perfect key alignment across all locale files!\")\n }\n\n // 4. Unused keys (warning only)\n if (unusedKeys.length > 0) {\n log.info(\n `\\n${pc.bold(pc.yellow(`⚠️ Unused Keys in locales (${unusedKeys.length}):`))}`\n )\n unusedKeys.sort().forEach((key) => {\n log.info(` - ${pc.yellow(key)}`)\n })\n } else {\n log.success(\n \"Zero unused keys detected! All defined keys are referenced in code.\"\n )\n }\n\n // 5. Unused placeholders (warning only)\n if (unusedPlaceholderKeys.length > 0) {\n log.info(\n `\\n${pc.bold(pc.yellow(`⚠️ Unused Placeholder Keys in locales (${unusedPlaceholderKeys.length}):`))}`\n )\n unusedPlaceholderKeys\n .sort((a, b) => a.key.localeCompare(b.key))\n .forEach(({ key, lang }) => {\n log.info(` - [${lang.toUpperCase()}] ${pc.yellow(key)}`)\n })\n }\n\n // Quality metrics summary\n log.header(\"QUALITY METRICS SUMMARY\")\n log.info(\n `- Translation Key Coverage (Code -> Locales): ${pc.bold(results.codeKeyCoverage === \"100.00\" ? pc.green(results.codeKeyCoverage + \"%\") : pc.red(results.codeKeyCoverage + \"%\"))}`\n )\n log.info(\n `- Translation Key Utilization (Locales -> Code): ${pc.bold(pc.magenta(results.utilizationPercent + \"%\"))}`\n )\n log.info(`- Total Defined Keys: ${pc.bold(results.totalDefinedKeys)}`)\n log.info(`- Actually Used in Code: ${pc.bold(results.usedDefinedKeysCount)}`)\n log.info(`- Missing/Undefined: ${pc.bold(missingKeys.length)}`)\n log.info(`- Unused/Stale: ${pc.bold(unusedKeys.length)}`)\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport pc from \"picocolors\"\nimport { normalizeDisplayPath } from \"@/core/locale-io\"\nimport type { ValidationResults, LocaleAlignmentMismatch } from \"@/types\"\nimport { log } from \"@/utils\"\n\n/**\n * A lookup interface that the validator builds during scanning and the\n * report consumes. Kept narrow so the report module is decoupled from\n * the (Set-backed) implementation in the validator orchestrator.\n */\nexport interface KeyToFilesLookup {\n has(key: string): boolean\n get(key: string): string[] | undefined\n}\n\n/**\n * Render and persist the markdown coverage report when `outputReport`\n * is set. Returns the resolved report path (or null when disabled).\n *\n * Kept side-effect-free aside from the single mkdirSync/writeFileSync\n * pair so it's trivial to test by snapshotting the returned content via\n * `renderMarkdownReport`.\n */\nexport function writeMarkdownReport(args: {\n cwd: string\n outputReport: string\n defaultBasename: string\n results: ValidationResults\n keyToFilesMap: KeyToFilesLookup\n getBaseKey: (key: string) => string\n}): string {\n const reportPath = path.resolve(args.cwd, args.outputReport)\n const markdownContent = renderMarkdownReport(args)\n // Ensure parent directory exists before writing the report.\n fs.mkdirSync(path.dirname(reportPath), { recursive: true })\n fs.writeFileSync(reportPath, markdownContent, \"utf8\")\n log.info(\n `💾 Markdown report saved to: ${pc.cyan(normalizeDisplayPath(path.relative(args.cwd, reportPath)))}\\n`\n )\n return reportPath\n}\n\n/**\n * Render the markdown coverage report as a string. Exposed for tests\n * that don't want to hit the filesystem.\n */\nexport function renderMarkdownReport(args: {\n defaultBasename: string\n results: ValidationResults\n keyToFilesMap: KeyToFilesLookup\n getBaseKey: (key: string) => string\n}): string {\n const {\n missingKeys,\n activePlaceholderKeys,\n unusedKeys,\n unusedPlaceholderKeys,\n keysOnlyInLanguages,\n codeKeyCoverage,\n utilizationPercent,\n totalDefinedKeys,\n usedDefinedKeysCount\n } = args.results\n const { keyToFilesMap, getBaseKey, defaultBasename } = args\n\n return `# i18n Quality and Coverage Report\n\nGenerated on: ${new Date().toISOString()}\n\n## Quality Metrics Summary\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Code Translation Coverage** | ${codeKeyCoverage}% | ${codeKeyCoverage === \"100.00\" ? \"🟢 100% Perfect\" : \"🔴 Missing Translations\"} |\n| **Locales Key Utilization** | ${utilizationPercent}% | ${Number(utilizationPercent) > 90 ? \"🟢 High\" : \"🟡 Medium\"} |\n| **Total Defined Keys** | ${totalDefinedKeys} | - |\n| **Actually Used Keys** | ${usedDefinedKeysCount} | - |\n| **Missing Keys** | ${missingKeys.length} | ${missingKeys.length === 0 ? \"🟢 Clean\" : \"🔴 Action Required\"} |\n| **Active Placeholders** | ${activePlaceholderKeys.length} | ${activePlaceholderKeys.length === 0 ? \"🟢 Clean\" : \"🔴 Action Required\"} |\n| **Unused Keys** | ${unusedKeys.length} | ${unusedKeys.length === 0 ? \"🟢 Optimized\" : \"🟡 Can be pruned\"} |\n| **Locale Alignment** | ${keysOnlyInLanguages.length === 0 ? \"Align'd\" : \"Mismatch\"} | ${keysOnlyInLanguages.length === 0 ? \"🟢 Perfect\" : \"🔴 Action Required\"} |\n\n${renderMissingKeysSection(missingKeys, keyToFilesMap, defaultBasename)}\n\n${renderActivePlaceholdersSection(activePlaceholderKeys, keyToFilesMap, getBaseKey)}\n\n${renderAlignmentSection(keysOnlyInLanguages)}\n\n${renderUnusedKeysSection(unusedKeys)}\n\n${renderUnusedPlaceholdersSection(unusedPlaceholderKeys)}\n`\n}\n\nfunction renderMissingKeysSection(\n missingKeys: string[],\n keyToFilesMap: KeyToFilesLookup,\n defaultBasename: string\n): string {\n if (missingKeys.length === 0) {\n return \"## ✅ Missing Keys\\n\\nNo missing translation keys detected in the source code.\"\n }\n return `## ❌ Missing Keys (${missingKeys.length})\n\nThe following keys are used in the source code but are not defined in the main locale file \\`${defaultBasename}\\`:\n\n${missingKeys\n .sort()\n .map(\n (key) =>\n `- **\\`${key}\\`** (referenced in: ${keyToFilesMap\n .get(key)\n ?.map((f) => `\\`${f}\\``)\n .join(\", \")})`\n )\n .join(\"\\n\")}\n`\n}\n\nfunction renderActivePlaceholdersSection(\n activePlaceholderKeys: { key: string; lang: string }[],\n keyToFilesMap: KeyToFilesLookup,\n getBaseKey: (key: string) => string\n): string {\n if (activePlaceholderKeys.length === 0) {\n return \"## ✅ Active Placeholders\\n\\nNo active placeholder keys detected in the source code.\"\n }\n return `## ❌ Active Placeholders (${activePlaceholderKeys.length})\n\nThe following keys are referenced in the source code but only have placeholder values (identical to the key path):\n\n${activePlaceholderKeys\n .sort((a, b) => a.key.localeCompare(b.key))\n .map(\n ({ key, lang }) =>\n `- **\\`${key}\\`** [\\`${lang.toUpperCase()}\\`] ${\n keyToFilesMap.has(key)\n ? `(referenced in: ${keyToFilesMap\n .get(key)\n ?.map((f) => `\\`${f}\\``)\n .join(\", \")})`\n : keyToFilesMap.has(getBaseKey(key))\n ? `(referenced in: ${keyToFilesMap\n .get(getBaseKey(key))\n ?.map((f) => `\\`${f}\\``)\n .join(\", \")})`\n : \"\"\n }`\n )\n .join(\"\\n\")}\n`\n}\n\nfunction renderAlignmentSection(\n keysOnlyInLanguages: LocaleAlignmentMismatch[]\n): string {\n if (keysOnlyInLanguages.length === 0) {\n return \"## ✅ Locale Alignment\\n\\nPerfect key alignment between all locale files.\"\n }\n return `## ❌ Locale Alignment Mismatches\n\n${keysOnlyInLanguages\n .map(\n (m) => `### Keys in ${m.from} but missing in ${m.to} (${m.keys.length})\n${m.keys\n .slice()\n .sort()\n .map((k) => `- \\`${k}\\``)\n .join(\"\\n\")}\n`\n )\n .join(\"\\n\")}\n`\n}\n\nfunction renderUnusedKeysSection(unusedKeys: string[]): string {\n if (unusedKeys.length === 0) {\n return \"## ✅ Unused Keys\\n\\nAll defined translation keys are used in the source code.\"\n }\n return `## ⚠️ Unused Keys (${unusedKeys.length})\n\nThese keys are defined in the locale file but are not used anywhere in the source code. They can be safely pruned to reduce bundle size:\n\n${unusedKeys\n .sort()\n .map((key) => `- \\`${key}\\``)\n .join(\"\\n\")}\n`\n}\n\nfunction renderUnusedPlaceholdersSection(\n unusedPlaceholderKeys: { key: string; lang: string }[]\n): string {\n if (unusedPlaceholderKeys.length === 0) return \"\"\n return `## ⚠️ Unused Placeholders (${unusedPlaceholderKeys.length})\n\nThese keys have placeholder values but are not currently used in the source code. They should be translated before use:\n\n${unusedPlaceholderKeys\n .sort((a, b) => a.key.localeCompare(b.key))\n .map(({ key, lang }) => `- \\`${key}\\` [\\`${lang.toUpperCase()}\\`]`)\n .join(\"\\n\")}\n`\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport pc from \"picocolors\"\nimport { I18nSharpenError } from \"@/core/errors\"\nimport { loadAllLocales, normalizeDisplayPath } from \"@/core/locale-io\"\nimport {\n scanSourceFiles,\n detectUsedKeys,\n buildKeyRegex,\n buildAttrRegex,\n buildDynamicCallRegex,\n isStaticStringLiteral,\n getBaseKey\n} from \"@/core/scanner\"\nimport type { I18nSharpenConfig, ValidationResults } from \"@/types\"\nimport { log } from \"@/utils\"\nimport {\n findMissingKeys,\n findUnusedKeys,\n findAlignmentMismatches,\n findPlaceholderKeys\n} from \"./validate/checks\"\nimport { printValidationResults } from \"./validate/output\"\nimport { writeMarkdownReport } from \"./validate/report\"\n\nexport function validate(\n config: I18nSharpenConfig,\n cwd: string = process.cwd()\n): ValidationResults {\n log.header(\"I18N-SHARPEN VALIDATOR\")\n\n const localesDirAbs = path.resolve(cwd, config.localesDir)\n\n // --- Load locales ---\n const { localesFlat, localeKeySets, localePaths } = loadAllLocales(\n localesDirAbs,\n config.supportedLanguages,\n (lang) => {\n log.warn(\n `Locale file not found for language '${lang}' in: ${localesDirAbs}`\n )\n }\n )\n\n const defaultLocalePath = localePaths[config.defaultLanguage] ?? null\n\n if (!defaultLocalePath) {\n throw new I18nSharpenError({\n kind: \"filesystem\",\n message: `Default language '${config.defaultLanguage}' locale file not found.`,\n path: localesDirAbs\n })\n }\n\n const defaultKeys = Object.keys(localesFlat[config.defaultLanguage])\n const defaultKeySet = localeKeySets[config.defaultLanguage]\n\n log.info(\n `Loaded default language '${config.defaultLanguage}' with ${pc.green(defaultKeys.length)} keys.`\n )\n for (const lang of config.supportedLanguages) {\n if (lang !== config.defaultLanguage) {\n const keysCount = Object.keys(localesFlat[lang]).length\n log.info(`Loaded language '${lang}' with ${pc.green(keysCount)} keys.`)\n }\n }\n\n // --- Scan source files ---\n const files = scanSourceFiles(config, cwd)\n\n for (const scanDir of config.scanDirs) {\n const scanDirAbs = path.resolve(cwd, scanDir)\n if (fs.existsSync(scanDirAbs)) {\n log.info(\n `Scanning directory: ${pc.cyan(normalizeDisplayPath(path.relative(cwd, scanDirAbs)))}`\n )\n } else {\n log.warn(`Scan directory does not exist: ${scanDirAbs}`)\n }\n }\n\n log.info(`Found ${pc.green(files.length)} source files to check.`)\n\n // --- Detect used keys ---\n const matchFunctions = config.matchFunctions ?? [\"t\", \"getTranslation\"]\n const matchAttributes = config.matchAttributes ?? [\"i18nKey\", \"id\"]\n\n const { usedKeys, fileContents } = detectUsedKeys(\n files,\n matchFunctions,\n matchAttributes\n )\n\n // Build key->files map for output/report and dynamic key warnings\n const keyToFilesSet = new Map<string, Set<string>>()\n const keyToFilesMap = {\n has(key: string): boolean {\n return keyToFilesSet.has(key)\n },\n get(key: string): string[] | undefined {\n const s = keyToFilesSet.get(key)\n return s ? Array.from(s) : undefined\n },\n add(key: string, file: string): void {\n let s = keyToFilesSet.get(key)\n if (!s) {\n s = new Set()\n keyToFilesSet.set(key, s)\n }\n s.add(file)\n }\n }\n\n const keyRegex = buildKeyRegex(matchFunctions)\n const attrRegex = buildAttrRegex(matchAttributes)\n const dynamicCallRegex = buildDynamicCallRegex(matchFunctions)\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i]\n const cleanContent = fileContents[i]\n const relativePath = normalizeDisplayPath(path.relative(cwd, file))\n\n for (const match of cleanContent.matchAll(keyRegex)) {\n const key = match[2]\n if (key.endsWith(\".\")) continue\n keyToFilesMap.add(key, relativePath)\n }\n for (const match of cleanContent.matchAll(attrRegex)) {\n const key = match[2]\n if (key.endsWith(\".\")) continue\n keyToFilesMap.add(key, relativePath)\n }\n for (const match of cleanContent.matchAll(dynamicCallRegex)) {\n const arg = match[1].trim()\n if (arg.length === 0) continue\n if (!isStaticStringLiteral(arg)) {\n log.warn(\n `Potential dynamic translation key reference in ${pc.cyan(relativePath)}: ${pc.yellow(match[0])}`\n )\n }\n }\n }\n\n // Loose key match second pass\n if (config.looseKeyMatch) {\n for (const key of defaultKeys) {\n if (usedKeys.has(key)) continue\n const dq = `\"${key}\"`\n const sq = `'${key}'`\n const bq = `\\`${key}\\``\n for (let i = 0; i < files.length; i++) {\n const cleanContent = fileContents[i]\n if (\n cleanContent.includes(dq) ||\n cleanContent.includes(sq) ||\n cleanContent.includes(bq)\n ) {\n usedKeys.add(key)\n keyToFilesMap.add(\n key,\n normalizeDisplayPath(path.relative(cwd, files[i]))\n )\n }\n }\n }\n }\n\n log.info(\n `Found ${pc.green(usedKeys.size)} unique translation keys used in source code.`\n )\n\n // --- Pure checks ---\n const suffixes = config.pluralSuffixes ?? []\n const missingKeys = findMissingKeys(usedKeys, defaultKeySet, config)\n const unusedKeys = findUnusedKeys(defaultKeys, usedKeys, config)\n const keysOnlyInLanguages = findAlignmentMismatches(\n config,\n defaultKeys,\n defaultKeySet,\n localesFlat,\n localeKeySets\n )\n const { activePlaceholderKeys, unusedPlaceholderKeys } = findPlaceholderKeys(\n config,\n usedKeys,\n localesFlat\n )\n\n // Coverage stats\n const totalDefinedKeys = defaultKeys.length\n const usedDefinedKeysCount = defaultKeys.length - unusedKeys.length\n const utilizationPercent =\n totalDefinedKeys > 0\n ? ((usedDefinedKeysCount / totalDefinedKeys) * 100).toFixed(2)\n : \"0.00\"\n const codeKeyCoverage =\n usedKeys.size > 0\n ? ((usedDefinedKeysCount / usedKeys.size) * 100).toFixed(2)\n : \"100.00\"\n\n const results: ValidationResults = {\n missingKeys,\n activePlaceholderKeys,\n unusedKeys,\n unusedPlaceholderKeys,\n keysOnlyInLanguages,\n codeKeyCoverage,\n utilizationPercent,\n totalDefinedKeys,\n usedDefinedKeysCount\n }\n\n // --- Output ---\n printValidationResults(results, keyToFilesMap, suffixes)\n\n if (config.outputReport) {\n writeMarkdownReport({\n cwd,\n outputReport: config.outputReport,\n defaultBasename: path.basename(defaultLocalePath),\n results,\n keyToFilesMap,\n getBaseKey: (key) => getBaseKey(key, suffixes)\n })\n }\n\n const hasError =\n missingKeys.length > 0 ||\n activePlaceholderKeys.length > 0 ||\n keysOnlyInLanguages.length > 0\n\n if (hasError) {\n log.error(\n \"Validation failed. Please fix the missing keys, active placeholders, or locale mismatches.\"\n )\n } else {\n log.success(\"i18n Quality Validation passed successfully!\\n\")\n }\n\n return results\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport pc from \"picocolors\"\nimport { I18nSharpenError } from \"@/core/errors\"\nimport {\n flattenObject,\n unflattenObject,\n findLocaleFile,\n readLocaleFile,\n writeLocaleFile,\n loadNamespacedLocales\n} from \"@/core/locale-io\"\nimport { scanSourceFiles, detectUsedKeys } from \"@/core/scanner\"\nimport type { I18nSharpenConfig } from \"@/types\"\nimport { log } from \"@/utils\"\n\nexport function extract(\n config: I18nSharpenConfig,\n cwd: string = process.cwd()\n): void {\n log.header(\"I18N-SHARPEN EXTRACTOR\")\n\n const localesDirAbs = path.resolve(cwd, config.localesDir)\n\n if (!fs.existsSync(localesDirAbs)) {\n throw new I18nSharpenError({\n kind: \"filesystem\",\n message: `Locales directory not found: ${localesDirAbs}`,\n path: localesDirAbs\n })\n }\n\n // Scan source files and detect used keys\n const files = scanSourceFiles(config, cwd)\n const matchFunctions = config.matchFunctions ?? [\"t\", \"getTranslation\"]\n const matchAttributes = config.matchAttributes ?? [\"i18nKey\", \"id\"]\n const { usedKeys } = detectUsedKeys(files, matchFunctions, matchAttributes)\n\n log.info(\n `Found ${pc.green(usedKeys.size)} unique translation keys referenced in code.`\n )\n\n if (config.localesLayout === \"namespaced\") {\n extractNamespaced(config, localesDirAbs, usedKeys)\n } else {\n extractFlat(config, localesDirAbs, usedKeys)\n }\n}\n\n/**\n * Extract missing keys into flat locale files (one file per language).\n * This is the default (pre-Phase 7) behavior.\n */\nfunction extractFlat(\n config: I18nSharpenConfig,\n localesDirAbs: string,\n usedKeys: Set<string>\n): void {\n // Two-phase write: parse every existing locale file up-front and\n // compute the new flat map. Only after every parse succeeds do we\n // write anything. Prevents partial extraction when one of several\n // languages has a corrupt locale file.\n interface Plan {\n lang: string\n langPath: string\n nestedJson: Record<string, unknown>\n missingKeys: string[]\n }\n const writePlans: Plan[] = []\n const suffixes = config.pluralSuffixes ?? []\n\n for (const lang of config.supportedLanguages) {\n let langPath = findLocaleFile(localesDirAbs, lang)\n let flatJson: Record<string, string> = {}\n\n if (!langPath) {\n langPath = path.join(localesDirAbs, `${lang}.json`)\n } else {\n try {\n const langJson = readLocaleFile(langPath)\n flatJson = flattenObject(langJson)\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"parse\",\n message: `Failed to parse locale file '${path.basename(langPath)}': ${(error as Error).message}`,\n path: langPath\n })\n }\n }\n\n const missingKeys: string[] = []\n for (const key of usedKeys) {\n let exists = key in flatJson\n if (!exists) {\n for (const suffix of suffixes) {\n if (key + suffix in flatJson) {\n exists = true\n break\n }\n }\n }\n if (!exists) {\n missingKeys.push(key)\n }\n }\n\n if (missingKeys.length > 0) {\n missingKeys.sort()\n for (const key of missingKeys) {\n flatJson[key] = key\n }\n const nestedJson = unflattenObject(flatJson)\n writePlans.push({ lang, langPath, nestedJson, missingKeys })\n } else {\n log.info(\n `✨ No new keys to extract for ${pc.cyan(path.basename(langPath))}.`\n )\n }\n }\n\n let totalExtractedCount = 0\n for (const plan of writePlans) {\n log.info(\n `📥 Extracting ${pc.green(plan.missingKeys.length)} new keys to ${pc.cyan(path.basename(plan.langPath))}:`\n )\n for (const key of plan.missingKeys) {\n log.info(` + ${pc.green(key)}`)\n }\n try {\n writeLocaleFile(plan.langPath, plan.nestedJson)\n totalExtractedCount += plan.missingKeys.length\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"filesystem\",\n message: `Failed to write to file '${plan.langPath}': ${(error as Error).message}`,\n path: plan.langPath,\n cause: error\n })\n }\n }\n\n if (totalExtractedCount > 0) {\n log.success(\"Locale files updated successfully!\\n\")\n } else {\n log.success(\n \"All used translation keys are already present in locale files.\\n\"\n )\n }\n}\n\n/**\n * Extract missing keys into namespaced locale files.\n * Keys with a colon prefix (`namespace:key.path`) are routed to the\n * appropriate namespace file (`<localesDir>/<lang>/<namespace>.json`).\n * Keys without a colon go into `default.json`.\n */\nfunction extractNamespaced(\n config: I18nSharpenConfig,\n localesDirAbs: string,\n usedKeys: Set<string>\n): void {\n const suffixes = config.pluralSuffixes ?? []\n\n const { localesFlat, localeNamespaces } = loadNamespacedLocales(\n localesDirAbs,\n config.supportedLanguages\n )\n\n interface NsPlan {\n lang: string\n ns: string\n filePath: string\n missingKeys: string[]\n }\n const writePlans: NsPlan[] = []\n\n for (const lang of config.supportedLanguages) {\n const existingFlat = localesFlat[lang] ?? {}\n const nsFilePaths = localeNamespaces[lang] ?? {}\n\n const missingByNs = new Map<string, string[]>()\n\n for (const fullKey of usedKeys) {\n const colonIdx = fullKey.indexOf(\":\")\n const ns = colonIdx >= 0 ? fullKey.slice(0, colonIdx) : \"default\"\n const keyPath = colonIdx >= 0 ? fullKey.slice(colonIdx + 1) : fullKey\n const namespacedKey = `${ns}:${keyPath}`\n\n let exists = namespacedKey in existingFlat\n if (!exists) {\n for (const suffix of suffixes) {\n if (`${ns}:${keyPath}${suffix}` in existingFlat) {\n exists = true\n break\n }\n }\n }\n if (!exists) {\n let arr = missingByNs.get(ns)\n if (!arr) {\n arr = []\n missingByNs.set(ns, arr)\n }\n arr.push(keyPath)\n }\n }\n\n for (const [ns, missingKeys] of missingByNs) {\n missingKeys.sort()\n const langDir = path.join(localesDirAbs, lang)\n const filePath = nsFilePaths[ns] ?? path.join(langDir, `${ns}.json`)\n writePlans.push({ lang, ns, filePath, missingKeys })\n }\n\n if (missingByNs.size === 0) {\n log.info(`✨ No new keys to extract for ${pc.cyan(lang)} (namespaced).`)\n }\n }\n\n interface WriteItem {\n filePath: string\n nestedJson: Record<string, unknown>\n missingKeys: string[]\n displayLabel: string\n }\n const writeItems: WriteItem[] = []\n\n for (const plan of writePlans) {\n const langDir = path.dirname(plan.filePath)\n let existingFlat: Record<string, string> = {}\n\n if (fs.existsSync(plan.filePath)) {\n try {\n existingFlat = flattenObject(readLocaleFile(plan.filePath))\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"parse\",\n message: `Failed to parse namespace file '${plan.filePath}': ${(error as Error).message}`,\n path: plan.filePath\n })\n }\n } else {\n fs.mkdirSync(langDir, { recursive: true })\n }\n\n for (const keyPath of plan.missingKeys) {\n existingFlat[keyPath] = keyPath\n }\n\n const nestedJson = unflattenObject(existingFlat)\n const displayLabel = `${plan.lang}/${plan.ns}.json`\n writeItems.push({\n filePath: plan.filePath,\n nestedJson,\n missingKeys: plan.missingKeys,\n displayLabel\n })\n }\n\n let totalExtractedCount = 0\n for (const item of writeItems) {\n log.info(\n `📥 Extracting ${pc.green(item.missingKeys.length)} new keys to ${pc.cyan(item.displayLabel)}:`\n )\n for (const key of item.missingKeys) {\n log.info(` + ${pc.green(key)}`)\n }\n try {\n writeLocaleFile(item.filePath, item.nestedJson)\n totalExtractedCount += item.missingKeys.length\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"filesystem\",\n message: `Failed to write to file '${item.filePath}': ${(error as Error).message}`,\n path: item.filePath,\n cause: error\n })\n }\n }\n\n if (totalExtractedCount > 0) {\n log.success(\"Locale files updated successfully!\\n\")\n } else {\n log.success(\n \"All used translation keys are already present in locale files.\\n\"\n )\n }\n}\n","import * as path from \"path\"\nimport pc from \"picocolors\"\nimport { I18nSharpenError } from \"@/core/errors\"\nimport {\n flattenObject,\n unflattenObject,\n findLocaleFile,\n readLocaleFile,\n writeLocaleFile,\n loadNamespacedLocales\n} from \"@/core/locale-io\"\nimport { isKeyUsed } from \"@/core/scanner\"\nimport type { I18nSharpenConfig, PruneResult } from \"@/types\"\nimport { log } from \"@/utils\"\n\ninterface WritePlan {\n lang: string\n langPath: string\n nestedJson: Record<string, unknown>\n prunedKeys: string[]\n /** Optional display label override (used by namespaced mode) */\n displayName?: string\n}\n\n/**\n * Execute prune write plans: log what will be removed, optionally write\n * files to disk, and return a structured PruneResult.\n */\nexport function executePrunePlans(\n writePlans: WritePlan[],\n perLocale: PruneResult[\"perLocale\"],\n dryRun: boolean\n): PruneResult {\n let totalPrunedCount = 0\n let written = false\n\n if (dryRun) {\n log.header(\n writePlans.length === 0\n ? \"PRUNE PREVIEW (no changes)\"\n : \"PRUNE PREVIEW (dry-run — no files written)\"\n )\n }\n\n for (const plan of writePlans) {\n const displayName = plan.displayName ?? path.basename(plan.langPath)\n const verb = dryRun ? \"Would prune\" : \"Pruning\"\n log.info(\n `${verb} ${pc.yellow(plan.prunedKeys.length)} unused keys from ${pc.cyan(displayName)}`\n )\n const sample = plan.prunedKeys.slice(0, 10)\n for (const k of sample) {\n log.info(` - ${pc.yellow(k)}`)\n }\n if (plan.prunedKeys.length > sample.length) {\n log.info(\n ` ... and ${plan.prunedKeys.length - sample.length} more (run with verbose flag to see all)`\n )\n }\n\n if (!dryRun) {\n try {\n writeLocaleFile(plan.langPath, plan.nestedJson)\n totalPrunedCount += plan.prunedKeys.length\n written = true\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"filesystem\",\n message: `Failed to write to file '${plan.langPath}': ${(error as Error).message}`,\n path: plan.langPath,\n cause: error\n })\n }\n } else {\n totalPrunedCount += plan.prunedKeys.length\n }\n }\n\n if (dryRun) {\n if (totalPrunedCount > 0) {\n log.warn(\n `Dry-run: ${totalPrunedCount} key${totalPrunedCount === 1 ? \"\" : \"s\"} would be removed. Re-run with --force (or set prune.force: true in config) to apply.\\n`\n )\n } else {\n log.success(\"Dry-run: no unused keys found to prune.\\n\")\n }\n } else if (totalPrunedCount > 0) {\n log.success(\n `Files have been successfully cleaned! Total pruned: ${totalPrunedCount} keys.\\n`\n )\n } else {\n log.success(\"No unused keys found to prune.\\n\")\n }\n\n return { written, dryRun, perLocale, totalPruned: totalPrunedCount }\n}\n\n/**\n * Prune unused keys from flat locale files (one file per language).\n */\nexport function pruneFlat(\n config: I18nSharpenConfig,\n localesDirAbs: string,\n usedKeys: Set<string>,\n fileContents: string[],\n dryRun: boolean\n): PruneResult {\n const allLocaleKeys = new Set<string>()\n const localesFlat: Record<string, Record<string, string>> = {}\n const localeFilePaths: Record<string, string> = {}\n\n for (const lang of config.supportedLanguages) {\n const langPath = findLocaleFile(localesDirAbs, lang)\n if (langPath) {\n localeFilePaths[lang] = langPath\n try {\n const parsed = readLocaleFile(langPath)\n localesFlat[lang] = flattenObject(parsed)\n Object.keys(localesFlat[lang]).forEach((key) => allLocaleKeys.add(key))\n } catch (error) {\n throw new I18nSharpenError({\n kind: \"parse\",\n message: `Failed to parse locale file '${path.basename(langPath)}': ${(error as Error).message}`,\n path: langPath\n })\n }\n }\n }\n\n // Opt-in loose match\n if (config.looseKeyMatch) {\n for (const key of allLocaleKeys) {\n if (usedKeys.has(key)) continue\n const dq = `\"${key}\"`,\n sq = `'${key}'`,\n bq = `\\`${key}\\``\n for (const cleanContent of fileContents) {\n if (\n cleanContent.includes(dq) ||\n cleanContent.includes(sq) ||\n cleanContent.includes(bq)\n ) {\n usedKeys.add(key)\n break\n }\n }\n }\n }\n\n const suffixes = config.pluralSuffixes ?? []\n const isUsed = (key: string): boolean =>\n isKeyUsed(key, usedKeys, config.ignoreKeys, suffixes)\n\n interface Plan {\n lang: string\n langPath: string\n nestedJson: Record<string, unknown>\n prunedKeys: string[]\n }\n const writePlans: Plan[] = []\n const perLocale: PruneResult[\"perLocale\"] = []\n\n for (const lang of config.supportedLanguages) {\n const langPath = localeFilePaths[lang]\n if (!langPath) continue\n\n const flatJson = localesFlat[lang]\n const newFlatJson: Record<string, string> = {}\n const prunedKeys: string[] = []\n\n for (const key in flatJson) {\n if (isUsed(key)) {\n newFlatJson[key] = flatJson[key]\n } else {\n prunedKeys.push(key)\n }\n }\n\n if (prunedKeys.length > 0) {\n const nestedJson = unflattenObject(newFlatJson)\n writePlans.push({ lang, langPath, nestedJson, prunedKeys })\n } else {\n log.info(\n `✨ No unused keys to prune in ${pc.cyan(path.basename(langPath))}.`\n )\n }\n perLocale.push({ lang, file: langPath, prunedKeys })\n }\n\n return executePrunePlans(writePlans, perLocale, dryRun)\n}\n\n/**\n * Prune unused keys from namespaced locale files (one directory per language,\n * one file per namespace).\n */\nexport function pruneNamespaced(\n config: I18nSharpenConfig,\n localesDirAbs: string,\n usedKeys: Set<string>,\n fileContents: string[],\n dryRun: boolean\n): PruneResult {\n const suffixes = config.pluralSuffixes ?? []\n\n const { localesFlat, localeNamespaces } = loadNamespacedLocales(\n localesDirAbs,\n config.supportedLanguages\n )\n\n const allLocaleKeys = new Set<string>()\n for (const lang of config.supportedLanguages) {\n for (const key of Object.keys(localesFlat[lang] ?? {})) {\n allLocaleKeys.add(key)\n }\n }\n\n if (config.looseKeyMatch) {\n for (const key of allLocaleKeys) {\n if (usedKeys.has(key)) continue\n const dq = `\"${key}\"`,\n sq = `'${key}'`,\n bq = `\\`${key}\\``\n for (const cleanContent of fileContents) {\n if (\n cleanContent.includes(dq) ||\n cleanContent.includes(sq) ||\n cleanContent.includes(bq)\n ) {\n usedKeys.add(key)\n break\n }\n }\n }\n }\n\n const isUsed = (namespacedKey: string): boolean =>\n isKeyUsed(namespacedKey, usedKeys, config.ignoreKeys, suffixes)\n\n interface NsPlan {\n lang: string\n ns: string\n filePath: string\n nestedJson: Record<string, unknown>\n prunedKeys: string[]\n }\n const writePlans: NsPlan[] = []\n const perLocale: PruneResult[\"perLocale\"] = []\n\n for (const lang of config.supportedLanguages) {\n const nsFilePaths = localeNamespaces[lang] ?? {}\n const langFlat = localesFlat[lang] ?? {}\n\n const keysByNs = new Map<string, Record<string, string>>()\n for (const [namespacedKey, value] of Object.entries(langFlat)) {\n const colonIdx = namespacedKey.indexOf(\":\")\n const ns = colonIdx >= 0 ? namespacedKey.slice(0, colonIdx) : \"default\"\n const keyPath =\n colonIdx >= 0 ? namespacedKey.slice(colonIdx + 1) : namespacedKey\n let nsObj = keysByNs.get(ns)\n if (!nsObj) {\n nsObj = {}\n keysByNs.set(ns, nsObj)\n }\n nsObj[keyPath] = value\n }\n\n for (const [ns, nsFlatKeys] of keysByNs) {\n const filePath = nsFilePaths[ns]\n if (!filePath) continue\n\n const newFlatJson: Record<string, string> = {}\n const prunedKeys: string[] = []\n\n for (const keyPath of Object.keys(nsFlatKeys)) {\n const namespacedKey = `${ns}:${keyPath}`\n if (isUsed(namespacedKey)) {\n newFlatJson[keyPath] = nsFlatKeys[keyPath]\n } else {\n prunedKeys.push(keyPath)\n }\n }\n\n if (prunedKeys.length > 0) {\n const nestedJson = unflattenObject(newFlatJson)\n writePlans.push({ lang, ns, filePath, nestedJson, prunedKeys })\n } else {\n log.info(\n `✨ No unused keys to prune in ${pc.cyan(`${lang}/${ns}.json`)}.`\n )\n }\n\n perLocale.push({ lang, file: filePath, prunedKeys })\n }\n\n if (keysByNs.size === 0) {\n log.info(`✨ No locale files found for ${pc.cyan(lang)}.`)\n }\n }\n\n const flatPlans = writePlans.map((p) => ({\n lang: p.lang,\n langPath: p.filePath,\n nestedJson: p.nestedJson,\n prunedKeys: p.prunedKeys,\n displayName: `${p.lang}/${p.ns}.json`\n }))\n\n return executePrunePlans(flatPlans, perLocale, dryRun)\n}\n","import * as fs from \"fs\"\nimport * as path from \"path\"\nimport pc from \"picocolors\"\nimport { I18nSharpenError } from \"@/core/errors\"\nimport { scanSourceFiles, detectUsedKeys } from \"@/core/scanner\"\nimport type { I18nSharpenConfig, PruneOptions, PruneResult } from \"@/types\"\nimport { log } from \"@/utils\"\nimport { pruneFlat, pruneNamespaced } from \"./prune/plans\"\n\n/**\n * Prune unused keys from locale files.\n *\n * Safe-by-default: runs in dry-run mode unless force is explicitly set via\n * config.prune.force, options.force, or --force CLI flag.\n * options.dryRun always wins over force.\n */\nexport function prune(\n config: I18nSharpenConfig,\n cwd: string = process.cwd(),\n options: PruneOptions = {}\n): PruneResult {\n log.header(\"I18N-SHARPEN PRUNER\")\n\n const configForce = config.prune?.force === true\n const optForce = options.force === true\n const optDryRun = options.dryRun === true\n const dryRun = optDryRun ? true : !(optForce || configForce)\n\n const localesDirAbs = path.resolve(cwd, config.localesDir)\n\n if (!fs.existsSync(localesDirAbs)) {\n throw new I18nSharpenError({\n kind: \"filesystem\",\n message: `Locales directory not found: ${localesDirAbs}`,\n path: localesDirAbs\n })\n }\n\n // Scan source files and detect used keys\n const files = scanSourceFiles(config, cwd)\n const matchFunctions = config.matchFunctions ?? [\"t\", \"getTranslation\"]\n const matchAttributes = config.matchAttributes ?? [\"i18nKey\", \"id\"]\n const { usedKeys, fileContents } = detectUsedKeys(\n files,\n matchFunctions,\n matchAttributes\n )\n\n log.info(\n `Found ${pc.green(usedKeys.size)} unique translation keys referenced in code.`\n )\n\n if (config.localesLayout === \"namespaced\") {\n return pruneNamespaced(\n config,\n localesDirAbs,\n usedKeys,\n fileContents,\n dryRun\n )\n }\n return pruneFlat(config, localesDirAbs, usedKeys, fileContents, dryRun)\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "i18n-sharpen",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A type-safe and configuration-driven i18n validator, extractor, and pruner CLI tool.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"i18n-sharpen": "./dist/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"keywords": [
|
|
21
|
+
"i18n",
|
|
22
|
+
"internationalization",
|
|
23
|
+
"validator",
|
|
24
|
+
"extractor",
|
|
25
|
+
"pruner",
|
|
26
|
+
"cli",
|
|
27
|
+
"translation"
|
|
28
|
+
],
|
|
29
|
+
"author": "",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"commander": "^12.1.0",
|
|
33
|
+
"picocolors": "^1.1.1",
|
|
34
|
+
"yaml": "^2.9.0",
|
|
35
|
+
"zod": "^4.4.3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/js": "^9.39.4",
|
|
39
|
+
"@types/node": "^20.12.7",
|
|
40
|
+
"eslint": "^9.39.4",
|
|
41
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
42
|
+
"eslint-plugin-unused-imports": "^4.4.1",
|
|
43
|
+
"fast-check": "^4.8.0",
|
|
44
|
+
"globals": "^17.6.0",
|
|
45
|
+
"lint-staged": "^17.0.5",
|
|
46
|
+
"prettier": "3.7.4",
|
|
47
|
+
"simple-git-hooks": "^2.13.1",
|
|
48
|
+
"tsup": "^8.0.2",
|
|
49
|
+
"typescript": "^5.9.3",
|
|
50
|
+
"typescript-eslint": "^8.59.3",
|
|
51
|
+
"vite-tsconfig-paths": "^6.1.1",
|
|
52
|
+
"vitest": "^1.5.0"
|
|
53
|
+
},
|
|
54
|
+
"simple-git-hooks": {
|
|
55
|
+
"pre-commit": "pnpm lint-staged"
|
|
56
|
+
},
|
|
57
|
+
"lint-staged": {
|
|
58
|
+
"src/**/*.ts": [
|
|
59
|
+
"prettier --write",
|
|
60
|
+
"eslint --fix"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsup",
|
|
65
|
+
"dev": "tsup --watch",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"lint": "eslint src/",
|
|
68
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
69
|
+
"test": "vitest run"
|
|
70
|
+
}
|
|
71
|
+
}
|