{"version":3,"file":"i18n-extract.es.mjs","names":[],"sources":["../src/i18n/extract/extract.ts","../src/i18n/extract/merge.ts","../src/i18n/extract/cli.ts"],"sourcesContent":["/**\n * Source scanning for translatable messages.\n *\n * Dependency-free, best-effort extraction: it recognises two anchors without\n * needing a full JavaScript parser —\n *\n * 1. `defineMessages({ ... })` catalog literals — keys **and** their default\n *    message strings are extracted.\n * 2. `t('key')` / `tc('key')` / `i18n.t('key')` translation calls — the key is\n *    extracted with an empty default (a string awaiting translation).\n *\n * The scanner is intentionally conservative: anything it cannot understand as a\n * string or nested object is skipped rather than guessed at.\n *\n * @module bquery/i18n\n */\n\n/** A nested catalog of message strings. */\nexport type ExtractedCatalog = { [key: string]: string | ExtractedCatalog };\n\n/** A single extracted message, keyed by its dot-delimited path. */\nexport type ExtractedMessage = { key: string; value: string };\n\nconst isIdentChar = (ch: string): boolean => /[A-Za-z0-9_$]/.test(ch);\n\n/** Advances past whitespace and `//` / block comments. */\nconst skipTrivia = (src: string, start: number): number => {\n  let i = start;\n  while (i < src.length) {\n    const ch = src[i];\n    if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n      i += 1;\n      continue;\n    }\n    if (ch === '/' && src[i + 1] === '/') {\n      i += 2;\n      while (i < src.length && src[i] !== '\\n') i += 1;\n      continue;\n    }\n    if (ch === '/' && src[i + 1] === '*') {\n      i += 2;\n      while (i < src.length && !(src[i] === '*' && src[i + 1] === '/')) i += 1;\n      i += 2;\n      continue;\n    }\n    break;\n  }\n  return i;\n};\n\nconst readIdent = (src: string, start: number): { value: string; end: number } => {\n  let i = start;\n  let value = '';\n  while (i < src.length && isIdentChar(src[i])) {\n    value += src[i];\n    i += 1;\n  }\n  return { value, end: i };\n};\n\nconst UNESCAPE: Record<string, string> = { n: '\\n', t: '\\t', r: '\\r', '\\\\': '\\\\', '`': '`' };\n\n/** Reads a quoted string literal (`'`, `\"`, or `` ` ``) and unescapes it. */\nconst readString = (src: string, start: number): { value: string; end: number } => {\n  const quote = src[start];\n  let i = start + 1;\n  let value = '';\n  while (i < src.length) {\n    const ch = src[i];\n    if (ch === '\\\\') {\n      const next = src[i + 1];\n      value += UNESCAPE[next] ?? next;\n      i += 2;\n      continue;\n    }\n    if (ch === quote) {\n      i += 1;\n      break;\n    }\n    value += ch;\n    i += 1;\n  }\n  return { value, end: i };\n};\n\n/** Skips a value that is neither a string nor an object, up to the enclosing `,`/`}`. */\nconst skipValue = (src: string, start: number): number => {\n  let i = start;\n  let depth = 0;\n  while (i < src.length) {\n    const ch = src[i];\n    if (ch === '\"' || ch === \"'\" || ch === '`') {\n      i = readString(src, i).end;\n      continue;\n    }\n    if (ch === '(' || ch === '[' || ch === '{') depth += 1;\n    else if (ch === ')' || ch === ']' || ch === '}') {\n      if (depth === 0) break;\n      depth -= 1;\n    } else if (ch === ',' && depth === 0) break;\n    i += 1;\n  }\n  return i;\n};\n\n/** Parses an object literal beginning at `{`. */\nconst parseObjectLiteral = (\n  src: string,\n  start: number\n): { value: ExtractedCatalog; end: number } => {\n  const obj: ExtractedCatalog = {};\n  let i = start + 1;\n\n  while (i < src.length) {\n    i = skipTrivia(src, i);\n    if (src[i] === '}') {\n      i += 1;\n      break;\n    }\n    if (src[i] === ',') {\n      i += 1;\n      continue;\n    }\n\n    // Key — identifier or quoted string.\n    let key: string;\n    if (src[i] === '\"' || src[i] === \"'\" || src[i] === '`') {\n      const r = readString(src, i);\n      key = r.value;\n      i = r.end;\n    } else {\n      const r = readIdent(src, i);\n      if (!r.value) {\n        i += 1;\n        continue;\n      }\n      key = r.value;\n      i = r.end;\n    }\n\n    i = skipTrivia(src, i);\n    if (src[i] !== ':') continue; // not a key:value pair (e.g. shorthand) — skip\n    i = skipTrivia(src, i + 1);\n\n    if (src[i] === '{') {\n      const r = parseObjectLiteral(src, i);\n      obj[key] = r.value;\n      i = r.end;\n    } else if (src[i] === '\"' || src[i] === \"'\" || src[i] === '`') {\n      const r = readString(src, i);\n      obj[key] = r.value;\n      i = r.end;\n    } else {\n      i = skipValue(src, i);\n    }\n  }\n\n  return { value: obj, end: i };\n};\n\n/** Flattens a nested catalog into dot-delimited `key → value` entries. */\nexport const flatten = (catalog: ExtractedCatalog, prefix = ''): ExtractedMessage[] => {\n  const out: ExtractedMessage[] = [];\n  for (const [key, value] of Object.entries(catalog)) {\n    const path = prefix ? `${prefix}.${key}` : key;\n    if (typeof value === 'string') out.push({ key: path, value });\n    else out.push(...flatten(value, path));\n  }\n  return out;\n};\n\n/**\n * Reconstructs a nested catalog from sorted dot-delimited entries.\n *\n * Keys are scanned from untrusted source files, so a `__proto__`, `constructor`\n * or `prototype` segment is rejected inline — right where each computed-property\n * assignment happens — to stop a malicious key from walking into or overwriting\n * the prototype chain.\n */\nexport const unflatten = (messages: ExtractedMessage[]): ExtractedCatalog => {\n  const root: ExtractedCatalog = {};\n  for (const { key, value } of [...messages].sort((a, b) => a.key.localeCompare(b.key))) {\n    const parts = key.split('.');\n    let node = root;\n    let unsafe = false;\n    for (let p = 0; p < parts.length - 1; p += 1) {\n      const part = parts[p];\n      if (part === '__proto__' || part === 'constructor' || part === 'prototype') {\n        unsafe = true;\n        break;\n      }\n      const child = node[part];\n      if (typeof child === 'object' && child !== null) {\n        node = child as ExtractedCatalog;\n      } else {\n        const created: ExtractedCatalog = {};\n        node[part] = created;\n        node = created;\n      }\n    }\n    if (unsafe) continue;\n    const leaf = parts[parts.length - 1];\n    if (leaf === '__proto__' || leaf === 'constructor' || leaf === 'prototype') continue;\n    node[leaf] = value;\n  }\n  return root;\n};\n\nconst DEFINE_RE = /\\bdefineMessages\\s*\\(/g;\n// `t('key')`, `tc('key')`, `i18n.t('key')` — first arg is a string literal.\n// A `.` may precede the call (instance method), but a preceding word char\n// must not (so `format(`, `connect(` etc. never match).\nconst CALL_RE = /(?:^|[^\\w$])(t|tc)\\s*\\(\\s*(['\"`])((?:\\\\.|(?!\\2).)*)\\2/g;\n\n/**\n * Removes `//` and block comments while preserving string and template\n * literals, so call/catalog scanning never trips on commented-out code.\n */\nconst stripComments = (src: string): string => {\n  let out = '';\n  let i = 0;\n  while (i < src.length) {\n    const ch = src[i];\n    if (ch === '\"' || ch === \"'\" || ch === '`') {\n      const start = i;\n      i += 1;\n      while (i < src.length) {\n        if (src[i] === '\\\\') {\n          i += 2;\n          continue;\n        }\n        if (src[i] === ch) {\n          i += 1;\n          break;\n        }\n        i += 1;\n      }\n      out += src.slice(start, i);\n      continue;\n    }\n    if (ch === '/' && src[i + 1] === '/') {\n      i += 2;\n      while (i < src.length && src[i] !== '\\n') i += 1;\n      continue;\n    }\n    if (ch === '/' && src[i + 1] === '*') {\n      i += 2;\n      while (i < src.length && !(src[i] === '*' && src[i + 1] === '/')) i += 1;\n      i += 2;\n      continue;\n    }\n    out += ch;\n    i += 1;\n  }\n  return out;\n};\n\n/**\n * Extracts every translatable message from a single source string.\n *\n * `defineMessages` catalogs contribute their keys **and** default values;\n * `t()` / `tc()` calls contribute keys with an empty default. Duplicate keys\n * keep the first non-empty value seen.\n *\n * @param source - File contents to scan\n * @returns Flat, de-duplicated extracted messages\n */\nexport const extractFromSource = (rawSource: string): ExtractedMessage[] => {\n  const source = stripComments(rawSource);\n  const found = new Map<string, string>();\n  const add = (key: string, value: string): void => {\n    const existing = found.get(key);\n    if (existing === undefined || (existing === '' && value !== '')) found.set(key, value);\n  };\n\n  // defineMessages({ ... }) catalogs.\n  DEFINE_RE.lastIndex = 0;\n  let match: RegExpExecArray | null;\n  while ((match = DEFINE_RE.exec(source)) !== null) {\n    const braceStart = skipTrivia(source, match.index + match[0].length);\n    if (source[braceStart] !== '{') continue;\n    const { value } = parseObjectLiteral(source, braceStart);\n    for (const entry of flatten(value)) add(entry.key, entry.value);\n  }\n\n  // t('key') / tc('key') calls.\n  CALL_RE.lastIndex = 0;\n  while ((match = CALL_RE.exec(source)) !== null) {\n    add(match[3], '');\n  }\n\n  return [...found.entries()].map(([key, value]) => ({ key, value }));\n};\n","/**\n * Catalog merging for message extraction.\n * @module bquery/i18n\n */\n\nimport { flatten, unflatten, type ExtractedCatalog, type ExtractedMessage } from './extract';\n\n/** Outcome of merging freshly extracted messages into an existing catalog. */\nexport type MergeResult = {\n  /** The merged, nested catalog. */\n  catalog: ExtractedCatalog;\n  /** Keys newly introduced by this extraction run. */\n  added: string[];\n  /** Keys present before but no longer found in source (only when `prune`). */\n  removed: string[];\n  /** Count of existing translations preserved untouched. */\n  kept: number;\n};\n\n/** Options for {@link mergeCatalog}. */\nexport type MergeOptions = {\n  /**\n   * Drop keys that exist in `existing` but are no longer found in source.\n   * Default `false` — stale keys are preserved so translations are never lost\n   * by accident. Pass `true` for a strict prune.\n   */\n  prune?: boolean;\n};\n\n/**\n * Merges extracted messages into an existing catalog without clobbering\n * already-translated values.\n *\n * - **New keys** are added with their extracted default (the `defineMessages`\n *   source string, or `''` for keys seen only in `t()` calls).\n * - **Existing keys** keep their current value — translations are never\n *   overwritten.\n * - **Stale keys** are preserved unless `prune` is set.\n *\n * @param existing - The current catalog (e.g. parsed from `locales/en.json`)\n * @param extracted - Flat messages from {@link extractFromSource}\n * @param options - Merge behaviour\n * @returns The merged catalog plus a diff summary\n */\nexport const mergeCatalog = (\n  existing: ExtractedCatalog,\n  extracted: ExtractedMessage[],\n  options: MergeOptions = {}\n): MergeResult => {\n  const existingFlat = new Map(flatten(existing).map((e) => [e.key, e.value]));\n  const extractedKeys = new Set(extracted.map((e) => e.key));\n\n  const out: ExtractedMessage[] = [];\n  const added: string[] = [];\n  const removed: string[] = [];\n  let kept = 0;\n\n  for (const { key, value } of extracted) {\n    const prior = existingFlat.get(key);\n    if (prior !== undefined) {\n      out.push({ key, value: prior });\n      kept += 1;\n    } else {\n      added.push(key);\n      out.push({ key, value });\n    }\n  }\n\n  for (const [key, value] of existingFlat) {\n    if (extractedKeys.has(key)) continue;\n    if (options.prune) removed.push(key);\n    else out.push({ key, value });\n  }\n\n  return {\n    catalog: unflatten(out),\n    added: added.sort(),\n    removed: removed.sort(),\n    kept,\n  };\n};\n","/**\n * Build-tool-agnostic CLI for message extraction.\n *\n * Thin glue around {@link extractFromSource} and {@link mergeCatalog}: it reads\n * source files, extracts translatable messages, merges them into an existing\n * catalog (preserving translations), and writes JSON. It is dependency-free and\n * meant to be wired into an existing build or run ad-hoc — not to become a build\n * tool of its own.\n *\n * Node's `fs`/`path` are imported lazily so the extract barrel stays\n * environment-neutral; only the CLI functions touch the filesystem.\n *\n * @module bquery/i18n\n */\n\nimport { extractFromSource, type ExtractedCatalog, type ExtractedMessage } from './extract';\nimport { mergeCatalog, type MergeResult } from './merge';\n\n/** Minimal console-shaped sink so the CLI is testable without globals. */\nexport type CliIO = { log: (msg: string) => void; error: (msg: string) => void };\n\n/**\n * Converts a `*` / `**` / `?` glob into a `RegExp`. `**` matches across\n * directory separators; `*` and `?` do not.\n */\nconst globToRegExp = (glob: string): RegExp => {\n  let re = '';\n  for (let i = 0; i < glob.length; i += 1) {\n    const ch = glob[i];\n    if (ch === '*') {\n      if (glob[i + 1] === '*') {\n        re += '.*';\n        i += 1;\n        if (glob[i + 1] === '/') i += 1;\n      } else {\n        re += '[^/]*';\n      }\n    } else if (ch === '?') re += '[^/]';\n    else re += ch.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n  }\n  return new RegExp(`^${re}$`);\n};\n\n/** The non-glob prefix of a pattern, used as the directory walk root. */\nconst globBase = (glob: string): string => {\n  const firstMagic = glob.search(/[*?]/);\n  const head = firstMagic === -1 ? glob : glob.slice(0, firstMagic);\n  const slash = head.lastIndexOf('/');\n  return slash === -1 ? '.' : head.slice(0, slash) || '.';\n};\n\n/**\n * Expands glob patterns to a sorted, de-duplicated list of files. Plain paths\n * (already expanded by the shell, or with no magic characters) pass through.\n */\nexport const expandGlobs = async (patterns: string[]): Promise<string[]> => {\n  const { readdir, stat, realpath } = await import('node:fs/promises');\n  const path = await import('node:path');\n  const found = new Set<string>();\n  // Canonical directory paths already walked, so a symlink cycle (e.g. a link\n  // pointing at an ancestor) cannot drive `walk` into infinite recursion.\n  const visited = new Set<string>();\n\n  const walk = async (dir: string, matcher: RegExp): Promise<void> => {\n    let canonical: string;\n    try {\n      canonical = await realpath(dir);\n    } catch {\n      return;\n    }\n    if (visited.has(canonical)) return;\n    visited.add(canonical);\n\n    let entries: string[];\n    try {\n      entries = await readdir(dir);\n    } catch {\n      return;\n    }\n    for (const entry of entries) {\n      const full = path.join(dir, entry).split(path.sep).join('/');\n      let isDir = false;\n      try {\n        isDir = (await stat(full)).isDirectory();\n      } catch {\n        continue;\n      }\n      if (isDir) await walk(full, matcher);\n      else if (matcher.test(full)) found.add(full);\n    }\n  };\n\n  for (const pattern of patterns) {\n    const normalized = pattern.split(path.sep).join('/');\n    if (!/[*?]/.test(normalized)) {\n      found.add(normalized);\n      continue;\n    }\n    const base = globBase(normalized);\n    const matcher = globToRegExp(normalized.replace(/^\\.\\//, ''));\n    await walk(base, matcher);\n  }\n\n  return [...found].sort();\n};\n\n/** Options controlling an extraction run. */\nexport type ExtractRunOptions = {\n  /** Output catalog path. When omitted, the catalog is returned, not written. */\n  out?: string;\n  /** Drop keys no longer present in source (default: keep them). */\n  prune?: boolean;\n};\n\n/** Result of {@link extractFiles}. */\nexport type ExtractFilesResult = MergeResult & {\n  /** Number of source files scanned. */\n  files: number;\n  /** Number of distinct keys extracted from the scanned sources (added + kept). */\n  total: number;\n};\n\nconst readJsonCatalog = async (file: string): Promise<ExtractedCatalog> => {\n  const { readFile } = await import('node:fs/promises');\n  try {\n    const text = await readFile(file, 'utf8');\n    return JSON.parse(text) as ExtractedCatalog;\n  } catch {\n    return {};\n  }\n};\n\n/**\n * Extracts messages from `files`, merges into the catalog at `options.out`\n * (when given), and writes the result.\n *\n * @example\n * ```ts\n * import { extractFiles } from '@bquery/bquery/i18n/extract';\n *\n * await extractFiles(['src/cart.ts'], { out: 'locales/en.json' });\n * ```\n */\nexport const extractFiles = async (\n  files: string[],\n  options: ExtractRunOptions = {}\n): Promise<ExtractFilesResult> => {\n  const { readFile, writeFile, mkdir } = await import('node:fs/promises');\n  const path = await import('node:path');\n\n  const messages = new Map<string, string>();\n  for (const file of files) {\n    const source = await readFile(file, 'utf8');\n    for (const { key, value } of extractFromSource(source)) {\n      const prior = messages.get(key);\n      if (prior === undefined || (prior === '' && value !== '')) messages.set(key, value);\n    }\n  }\n\n  const extracted: ExtractedMessage[] = [...messages.entries()].map(([key, value]) => ({\n    key,\n    value,\n  }));\n\n  const existing = options.out ? await readJsonCatalog(options.out) : {};\n  const merged = mergeCatalog(existing, extracted, { prune: options.prune });\n\n  if (options.out) {\n    await mkdir(path.dirname(options.out), { recursive: true });\n    await writeFile(options.out, `${JSON.stringify(merged.catalog, null, 2)}\\n`, 'utf8');\n  }\n\n  return { ...merged, files: files.length, total: extracted.length };\n};\n\nconst USAGE = `Usage: bquery-i18n extract [options] <glob...>\n  --out <file>   merge into and write this catalog (JSON)\n  --prune        drop keys no longer present in source\n  -h, --help     show this help`;\n\n/**\n * Parses argv and runs an extraction. Returns a process exit code\n * (`0` success, `1` usage error / failure).\n *\n * Usage: `bquery-i18n extract [options] <glob...>`\n */\nexport const runExtractCli = async (\n  argv: string[],\n  io: CliIO = { log: (m) => console.log(m), error: (m) => console.error(m) }\n): Promise<number> => {\n  const args = argv[0] === 'extract' ? argv.slice(1) : argv;\n  const patterns: string[] = [];\n  const options: ExtractRunOptions = {};\n\n  for (let i = 0; i < args.length; i += 1) {\n    const arg = args[i];\n    switch (arg) {\n      case '--out':\n        options.out = args[++i];\n        break;\n      case '--prune':\n        options.prune = true;\n        break;\n      case '-h':\n      case '--help':\n        io.log(USAGE);\n        return 0;\n      default:\n        if (arg.startsWith('-')) {\n          io.error(`Unknown option: ${arg}`);\n          return 1;\n        }\n        patterns.push(arg);\n    }\n  }\n\n  if (patterns.length === 0) {\n    io.error(`No input patterns.\\n${USAGE}`);\n    return 1;\n  }\n\n  try {\n    const files = await expandGlobs(patterns);\n    if (files.length === 0) {\n      io.error('No files matched the given patterns.');\n      return 1;\n    }\n    const result = await extractFiles(files, options);\n    const target = options.out ?? '(stdout — pass --out to write)';\n    io.log(\n      `Scanned ${result.files} file(s) → ${result.total} key(s): ` +\n        `${result.added.length} new, ${result.kept} kept` +\n        (options.prune ? `, ${result.removed.length} pruned` : '')\n    );\n    if (!options.out) io.log(JSON.stringify(result.catalog, null, 2));\n    else io.log(`Wrote ${target}`);\n    return 0;\n  } catch (error) {\n    io.error(`i18n extract failed: ${error instanceof Error ? error.message : String(error)}`);\n    return 1;\n  }\n};\n"],"mappings":"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"}