@fluenti/cli 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +9 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +290 -251
- package/dist/cli.js.map +1 -1
- package/dist/compile-CX1b_JVQ.cjs +8 -0
- package/dist/compile-CX1b_JVQ.cjs.map +1 -0
- package/dist/{compile-B4y2UPsX.js → compile-CXReVuTG.js} +35 -32
- package/dist/compile-CXReVuTG.js.map +1 -0
- package/dist/compile-cache.d.ts.map +1 -1
- package/dist/compile-worker.cjs +1 -1
- package/dist/compile-worker.cjs.map +1 -1
- package/dist/compile-worker.d.ts +1 -0
- package/dist/compile-worker.d.ts.map +1 -1
- package/dist/compile-worker.js +19 -7
- package/dist/compile-worker.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/{extract-cache-DYoHe5P-.js → extract-cache-BTxWgic2.js} +57 -44
- package/dist/extract-cache-BTxWgic2.js.map +1 -0
- package/dist/{extract-cache-idNfsd7n.cjs → extract-cache-CGSKwh76.cjs} +5 -5
- package/dist/extract-cache-CGSKwh76.cjs.map +1 -0
- package/dist/extract-cache.d.ts.map +1 -1
- package/dist/extract-runner.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/parallel-compile.d.ts.map +1 -1
- package/dist/po-format.d.ts.map +1 -1
- package/dist/translate.d.ts +2 -1
- package/dist/translate.d.ts.map +1 -1
- package/dist/{tsx-extractor-C-9_TnCW.cjs → tsx-extractor-BOD7JJQK.cjs} +2 -2
- package/dist/tsx-extractor-BOD7JJQK.cjs.map +1 -0
- package/dist/{tsx-extractor-CjQIMvKo.js → tsx-extractor-C-HZNobu.js} +2 -2
- package/dist/tsx-extractor-C-HZNobu.js.map +1 -0
- package/dist/tsx-extractor.d.ts.map +1 -1
- package/dist/validation.d.ts +4 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/vue-extractor.cjs +2 -2
- package/dist/vue-extractor.cjs.map +1 -1
- package/dist/vue-extractor.d.ts.map +1 -1
- package/dist/vue-extractor.js +3 -3
- package/dist/vue-extractor.js.map +1 -1
- package/package.json +2 -2
- package/dist/compile-B4y2UPsX.js.map +0 -1
- package/dist/compile-Brygn0bn.cjs +0 -8
- package/dist/compile-Brygn0bn.cjs.map +0 -1
- package/dist/extract-cache-DYoHe5P-.js.map +0 -1
- package/dist/extract-cache-idNfsd7n.cjs.map +0 -1
- package/dist/tsx-extractor-C-9_TnCW.cjs.map +0 -1
- package/dist/tsx-extractor-CjQIMvKo.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-cache-CGSKwh76.cjs","names":[],"sources":["../src/catalog.ts","../src/json-format.ts","../src/po-format.ts","../src/parallel-compile.ts","../src/extract-cache.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\n\nexport interface CatalogEntry {\n message?: string | undefined\n context?: string | undefined\n comment?: string | undefined\n translation?: string | undefined\n origin?: string | string[] | undefined\n obsolete?: boolean | undefined\n fuzzy?: boolean | undefined\n}\n\nexport type CatalogData = Record<string, CatalogEntry>\n\nexport interface UpdateResult {\n added: number\n unchanged: number\n obsolete: number\n}\n\nexport interface UpdateCatalogOptions {\n stripFuzzy?: boolean\n}\n\n/** Update catalog with newly extracted messages */\nexport function updateCatalog(\n existing: CatalogData,\n extracted: ExtractedMessage[],\n options?: UpdateCatalogOptions,\n): { catalog: CatalogData; result: UpdateResult } {\n const extractedIds = new Set(extracted.map((m) => m.id))\n const consumedCarryForwardIds = new Set<string>()\n const catalog: CatalogData = {}\n let added = 0\n let unchanged = 0\n let obsolete = 0\n\n for (const msg of extracted) {\n const existingEntry = existing[msg.id]\n const carried = existingEntry\n ? undefined\n : findCarryForwardEntry(existing, msg, consumedCarryForwardIds)\n const origin = `${msg.origin.file}:${msg.origin.line}`\n const baseEntry = existingEntry ?? carried?.entry\n\n if (carried) {\n consumedCarryForwardIds.add(carried.id)\n }\n\n if (baseEntry) {\n catalog[msg.id] = {\n ...baseEntry,\n message: msg.message ?? baseEntry.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n obsolete: false,\n }\n unchanged++\n } else if (catalog[msg.id]) {\n // Same ID already seen in this extraction batch — merge origin\n const existing = catalog[msg.id]!\n catalog[msg.id] = {\n ...existing,\n origin: mergeOrigins(existing.origin, origin),\n }\n } else {\n catalog[msg.id] = {\n message: msg.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n }\n added++\n }\n\n if (options?.stripFuzzy) {\n const { fuzzy: _fuzzy, ...rest } = catalog[msg.id]!\n catalog[msg.id] = rest\n }\n }\n\n for (const [id, entry] of Object.entries(existing)) {\n if (!extractedIds.has(id)) {\n const { fuzzy: _fuzzy, ...rest } = entry\n const obsoleteEntry = options?.stripFuzzy\n ? { ...rest, obsolete: true }\n : { ...entry, obsolete: true }\n catalog[id] = obsoleteEntry\n obsolete++\n }\n }\n\n return { catalog, result: { added, unchanged, obsolete } }\n}\n\nfunction mergeOrigins(\n existing: string | string[] | undefined,\n newOrigin: string,\n): string | string[] {\n if (!existing) return newOrigin\n const existingArray = Array.isArray(existing) ? existing : [existing]\n const merged = [...new Set([...existingArray, newOrigin])]\n return merged.length === 1 ? merged[0]! : merged\n}\n\nfunction findCarryForwardEntry(\n existing: CatalogData,\n extracted: ExtractedMessage,\n consumedCarryForwardIds: Set<string>,\n): { id: string; entry: CatalogEntry } | undefined {\n if (!extracted.context) {\n return undefined\n }\n\n const extractedOrigin = `${extracted.origin.file}:${extracted.origin.line}`\n for (const [id, entry] of Object.entries(existing)) {\n if (consumedCarryForwardIds.has(id)) continue\n if (entry.context !== undefined) continue\n if (entry.message !== extracted.message) continue\n if (!sameOrigin(entry.origin, extractedOrigin)) continue\n return { id, entry }\n }\n\n return undefined\n}\n\nfunction sameOrigin(previous: string | string[] | undefined, next: string): boolean {\n if (!previous) return false\n const origins = Array.isArray(previous) ? previous : [previous]\n return origins.some((o) => o === next || originFile(o) === originFile(next))\n}\n\nfunction originFile(origin: string): string {\n const match = origin.match(/^(.*):\\d+$/)\n return match?.[1] ?? origin\n}\n","import type { CatalogData } from './catalog'\n\n/** Read a JSON catalog file */\nexport function readJsonCatalog(content: string): CatalogData {\n const raw = JSON.parse(content) as Record<string, unknown>\n const catalog: CatalogData = {}\n\n for (const [id, entry] of Object.entries(raw)) {\n if (typeof entry === 'object' && entry !== null) {\n const e = entry as Record<string, unknown>\n catalog[id] = {\n message: typeof e['message'] === 'string' ? e['message'] : undefined,\n context: typeof e['context'] === 'string' ? e['context'] : undefined,\n comment: typeof e['comment'] === 'string' ? e['comment'] : undefined,\n translation: typeof e['translation'] === 'string' ? e['translation'] : undefined,\n origin: typeof e['origin'] === 'string'\n ? e['origin']\n : Array.isArray(e['origin']) && (e['origin'] as unknown[]).every((v) => typeof v === 'string')\n ? (e['origin'] as string[])\n : undefined,\n obsolete: typeof e['obsolete'] === 'boolean' ? e['obsolete'] : undefined,\n fuzzy: typeof e['fuzzy'] === 'boolean' ? e['fuzzy'] : undefined,\n }\n }\n }\n\n return catalog\n}\n\n/** Write a catalog to JSON format */\nexport function writeJsonCatalog(catalog: CatalogData): string {\n const output: Record<string, Record<string, unknown>> = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n const obj: Record<string, unknown> = {}\n if (entry.message !== undefined) obj['message'] = entry.message\n if (entry.context !== undefined) obj['context'] = entry.context\n if (entry.comment !== undefined) obj['comment'] = entry.comment\n if (entry.translation !== undefined) obj['translation'] = entry.translation\n if (entry.origin !== undefined) obj['origin'] = entry.origin\n if (entry.obsolete) obj['obsolete'] = true\n if (entry.fuzzy) obj['fuzzy'] = true\n output[id] = obj\n }\n\n return JSON.stringify(output, null, 2) + '\\n'\n}\n","import type { CatalogData } from './catalog'\nimport { hashMessage } from '@fluenti/core/internal'\nimport * as gettextParser from 'gettext-parser'\n\nconst CUSTOM_ID_MARKER = 'fluenti-id:'\n\ninterface POTranslation {\n msgid: string\n msgctxt?: string\n msgstr: string[]\n comments?: {\n reference?: string\n extracted?: string\n flag?: string\n translator?: string\n previous?: string\n }\n}\n\ninterface POData {\n headers?: Record<string, string>\n translations: Record<string, Record<string, POTranslation>>\n obsolete?: Record<string, Record<string, POTranslation>>\n}\n\ninterface ParsedExtractedComment {\n comment?: string\n customId?: string\n sourceMessage?: string\n}\n\nfunction processPoEntries(\n contextMap: Record<string, Record<string, POTranslation>>,\n catalog: CatalogData,\n isObsolete: boolean,\n): void {\n for (const [contextKey, entries] of Object.entries(contextMap)) {\n for (const [msgid, entry] of Object.entries(entries)) {\n if (!msgid) continue\n\n const context = contextKey || entry.msgctxt || undefined\n const translation = entry.msgstr?.[0] ?? undefined\n const rawReference = entry.comments?.reference ?? undefined\n const origin = rawReference?.includes('\\n')\n ? rawReference.split('\\n').map((r: string) => r.trim()).filter(Boolean)\n : rawReference?.includes(' ')\n ? rawReference.split(/\\s+/).filter(Boolean)\n : rawReference\n const normalizedOrigin = Array.isArray(origin) && origin.length === 1 ? origin[0] : origin\n const isFuzzy = !isObsolete && (entry.comments?.flag?.includes('fuzzy') ?? false)\n const { comment, customId, sourceMessage } = parseExtractedComment(entry.comments?.extracted)\n // When a custom ID is present, the msgid may be the custom key (not source text),\n // so accept sourceMessage directly without requiring a hash match.\n // For hash-ID entries (no customId), verify the hash to prevent double-hashing.\n const resolvedSourceMessage = sourceMessage\n && (customId !== undefined || hashMessage(sourceMessage, context) === msgid)\n ? sourceMessage\n : undefined\n const id = customId\n ?? (resolvedSourceMessage ? msgid : hashMessage(msgid, context))\n\n catalog[id] = {\n message: resolvedSourceMessage ?? msgid,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n ...(translation ? { translation } : {}),\n ...(normalizedOrigin !== undefined ? { origin: normalizedOrigin } : {}),\n ...(isFuzzy ? { fuzzy: true } : {}),\n ...(isObsolete ? { obsolete: true } : {}),\n }\n }\n }\n}\n\n/** Read a PO catalog file */\nexport function readPoCatalog(content: string): CatalogData {\n const po = gettextParser.po.parse(content) as POData\n const catalog: CatalogData = {}\n\n processPoEntries(po.translations ?? {}, catalog, false)\n if (po.obsolete) {\n processPoEntries(po.obsolete, catalog, true)\n }\n\n return catalog\n}\n\n/** Write a catalog to PO format */\nexport function writePoCatalog(catalog: CatalogData): string {\n const translations: POData['translations'] = {\n '': {\n '': {\n msgid: '',\n msgstr: ['Content-Type: text/plain; charset=UTF-8\\n'],\n },\n },\n }\n const obsolete: POData['obsolete'] = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n // Use custom ID as msgid for non-hash entries to prevent collision when two\n // entries share the same source message but have different custom IDs.\n // Hash-ID entries keep source message as msgid (PO-friendly for translators).\n const isHashId = entry.message !== undefined && hashMessage(entry.message, entry.context) === id\n const msgid = isHashId ? (entry.message ?? id) : id\n const poEntry: POTranslation = {\n msgid,\n ...(entry.context !== undefined ? { msgctxt: entry.context } : {}),\n msgstr: [entry.translation ?? ''],\n }\n\n const comments: POTranslation['comments'] = {}\n if (entry.origin && !entry.obsolete) {\n comments.reference = Array.isArray(entry.origin)\n ? entry.origin.join('\\n')\n : entry.origin\n }\n const extractedComment = buildExtractedComment(id, entry.message ?? id, entry.context, entry.comment)\n if (extractedComment) {\n comments.extracted = extractedComment\n }\n if (entry.fuzzy && !entry.obsolete) {\n comments.flag = 'fuzzy'\n }\n if (comments.reference || comments.extracted || comments.flag) {\n poEntry.comments = comments\n }\n\n if (entry.obsolete) {\n const contextKey = entry.context ?? ''\n obsolete[contextKey] ??= {}\n obsolete[contextKey]![poEntry.msgid] = poEntry\n } else {\n const contextKey = entry.context ?? ''\n translations[contextKey] ??= {}\n translations[contextKey]![poEntry.msgid] = poEntry\n }\n }\n\n const poData: POData = {\n headers: {\n 'Content-Type': 'text/plain; charset=UTF-8',\n },\n translations,\n ...(Object.keys(obsolete).length > 0 ? { obsolete } : {}),\n }\n\n const buffer = gettextParser.po.compile(poData as Parameters<typeof gettextParser.po.compile>[0])\n return buffer.toString()\n}\n\nfunction parseExtractedComment(\n extracted: string | undefined,\n): ParsedExtractedComment {\n if (!extracted) {\n return {}\n }\n\n const lines = extracted.split('\\n').map((line) => line.trim()).filter(Boolean)\n let customId: string | undefined\n let sourceMessage: string | undefined\n const commentLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith(CUSTOM_ID_MARKER)) {\n customId = line.slice(CUSTOM_ID_MARKER.length).trim() || undefined\n continue\n }\n if (line.startsWith('msg`') && line.endsWith('`')) {\n sourceMessage = line.slice(4, -1)\n continue\n }\n if (line.startsWith('Trans: ')) {\n sourceMessage = normalizeRichTextComment(line.slice('Trans: '.length))\n continue\n }\n commentLines.push(line)\n }\n\n return {\n ...(commentLines.length > 0 ? { comment: commentLines.join('\\n') } : {}),\n ...(customId ? { customId } : {}),\n ...(sourceMessage ? { sourceMessage } : {}),\n }\n}\n\nfunction normalizeRichTextComment(comment: string): string {\n let stack: Array<{ tag: string; index: number }> = []\n let nextIndex = 0\n\n return comment.replace(/<\\/?([a-zA-Z][\\w-]*)>/g, (match, rawTag: string) => {\n const tag = rawTag\n if (match.startsWith('</')) {\n for (let index = stack.length - 1; index >= 0; index--) {\n const entry = stack[index]\n if (entry?.tag !== tag) continue\n stack = stack.filter((_, i) => i !== index)\n return `</${entry.index}>`\n }\n return match\n }\n\n const index = nextIndex++\n stack.push({ tag, index })\n return `<${index}>`\n })\n}\n\nfunction buildExtractedComment(\n id: string,\n message: string,\n context: string | undefined,\n comment: string | undefined,\n): string | undefined {\n const lines: string[] = []\n\n if (comment) {\n lines.push(comment)\n }\n\n if (id !== hashMessage(message, context)) {\n lines.push(`${CUSTOM_ID_MARKER} ${id}`)\n // Preserve source message so round-trip works when msgid is the custom ID (not source text)\n lines.push(`msg\\`${message}\\``)\n }\n\n return lines.length > 0 ? lines.join('\\n') : undefined\n}\n","import { Worker } from 'node:worker_threads'\nimport { availableParallelism } from 'node:os'\nimport { existsSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { CatalogData } from './catalog'\nimport type { CompileOptions, CompileStats } from './compile'\nimport type { CompileWorkerRequest, CompileWorkerResponse } from './compile-worker'\n\nexport interface ParallelCompileTask {\n locale: string\n catalog: CatalogData\n allIds: string[]\n sourceLocale: string\n options?: CompileOptions\n}\n\nexport interface ParallelCompileResult {\n locale: string\n code: string\n stats: CompileStats\n}\n\n/** Default timeout per worker in milliseconds (30 seconds) */\nconst WORKER_TIMEOUT_MS = 30_000\n\nfunction getWorkerPath(): string {\n const thisDir = typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url))\n return resolve(thisDir, 'compile-worker.js')\n}\n\n/**\n * Compile multiple locales in parallel using worker threads.\n *\n * - Single task → returns result directly (no worker overhead)\n * - Multiple tasks → spawns min(tasks, availableParallelism()) workers\n * - Workers are created per-call and destroyed after completion\n *\n * Falls back to in-process compilation when the compiled worker is unavailable\n * (e.g. when running from TypeScript source in development/tests).\n */\nexport async function parallelCompile(\n tasks: ParallelCompileTask[],\n concurrency?: number,\n): Promise<ParallelCompileResult[]> {\n if (tasks.length === 0) return []\n\n // Single task: compile in-process, no worker overhead\n if (tasks.length === 1) {\n const { compileCatalog } = await import('./compile')\n const task = tasks[0]!\n const { code, stats } = compileCatalog(task.catalog, task.locale, task.allIds, task.sourceLocale, task.options)\n return [{ locale: task.locale, code, stats }]\n }\n\n const workerPath = getWorkerPath()\n\n // If compiled worker doesn't exist (dev/test), fall back to concurrent in-process compilation\n if (!existsSync(workerPath)) {\n return inProcessParallelCompile(tasks)\n }\n\n const maxWorkers = concurrency ?? Math.min(tasks.length, availableParallelism())\n const results: ParallelCompileResult[] = []\n const queue = [...tasks]\n let rejected = false\n\n return new Promise<ParallelCompileResult[]>((resolveAll, rejectAll) => {\n let activeWorkers = 0\n\n function spawnNext(): void {\n if (rejected) return\n const task = queue.shift()\n if (!task) {\n if (activeWorkers === 0) {\n resolveAll(results)\n }\n return\n }\n\n activeWorkers++\n const worker = new Worker(workerPath)\n\n const timer = setTimeout(() => {\n if (!rejected) {\n rejected = true\n activeWorkers--\n worker.terminate()\n rejectAll(new Error(`Worker timed out after ${WORKER_TIMEOUT_MS}ms compiling locale \"${task.locale}\"`))\n }\n }, WORKER_TIMEOUT_MS)\n\n worker.on('message', (response: CompileWorkerResponse) => {\n clearTimeout(timer)\n if (rejected) return\n if (response.error) {\n rejected = true\n activeWorkers--\n worker.terminate()\n rejectAll(new Error(`Failed to compile locale \"${response.locale}\": ${response.error}`))\n return\n }\n results.push({\n locale: response.locale,\n code: response.code,\n stats: response.stats,\n })\n activeWorkers--\n worker.terminate()\n spawnNext()\n })\n\n worker.on('error', (err: Error) => {\n clearTimeout(timer)\n if (!rejected) {\n rejected = true\n worker.terminate()\n rejectAll(new Error(`Worker error compiling locale \"${task.locale}\": ${err.message}`))\n }\n })\n\n worker.on('exit', (code) => {\n clearTimeout(timer)\n if (code !== 0 && !rejected) {\n rejected = true\n rejectAll(new Error(`Worker exited with code ${code} while compiling locale \"${task.locale}\"`))\n }\n })\n\n const request: CompileWorkerRequest = {\n locale: task.locale,\n catalog: task.catalog,\n allIds: task.allIds,\n sourceLocale: task.sourceLocale,\n options: task.options,\n }\n worker.postMessage(request)\n }\n\n // Start initial batch of workers\n const initialBatch = Math.min(maxWorkers, queue.length)\n for (let i = 0; i < initialBatch; i++) {\n spawnNext()\n }\n })\n}\n\n/**\n * In-process fallback for parallel compilation.\n * Uses Promise.all for concurrency when workers are unavailable.\n */\nasync function inProcessParallelCompile(\n tasks: ParallelCompileTask[],\n): Promise<ParallelCompileResult[]> {\n const { compileCatalog } = await import('./compile')\n return Promise.all(\n tasks.map((task) => {\n const { code, stats } = compileCatalog(task.catalog, task.locale, task.allIds, task.sourceLocale, task.options)\n return { locale: task.locale, code, stats }\n }),\n )\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\n\n/** Cache format version — bump when the structure changes */\nconst CACHE_VERSION = '1'\n\ninterface ExtractCacheEntry {\n mtime: number\n size: number\n messages: ExtractedMessage[]\n}\n\ninterface ExtractCacheData {\n version: string\n entries: Record<string, ExtractCacheEntry>\n}\n\n/**\n * File-level extract cache that skips re-extraction for unchanged files.\n *\n * Cache is keyed by file path, with mtime + size as change detection.\n */\nexport class ExtractCache {\n private data: ExtractCacheData\n private cachePath: string\n private dirty = false\n\n constructor(catalogDir: string, projectId?: string) {\n const cacheDir = projectId\n ? resolve(catalogDir, '.cache', projectId)\n : resolve(catalogDir, '.cache')\n this.cachePath = resolve(cacheDir, 'extract-cache.json')\n this.data = this.load()\n }\n\n /**\n * Check if a file has changed since the last extraction.\n * Returns cached messages if unchanged, undefined if re-extraction needed.\n */\n get(filePath: string): ExtractedMessage[] | undefined {\n const entry = this.data.entries[filePath]\n if (!entry) return undefined\n\n try {\n const stat = statSync(filePath)\n if (stat.mtimeMs === entry.mtime && stat.size === entry.size) {\n return entry.messages\n }\n } catch {\n // File no longer exists or can't be stat'd — cache miss\n }\n\n return undefined\n }\n\n /**\n * Update the cache for a file after extraction.\n */\n set(filePath: string, messages: ExtractedMessage[]): void {\n try {\n const stat = statSync(filePath)\n this.data.entries[filePath] = {\n mtime: stat.mtimeMs,\n size: stat.size,\n messages,\n }\n this.dirty = true\n } catch {\n // File doesn't exist — skip caching\n }\n }\n\n /**\n * Remove entries for files that no longer exist in the file list.\n */\n prune(currentFiles: Set<string>): void {\n for (const filePath of Object.keys(this.data.entries)) {\n if (!currentFiles.has(filePath)) {\n delete this.data.entries[filePath]\n this.dirty = true\n }\n }\n }\n\n /**\n * Write the cache to disk if any changes were made.\n */\n save(): void {\n if (!this.dirty) return\n\n try {\n mkdirSync(dirname(this.cachePath), { recursive: true })\n writeFileSync(this.cachePath, JSON.stringify(this.data), 'utf-8')\n this.dirty = false\n } catch {\n // Cache write failure is non-fatal — next run will re-extract\n }\n }\n\n /** Number of cached entries */\n get size(): number {\n return Object.keys(this.data.entries).length\n }\n\n private load(): ExtractCacheData {\n try {\n if (existsSync(this.cachePath)) {\n const raw = readFileSync(this.cachePath, 'utf-8')\n const parsed = JSON.parse(raw) as ExtractCacheData\n if (parsed.version === CACHE_VERSION) {\n return parsed\n }\n }\n } catch {\n // Corrupt or unreadable cache — start fresh\n }\n\n return { version: CACHE_VERSION, entries: {} }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-cache.d.ts","sourceRoot":"","sources":["../src/extract-cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAgB9D;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAQ;gBAET,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAQlD;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,GAAG,SAAS;IAgBrD;;OAEG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAczD;;OAEG;IACH,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAStC;;OAEG;IACH,IAAI,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"extract-cache.d.ts","sourceRoot":"","sources":["../src/extract-cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAgB9D;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAQ;gBAET,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAQlD;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,GAAG,SAAS;IAgBrD;;OAEG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAczD;;OAEG;IACH,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAStC;;OAEG;IACH,IAAI,IAAI,IAAI;IAYZ,+BAA+B;IAC/B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,IAAI;CAeb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-runner.d.ts","sourceRoot":"","sources":["../src/extract-runner.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;
|
|
1
|
+
{"version":3,"file":"extract-runner.d.ts","sourceRoot":"","sources":["../src/extract-runner.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAgCD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmExF"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./extract-cache-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./extract-cache-CGSKwh76.cjs`),t=require(`./tsx-extractor-BOD7JJQK.cjs`),n=require(`./compile-CX1b_JVQ.cjs`);let r=require(`@fluenti/core/internal`),i=require(`node:fs`),a=require(`node:path`),o=require(`fast-glob`);o=e.l(o);let s=require(`node:crypto`),c=require(`@fluenti/core/config`);function l(e){return e}function u(t,n){if(!(0,i.existsSync)(t))return{};let r=(0,i.readFileSync)(t,`utf-8`);return n===`json`?e.a(r):e.r(r)}function d(e){let t={};for(let[n,r]of Object.entries(e))r.obsolete||(t[n]=r.translation??r.message??n);return t}async function f(t,o){let s=await(0,c.loadConfig)(void 0,t),l=(0,r.resolveLocaleCodes)(s.locales),f=s.format===`json`?`.json`:`.po`,p=(0,a.resolve)(t,s.compileOutDir);(0,i.mkdirSync)(p,{recursive:!0});let m=s.plugins?.length?(0,r.createPluginRunner)(s.plugins):void 0,h={};for(let e of l)h[e]=u((0,a.resolve)(t,s.catalogDir,`${e}${f}`),s.format);let g=n.t(h);for(let e of l)if(m){let t={locale:e,messages:d(h[e]),outDir:p,config:s};await m.runBeforeCompile(t)}if(o?.parallel&&l.length>1){let t=await e.n(l.map(e=>({locale:e,catalog:h[e],allIds:g,sourceLocale:s.sourceLocale})));for(let e of t)(0,i.writeFileSync)((0,a.resolve)(p,`${e.locale}.js`),e.code,`utf-8`)}else for(let e of l){let{code:t}=n.n(h[e],e,g,s.sourceLocale);(0,i.writeFileSync)((0,a.resolve)(p,`${e}.js`),t,`utf-8`)}let _=n.r(l,s.compileOutDir);(0,i.writeFileSync)((0,a.resolve)(p,`index.js`),_,`utf-8`);let v=n.i(g,h,s.sourceLocale);(0,i.writeFileSync)((0,a.resolve)(p,`messages.d.ts`),v,`utf-8`);for(let e of l)if(m){let t={locale:e,messages:d(h[e]),outDir:p,config:s};await m.runAfterCompile(t)}}function p(e){return(0,s.createHash)(`md5`).update(e).digest(`hex`).slice(0,8)}function m(t,n){if(!(0,i.existsSync)(t))return{};let r=(0,i.readFileSync)(t,`utf-8`);return n===`json`?e.a(r):e.r(r)}function h(t,n,r){let o=r===`json`?e.o(n):e.i(n);try{(0,i.mkdirSync)((0,a.dirname)(t),{recursive:!0}),(0,i.writeFileSync)(t,o,`utf-8`)}catch(e){let n=e instanceof Error?e.message:String(e);throw Error(`Failed to write catalog "${t}": ${n}`)}}async function g(e,n){if((0,a.extname)(e)===`.vue`)try{let{extractFromVue:t}=await Promise.resolve().then(()=>require(`./vue-extractor.cjs`));return t(n,e)}catch{return[]}return t.t(n,e)}async function _(t,n){let s=await(0,c.loadConfig)(void 0,t),l=(0,r.resolveLocaleCodes)(s.locales),u=await(0,o.default)(s.include,{cwd:t,ignore:s.exclude??[]}),d=[],f=n?.useCache===!1?null:new e.t((0,a.resolve)(t,s.catalogDir),p(t));for(let e of u){let n=(0,a.resolve)(t,e);if(f){let e=f.get(n);if(e){d.push(...e);continue}}let r=await g(n,(0,i.readFileSync)(n,`utf-8`));d.push(...r),f&&f.set(n,r)}f&&(f.prune(new Set(u.map(e=>(0,a.resolve)(t,e)))),f.save());let _=s.plugins?.length?(0,r.createPluginRunner)(s.plugins):void 0;if(_){let e=new Map;for(let t of d)e.set(t.id,t);let t={messages:e,sourceLocale:s.sourceLocale,targetLocales:l.filter(e=>e!==s.sourceLocale),config:s};await _.runAfterExtract(t)}let v=s.format===`json`?`.json`:`.po`,y=n?.clean??!1,b=n?.stripFuzzy??!1;for(let n of l){let r=(0,a.resolve)(t,s.catalogDir,`${n}${v}`),{catalog:i}=e.s(m(r,s.format),d,{stripFuzzy:b});h(r,y?Object.fromEntries(Object.entries(i).filter(([,e])=>!e.obsolete)):i,s.format)}}exports.collectAllIds=n.t,exports.compileCatalog=n.n,exports.compileIndex=n.r,exports.defineConfig=l,exports.extractFromTsx=t.t,Object.defineProperty(exports,`hashMessage`,{enumerable:!0,get:function(){return r.hashMessage}}),Object.defineProperty(exports,`loadConfig`,{enumerable:!0,get:function(){return c.loadConfig}}),exports.readJsonCatalog=e.a,exports.readPoCatalog=e.r,exports.runCompile=f,exports.runExtract=_,exports.updateCatalog=e.s,exports.writeJsonCatalog=e.o,exports.writePoCatalog=e.i;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n mkdirSync(dirname(filePath), { recursive: true })\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n writeFileSync(filePath, content, 'utf-8')\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n try {\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, content, 'utf-8')\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to write catalog \"${filePath}\": ${message}`)\n }\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as e, n as t, r as n, t as r } from "./compile-
|
|
2
|
-
import { t as i } from "./tsx-extractor-
|
|
3
|
-
import { a, c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "./extract-cache-
|
|
1
|
+
import { i as e, n as t, r as n, t as r } from "./compile-CXReVuTG.js";
|
|
2
|
+
import { t as i } from "./tsx-extractor-C-HZNobu.js";
|
|
3
|
+
import { a, c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "./extract-cache-BTxWgic2.js";
|
|
4
4
|
import { createPluginRunner as p, hashMessage as m, resolveLocaleCodes as h } from "@fluenti/core/internal";
|
|
5
5
|
import { existsSync as g, mkdirSync as _, readFileSync as v, writeFileSync as y } from "node:fs";
|
|
6
6
|
import { dirname as b, extname as x, resolve as S } from "node:path";
|
|
@@ -74,7 +74,13 @@ function A(e, t) {
|
|
|
74
74
|
return t === "json" ? l(n) : s(n);
|
|
75
75
|
}
|
|
76
76
|
function j(e, t, n) {
|
|
77
|
-
|
|
77
|
+
let r = n === "json" ? d(t) : a(t);
|
|
78
|
+
try {
|
|
79
|
+
_(b(e), { recursive: !0 }), y(e, r, "utf-8");
|
|
80
|
+
} catch (t) {
|
|
81
|
+
let n = t instanceof Error ? t.message : String(t);
|
|
82
|
+
throw Error(`Failed to write catalog "${e}": ${n}`);
|
|
83
|
+
}
|
|
78
84
|
}
|
|
79
85
|
async function M(e, t) {
|
|
80
86
|
if (x(e) === ".vue") try {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n mkdirSync(dirname(filePath), { recursive: true })\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n writeFileSync(filePath, content, 'utf-8')\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n try {\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, content, 'utf-8')\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to write catalog \"${filePath}\": ${message}`)\n }\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
|
package/dist/lint.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG5C,2CAA2C;AAC3C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,qBAAqB;IACrB,QAAQ,EAAE,YAAY,CAAA;IACtB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,OAAO,EAAE,WAAW,GACnB,cAAc,EAAE,CAgIlB;AAGD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,GAAG,MAAM,CAsBvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel-compile.d.ts","sourceRoot":"","sources":["../src/parallel-compile.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAG7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;CACpB;
|
|
1
|
+
{"version":3,"file":"parallel-compile.d.ts","sourceRoot":"","sources":["../src/parallel-compile.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAG7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;CACpB;AAYD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,mBAAmB,EAAE,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAqGlC"}
|
package/dist/po-format.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"po-format.d.ts","sourceRoot":"","sources":["../src/po-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"po-format.d.ts","sourceRoot":"","sources":["../src/po-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA0E5C,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAU1D;AAED,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CA6D3D"}
|
package/dist/translate.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CatalogData } from './catalog';
|
|
2
|
-
|
|
2
|
+
import { AIProvider } from './ai-provider';
|
|
3
|
+
export type { AIProvider } from './ai-provider';
|
|
3
4
|
export declare function buildPrompt(sourceLocale: string, targetLocale: string, messages: Record<string, string>, context?: string): string;
|
|
4
5
|
export declare function extractJSON(text: string): Record<string, string>;
|
|
5
6
|
export declare function getUntranslatedEntries(catalog: CatalogData): Record<string, string>;
|
package/dist/translate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAeR;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBhE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASnF;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAa/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC;IACzE,OAAO,EAAE,WAAW,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CA0CD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`./extract-cache-
|
|
2
|
-
//# sourceMappingURL=tsx-extractor-
|
|
1
|
+
require(`./extract-cache-CGSKwh76.cjs`);let e=require(`@fluenti/core/transform`);var t=new Set([`@fluenti/core`,`@fluenti/react`,`@fluenti/vue`,`@fluenti/solid`,`@fluenti/next`]);function n(e){let t=e.trim();if(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(t))return t;if(/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(t)&&!t.endsWith(`.`)){let e=t.split(`.`);return e[e.length-1]}let n=t.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\s*\(/);return n?n[1].replace(/\./g,`_`):``}function r(e,t){let r=``,i=0;for(let a=0;a<e.length;a++){if(r+=e[a],a>=t.length)continue;let o=n(t[a]);if(o===``){r+=`{arg${i}}`,i++;continue}r+=`{${o}}`}return r}function i(e,t,n){if(!e.message)return;let r=n.loc?.start.line??1,i=(n.loc?.start.column??0)+1;return{id:e.id,message:e.message,...e.context===void 0?{}:{context:e.context},...e.comment===void 0?{}:{comment:e.comment},origin:{file:t,line:r,column:i}}}function a(t,n){if(!t.message)return;let r=n??e.createMessageId;return{id:t.id??r(t.message,t.context),message:t.message,...t.context===void 0?{}:{context:t.context},...t.comment===void 0?{}:{comment:t.comment}}}function o(e,t){if(e.type===`StringLiteral`)return a({message:e.value},t);if(e.type===`TemplateLiteral`){let n=e;return n.expressions.length===0?a({message:n.quasis.map(e=>e.value.cooked??e.value.raw).join(``)},t):void 0}if(e.type!==`ObjectExpression`)return;let n={};for(let t of e.properties){if(t.type!==`ObjectProperty`)continue;let e=t;if(e.computed||!T(e.key))continue;let r=e.key.name;if(![`id`,`message`,`context`,`comment`].includes(r))continue;let i=p(e.value);i!==void 0&&(n[r]=i)}if(n.message)return a(n,t)}var s=new Set([`id`,`value`,`context`,`comment`,`options`,`other`,`tag`]);function c(e,t,n){let r=[];for(let[e,n]of Object.entries(t))r.push(`${e} {${n}}`);return r.push(`other {${n}}`),`{${e}, select, ${r.join(` `)}}`}function l(e,t){let r,i,a,o,c,l={};for(let u of e.attributes){if(u.type!==`JSXAttribute`)continue;let e=u;if(e.name.type!==`JSXIdentifier`)continue;let d=String(e.name.name);if(d===`id`){i=e.value?p(e.value):void 0;continue}if(d===`value`){let i=e.value?p(e.value)??m(e.value,t):void 0;r=i?n(i)||i:void 0;continue}if(d===`context`){a=e.value?p(e.value):void 0;continue}if(d===`comment`){o=e.value?p(e.value):void 0;continue}if(d===`other`){c=e.value?p(e.value):void 0;continue}if(s.has(d))continue;let f=e.value?p(e.value):void 0;f!==void 0&&(l[d]=f)}return{varName:r,id:i,context:a,comment:o,cases:l,other:c}}function u(e){let t=[`zero`,`one`,`two`,`few`,`many`,`other`],n=e.value??e.count??`count`,r=[],i=e.offset;for(let n of t){let t=e[n];if(t===void 0)continue;let i=n===`zero`?`=0`:n;r.push(`${i} {${t}}`)}return r.length===0?``:`{${n}, plural, ${i?`offset:${i} `:``}${r.join(` `)}}`}function d(e){let t=0;function n(e){let r=``;for(let i of e){if(i.type===`JSXText`){r+=f(i.value);continue}if(i.type===`JSXElement`){let e=t++,a=n(i.children);if(a===void 0)return;r+=`<${e}>${a}</${e}>`;continue}if(i.type===`JSXFragment`){let e=n(i.children);if(e===void 0)return;r+=e;continue}if(i.type===`JSXExpressionContainer`){let e=i.expression;if(e.type===`StringLiteral`){r+=e.value;continue}if(e.type===`NumericLiteral`){r+=String(e.value);continue}return}}return r}let r=n(e);if(r!==void 0)return r.replace(/\s+/g,` `).trim()||void 0}function f(e){return e.replace(/\s+/g,` `)}function p(e){if(e.type===`StringLiteral`)return e.value;if(e.type===`NumericLiteral`)return String(e.value);if(e.type===`JSXExpressionContainer`)return p(e.expression);if(e.type===`TemplateLiteral`){let t=e;if(t.expressions.length===0)return t.quasis.map(e=>e.value.cooked??e.value.raw).join(``)}}function m(e,t){if(!(e.start==null||e.end==null))return e.type===`JSXExpressionContainer`?m(e.expression,t):t.slice(e.start,e.end).trim()}function h(e,t){for(let n of e.attributes){if(n.type!==`JSXAttribute`)continue;let e=n;if(e.name.type===`JSXIdentifier`&&e.name.name===t)return e}}function g(e,t){let n={};for(let r of[`id`,`value`,`count`,`offset`,`zero`,`one`,`two`,`few`,`many`,`other`]){let i=h(e,r);if(!i?.value)continue;let a=p(i.value);if(a!==void 0){n[r]=a;continue}let o=m(i.value,t);o!==void 0&&(r===`value`||r===`count`||r===`offset`)&&(n[r]=o)}return n}function _(t,n,i){let a=r(n.quasi.quasis.map(e=>e.value.cooked??e.value.raw),n.quasi.expressions.map(e=>e.start==null||e.end==null?``:t.slice(e.start,e.end)));return{id:(i??e.createMessageId)(a),message:a}}function v(e){let n=new Map,r=Array.isArray(e.body)?e.body:[];for(let e of r)if(b(e)&&t.has(e.source.value))for(let t of e.specifiers){if(!x(t))continue;let e=S(t);(e===`t`||e===`msg`)&&n.set(t.local.name,e)}return n}function y(t,n,r){let a=(0,e.parseSourceModule)(t);if(!a)return console.warn(`[fluenti] Failed to parse ${n} — skipping message extraction`),[];let s=[],f=v(a);return(0,e.walkSourceAst)(a,a=>{if(a.type===`TaggedTemplateExpression`){let e=a;if(T(e.tag)&&(e.tag.name===`t`||f.has(e.tag.name))){let a=_(t,e,r);f.get(e.tag.name)===`msg`&&(a.comment=`msg tagged template`);let o=i(a,n,e);o&&s.push(o)}return}if(a.type===`CallExpression`){let e=a,t=f.get(e.callee&&T(e.callee)?e.callee.name:``);if(T(e.callee)&&(e.callee.name===`t`||f.has(e.callee.name)&&t===`t`)){if(f.has(e.callee.name)&&e.arguments[0]?.type!==`ObjectExpression`)return;let t=e.arguments[0]?o(e.arguments[0],r):void 0,a=t?i(t,n,e):void 0;a&&s.push(a)}else if(e.callee.type===`MemberExpression`&&T(e.callee.object)&&f.get(e.callee.object.name)===`msg`&&T(e.callee.property)&&e.callee.property.name===`descriptor`&&e.arguments[0]){let t=o(e.arguments[0],r),a=t?i(t,n,e):void 0;a&&s.push(a)}return}if(a.type!==`JSXElement`)return;let m=a,v=m.openingElement,y=C(v.name);if(y===`Trans`){let e=h(v,`message`),t=h(v,`id`),a=h(v,`context`),o=h(v,`comment`),c=e?.value?w({id:t?.value?p(t.value):void 0,message:p(e.value),context:a?.value?p(a.value):void 0,comment:o?.value?p(o.value):void 0},r):w({id:t?.value?p(t.value):void 0,message:d(m.children),context:a?.value?p(a.value):void 0,comment:o?.value?p(o.value):void 0},r),l=c?i(c,n,m):void 0;l&&s.push(l);return}if(y===`Plural`){let a=g(v,t),o=u(a);if(!o)return;let c=r??e.createMessageId,l=i({id:a.id??c(o),message:o},n,m);l&&s.push(l);return}if(y===`Select`){let{varName:a,id:o,context:u,comment:d,cases:f,other:p}=l(v,t);if(!a||!p||Object.keys(f).length===0)return;let h=c(a,f,p),g=i({id:o??(r??e.createMessageId)(h,u),message:h,...u===void 0?{}:{context:u},...d===void 0?{}:{comment:d}},n,m);g&&s.push(g)}}),s}function b(t){return(0,e.isSourceNode)(t)&&t.type===`ImportDeclaration`}function x(t){return(0,e.isSourceNode)(t)&&t.type===`ImportSpecifier`}function S(e){if(e.imported.type===`Identifier`)return e.imported.name;if(e.imported.type===`StringLiteral`)return e.imported.value}function C(e){if(e.type===`JSXIdentifier`)return String(e.name)}function w(e,t){let n={};return e.id!==void 0&&(n.id=e.id),e.message!==void 0&&(n.message=e.message),e.context!==void 0&&(n.context=e.context),e.comment!==void 0&&(n.comment=e.comment),a(n,t)}function T(t){return(0,e.isSourceNode)(t)&&t.type===`Identifier`}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return y}});
|
|
2
|
+
//# sourceMappingURL=tsx-extractor-BOD7JJQK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsx-extractor-BOD7JJQK.cjs","names":[],"sources":["../src/tsx-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\nimport {\n createMessageId,\n isSourceNode,\n parseSourceModule,\n walkSourceAst,\n type SourceNode,\n} from '@fluenti/core/transform'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { raw: string; cooked: string | null }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n quasis: TemplateElementNode[]\n expressions: SourceNode[]\n}\n\ninterface TaggedTemplateExpressionNode extends SourceNode {\n type: 'TaggedTemplateExpression'\n tag: SourceNode\n quasi: TemplateLiteralNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n children: SourceNode[]\n}\n\ninterface JSXFragmentNode extends SourceNode {\n type: 'JSXFragment'\n children: SourceNode[]\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: SourceNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface JSXTextNode extends SourceNode {\n type: 'JSXText'\n value: string\n}\n\ninterface ExtractedDescriptor {\n id: string\n message?: string\n context?: string\n comment?: string\n}\n\nconst DIRECT_T_SOURCES = new Set([\n '@fluenti/core',\n '@fluenti/react',\n '@fluenti/vue',\n '@fluenti/solid',\n '@fluenti/next',\n])\n\nfunction classifyExpression(expr: string): string {\n const trimmed = expr.trim()\n // Simple identifier: name, count\n if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(trimmed)) {\n return trimmed\n }\n // Dotted path: user.name → name\n if (/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(trimmed) && !trimmed.endsWith('.')) {\n const parts = trimmed.split('.')\n return parts[parts.length - 1]!\n }\n // Function call: fun() → fun, obj.method() → obj_method\n const callMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\\s*\\(/)\n if (callMatch) {\n return callMatch[1]!.replace(/\\./g, '_')\n }\n return ''\n}\n\nfunction buildICUFromTemplate(\n strings: readonly string[],\n expressions: readonly string[],\n): string {\n let result = ''\n let positionalIndex = 0\n\n for (let index = 0; index < strings.length; index++) {\n result += strings[index]!\n if (index >= expressions.length) continue\n\n const name = classifyExpression(expressions[index]!)\n if (name === '') {\n result += `{arg${positionalIndex}}`\n positionalIndex++\n continue\n }\n\n result += `{${name}}`\n }\n\n return result\n}\n\nfunction createExtractedMessage(\n descriptor: ExtractedDescriptor,\n filename: string,\n node: SourceNode,\n): ExtractedMessage | undefined {\n if (!descriptor.message) {\n return undefined\n }\n\n const line = node.loc?.start.line ?? 1\n const column = (node.loc?.start.column ?? 0) + 1\n\n return {\n id: descriptor.id,\n message: descriptor.message,\n ...(descriptor.context !== undefined ? { context: descriptor.context } : {}),\n ...(descriptor.comment !== undefined ? { comment: descriptor.comment } : {}),\n origin: { file: filename, line, column },\n }\n}\n\nfunction descriptorFromStaticParts(\n parts: {\n id?: string\n message?: string\n context?: string\n comment?: string\n },\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor | undefined {\n if (!parts.message) {\n return undefined\n }\n\n const generateId = idGenerator ?? createMessageId\n\n return {\n id: parts.id ?? generateId(parts.message, parts.context),\n message: parts.message,\n ...(parts.context !== undefined ? { context: parts.context } : {}),\n ...(parts.comment !== undefined ? { comment: parts.comment } : {}),\n }\n}\n\nfunction extractDescriptorFromCallArgument(\n argument: SourceNode,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor | undefined {\n if (argument.type === 'StringLiteral') {\n return descriptorFromStaticParts({ message: (argument as StringLiteralNode).value }, idGenerator)\n }\n\n if (argument.type === 'TemplateLiteral') {\n const template = argument as TemplateLiteralNode\n if (template.expressions.length === 0) {\n const message = template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n return descriptorFromStaticParts({ message }, idGenerator)\n }\n return undefined\n }\n\n if (argument.type !== 'ObjectExpression') {\n return undefined\n }\n\n const staticParts: { id?: string; message?: string; context?: string; comment?: string } = {}\n for (const property of (argument as ObjectExpressionNode).properties) {\n if (property.type !== 'ObjectProperty') continue\n\n const objectProperty = property as ObjectPropertyNode\n if (objectProperty.computed || !isIdentifier(objectProperty.key)) continue\n\n const key = objectProperty.key.name\n if (!['id', 'message', 'context', 'comment'].includes(key)) continue\n\n const value = readStaticStringValue(objectProperty.value)\n if (value === undefined) continue\n staticParts[key as keyof typeof staticParts] = value\n }\n\n if (!staticParts.message) {\n return undefined\n }\n\n return descriptorFromStaticParts(staticParts, idGenerator)\n}\n\nconst SELECT_RESERVED_PROPS = new Set(['id', 'value', 'context', 'comment', 'options', 'other', 'tag'])\n\nfunction buildSelectICU(varName: string, cases: Record<string, string>, other: string): string {\n const options: string[] = []\n for (const [key, value] of Object.entries(cases)) {\n options.push(`${key} {${value}}`)\n }\n options.push(`other {${other}}`)\n return `{${varName}, select, ${options.join(' ')}}`\n}\n\nfunction extractSelectProps(\n openingElement: JSXOpeningElementNode,\n code: string,\n): { varName: string | undefined; id: string | undefined; context: string | undefined; comment: string | undefined; cases: Record<string, string>; other: string | undefined } {\n let varName: string | undefined\n let id: string | undefined\n let context: string | undefined\n let comment: string | undefined\n let other: string | undefined\n const cases: Record<string, string> = {}\n\n for (const attribute of openingElement.attributes) {\n if (attribute.type !== 'JSXAttribute') continue\n const attr = attribute as JSXAttributeNode\n if (attr.name.type !== 'JSXIdentifier') continue\n const name = String(attr.name['name'])\n\n if (name === 'id') {\n id = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (name === 'value') {\n const raw = attr.value ? (readStaticStringValue(attr.value) ?? readExpressionSource(attr.value, code)) : undefined\n varName = raw ? classifyExpression(raw) || raw : undefined\n continue\n }\n if (name === 'context') {\n context = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (name === 'comment') {\n comment = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (name === 'other') {\n other = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (SELECT_RESERVED_PROPS.has(name)) continue\n\n const staticValue = attr.value ? readStaticStringValue(attr.value) : undefined\n if (staticValue === undefined) continue\n\n cases[name] = staticValue\n }\n\n return { varName, id, context, comment, cases, other }\n}\n\nfunction buildPluralICU(props: Record<string, string>): string {\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n const countVar = props['value'] ?? props['count'] ?? 'count'\n const options: string[] = []\n const offset = props['offset']\n\n for (const category of categories) {\n const value = props[category]\n if (value === undefined) continue\n const key = category === 'zero' ? '=0' : category\n options.push(`${key} {${value}}`)\n }\n\n if (options.length === 0) {\n return ''\n }\n\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction extractRichTextMessage(children: readonly SourceNode[]): string | undefined {\n let nextIndex = 0\n\n function render(nodes: readonly SourceNode[]): string | undefined {\n let message = ''\n\n for (const node of nodes) {\n if (node.type === 'JSXText') {\n message += normalizeJsxText((node as JSXTextNode).value)\n continue\n }\n\n if (node.type === 'JSXElement') {\n const idx = nextIndex++\n const inner = render((node as JSXElementNode).children)\n if (inner === undefined) return undefined\n message += `<${idx}>${inner}</${idx}>`\n continue\n }\n\n if (node.type === 'JSXFragment') {\n const inner = render((node as JSXFragmentNode).children)\n if (inner === undefined) return undefined\n message += inner\n continue\n }\n\n if (node.type === 'JSXExpressionContainer') {\n const expression = (node as JSXExpressionContainerNode).expression\n if (expression.type === 'StringLiteral') {\n message += (expression as StringLiteralNode).value\n continue\n }\n if (expression.type === 'NumericLiteral') {\n message += String((expression as NumericLiteralNode).value)\n continue\n }\n return undefined\n }\n }\n\n return message\n }\n\n const message = render(children)\n if (message === undefined) return undefined\n\n const normalized = message.replace(/\\s+/g, ' ').trim()\n return normalized || undefined\n}\n\nfunction normalizeJsxText(value: string): string {\n return value.replace(/\\s+/g, ' ')\n}\n\nfunction readStaticStringValue(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'NumericLiteral') {\n return String((node as NumericLiteralNode).value)\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readStaticStringValue((node as JSXExpressionContainerNode).expression)\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0) {\n return template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n }\n }\n\n return undefined\n}\n\nfunction readExpressionSource(node: SourceNode, code: string): string | undefined {\n if (node.start == null || node.end == null) {\n return undefined\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readExpressionSource((node as JSXExpressionContainerNode).expression, code)\n }\n\n return code.slice(node.start, node.end).trim()\n}\n\nfunction getJsxAttribute(\n openingElement: JSXOpeningElementNode,\n name: string,\n): JSXAttributeNode | undefined {\n for (const attribute of openingElement.attributes) {\n if (attribute.type !== 'JSXAttribute') continue\n\n const jsxAttribute = attribute as JSXAttributeNode\n if (jsxAttribute.name.type === 'JSXIdentifier' && jsxAttribute.name['name'] === name) {\n return jsxAttribute\n }\n }\n\n return undefined\n}\n\nfunction extractPluralProps(\n openingElement: JSXOpeningElementNode,\n code: string,\n): Record<string, string> {\n const props: Record<string, string> = {}\n const propNames = ['id', 'value', 'count', 'offset', 'zero', 'one', 'two', 'few', 'many', 'other']\n\n for (const name of propNames) {\n const attribute = getJsxAttribute(openingElement, name)\n if (!attribute?.value) continue\n\n const staticValue = readStaticStringValue(attribute.value)\n if (staticValue !== undefined) {\n props[name] = staticValue\n continue\n }\n\n const exprValue = readExpressionSource(attribute.value, code)\n if (exprValue !== undefined && (name === 'value' || name === 'count' || name === 'offset')) {\n props[name] = exprValue\n }\n }\n\n return props\n}\n\nfunction extractTaggedTemplateMessage(\n code: string,\n node: TaggedTemplateExpressionNode,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor {\n const strings = node.quasi.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw)\n const expressions = node.quasi.expressions.map((expression) => {\n if (expression.start == null || expression.end == null) {\n return ''\n }\n return code.slice(expression.start, expression.end)\n })\n const message = buildICUFromTemplate(strings, expressions)\n const generateId = idGenerator ?? createMessageId\n\n return {\n id: generateId(message),\n message,\n }\n}\n\nfunction collectDirectBindings(ast: SourceNode): Map<string, 't' | 'msg'> {\n const bindings = new Map<string, 't' | 'msg'>()\n const body = Array.isArray(ast['body']) ? ast['body'] : []\n\n for (const entry of body) {\n if (!isImportDeclaration(entry)) continue\n if (!DIRECT_T_SOURCES.has(entry.source.value)) continue\n\n for (const specifier of entry.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n const importedName = readImportedName(specifier)\n if (importedName === 't' || importedName === 'msg') {\n bindings.set(specifier.local.name, importedName as 't' | 'msg')\n }\n }\n }\n\n return bindings\n}\n\nexport function extractFromTsx(\n code: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const ast = parseSourceModule(code)\n if (!ast) {\n console.warn(`[fluenti] Failed to parse ${filename} — skipping message extraction`)\n return []\n }\n\n const messages: ExtractedMessage[] = []\n const directBindings = collectDirectBindings(ast)\n\n walkSourceAst(ast, (node: SourceNode) => {\n if (node.type === 'TaggedTemplateExpression') {\n const tagged = node as TaggedTemplateExpressionNode\n if (\n isIdentifier(tagged.tag)\n && (tagged.tag.name === 't' || directBindings.has(tagged.tag.name))\n ) {\n const descriptor = extractTaggedTemplateMessage(code, tagged, idGenerator)\n const bindingType = directBindings.get(tagged.tag.name)\n if (bindingType === 'msg') {\n descriptor.comment = 'msg tagged template'\n }\n const extracted = createExtractedMessage(\n descriptor,\n filename,\n tagged,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type === 'CallExpression') {\n const call = node as CallExpressionNode\n const callBindingType = directBindings.get(call.callee && isIdentifier(call.callee) ? call.callee.name : '')\n if (isIdentifier(call.callee) && (call.callee.name === 't' || (directBindings.has(call.callee.name) && callBindingType === 't'))) {\n if (directBindings.has(call.callee.name) && call.arguments[0]?.type !== 'ObjectExpression') {\n return\n }\n const descriptor = call.arguments[0] ? extractDescriptorFromCallArgument(call.arguments[0], idGenerator) : undefined\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, call)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n } else if (\n call.callee.type === 'MemberExpression'\n && isIdentifier(call.callee['object'])\n && directBindings.get((call.callee['object'] as IdentifierNode).name) === 'msg'\n && isIdentifier(call.callee['property'])\n && (call.callee['property'] as IdentifierNode).name === 'descriptor'\n && call.arguments[0]\n ) {\n const descriptor = extractDescriptorFromCallArgument(call.arguments[0], idGenerator)\n const extracted = descriptor ? createExtractedMessage(descriptor, filename, call) : undefined\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type !== 'JSXElement') {\n return\n }\n\n const element = node as JSXElementNode\n const openingElement = element.openingElement\n const elementName = readJsxElementName(openingElement.name)\n\n if (elementName === 'Trans') {\n const messageAttr = getJsxAttribute(openingElement, 'message')\n const idAttr = getJsxAttribute(openingElement, 'id')\n const contextAttr = getJsxAttribute(openingElement, 'context')\n const commentAttr = getJsxAttribute(openingElement, 'comment')\n\n const descriptor = messageAttr?.value\n ? buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: readStaticStringValue(messageAttr.value),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n }, idGenerator)\n : buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: extractRichTextMessage(element.children),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n }, idGenerator)\n\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, element)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n return\n }\n\n if (elementName === 'Plural') {\n const props = extractPluralProps(openingElement, code)\n const message = buildPluralICU(props)\n if (!message) {\n return\n }\n\n const generateId = idGenerator ?? createMessageId\n const extracted = createExtractedMessage(\n {\n id: props['id'] ?? generateId(message),\n message,\n },\n filename,\n element,\n )\n if (extracted) {\n messages.push(extracted)\n }\n return\n }\n\n if (elementName === 'Select') {\n const { varName, id, context, comment, cases, other } = extractSelectProps(openingElement, code)\n if (!varName || !other || Object.keys(cases).length === 0) {\n return\n }\n\n const message = buildSelectICU(varName, cases, other)\n const generateId = idGenerator ?? createMessageId\n const extracted = createExtractedMessage(\n {\n id: id ?? generateId(message, context),\n message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n },\n filename,\n element,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n })\n\n return messages\n}\n\nfunction isImportDeclaration(node: unknown): node is ImportDeclarationNode {\n return isSourceNode(node) && node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: unknown): node is ImportSpecifierNode {\n return isSourceNode(node) && node.type === 'ImportSpecifier'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n if (specifier.imported.type === 'Identifier') {\n return (specifier.imported as IdentifierNode).name\n }\n if (specifier.imported.type === 'StringLiteral') {\n return (specifier.imported as StringLiteralNode).value\n }\n return undefined\n}\n\nfunction readJsxElementName(node: SourceNode): string | undefined {\n if (node.type === 'JSXIdentifier') {\n return String(node['name'])\n }\n return undefined\n}\n\nfunction buildStaticTransDescriptor(\n parts: {\n id: string | undefined\n message: string | undefined\n context: string | undefined\n comment: string | undefined\n },\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor | undefined {\n const payload: {\n id?: string\n message?: string\n context?: string\n comment?: string\n } = {}\n\n if (parts.id !== undefined) payload.id = parts.id\n if (parts.message !== undefined) payload.message = parts.message\n if (parts.context !== undefined) payload.context = parts.context\n if (parts.comment !== undefined) payload.comment = parts.comment\n\n return descriptorFromStaticParts(payload, idGenerator)\n}\n\nfunction isIdentifier(node: unknown): node is IdentifierNode {\n return isSourceNode(node) && node.type === 'Identifier'\n}\n"],"mappings":"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"}
|
|
@@ -256,7 +256,7 @@ function x(e) {
|
|
|
256
256
|
}
|
|
257
257
|
function S(t, i, a) {
|
|
258
258
|
let o = n(t);
|
|
259
|
-
if (!o) return [];
|
|
259
|
+
if (!o) return console.warn(`[fluenti] Failed to parse ${i} — skipping message extraction`), [];
|
|
260
260
|
let c = [], u = x(o);
|
|
261
261
|
return r(o, (n) => {
|
|
262
262
|
if (n.type === "TaggedTemplateExpression") {
|
|
@@ -344,4 +344,4 @@ function O(e) {
|
|
|
344
344
|
//#endregion
|
|
345
345
|
export { S as t };
|
|
346
346
|
|
|
347
|
-
//# sourceMappingURL=tsx-extractor-
|
|
347
|
+
//# sourceMappingURL=tsx-extractor-C-HZNobu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsx-extractor-C-HZNobu.js","names":[],"sources":["../src/tsx-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\nimport {\n createMessageId,\n isSourceNode,\n parseSourceModule,\n walkSourceAst,\n type SourceNode,\n} from '@fluenti/core/transform'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { raw: string; cooked: string | null }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n quasis: TemplateElementNode[]\n expressions: SourceNode[]\n}\n\ninterface TaggedTemplateExpressionNode extends SourceNode {\n type: 'TaggedTemplateExpression'\n tag: SourceNode\n quasi: TemplateLiteralNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n children: SourceNode[]\n}\n\ninterface JSXFragmentNode extends SourceNode {\n type: 'JSXFragment'\n children: SourceNode[]\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: SourceNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface JSXTextNode extends SourceNode {\n type: 'JSXText'\n value: string\n}\n\ninterface ExtractedDescriptor {\n id: string\n message?: string\n context?: string\n comment?: string\n}\n\nconst DIRECT_T_SOURCES = new Set([\n '@fluenti/core',\n '@fluenti/react',\n '@fluenti/vue',\n '@fluenti/solid',\n '@fluenti/next',\n])\n\nfunction classifyExpression(expr: string): string {\n const trimmed = expr.trim()\n // Simple identifier: name, count\n if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(trimmed)) {\n return trimmed\n }\n // Dotted path: user.name → name\n if (/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(trimmed) && !trimmed.endsWith('.')) {\n const parts = trimmed.split('.')\n return parts[parts.length - 1]!\n }\n // Function call: fun() → fun, obj.method() → obj_method\n const callMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\\s*\\(/)\n if (callMatch) {\n return callMatch[1]!.replace(/\\./g, '_')\n }\n return ''\n}\n\nfunction buildICUFromTemplate(\n strings: readonly string[],\n expressions: readonly string[],\n): string {\n let result = ''\n let positionalIndex = 0\n\n for (let index = 0; index < strings.length; index++) {\n result += strings[index]!\n if (index >= expressions.length) continue\n\n const name = classifyExpression(expressions[index]!)\n if (name === '') {\n result += `{arg${positionalIndex}}`\n positionalIndex++\n continue\n }\n\n result += `{${name}}`\n }\n\n return result\n}\n\nfunction createExtractedMessage(\n descriptor: ExtractedDescriptor,\n filename: string,\n node: SourceNode,\n): ExtractedMessage | undefined {\n if (!descriptor.message) {\n return undefined\n }\n\n const line = node.loc?.start.line ?? 1\n const column = (node.loc?.start.column ?? 0) + 1\n\n return {\n id: descriptor.id,\n message: descriptor.message,\n ...(descriptor.context !== undefined ? { context: descriptor.context } : {}),\n ...(descriptor.comment !== undefined ? { comment: descriptor.comment } : {}),\n origin: { file: filename, line, column },\n }\n}\n\nfunction descriptorFromStaticParts(\n parts: {\n id?: string\n message?: string\n context?: string\n comment?: string\n },\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor | undefined {\n if (!parts.message) {\n return undefined\n }\n\n const generateId = idGenerator ?? createMessageId\n\n return {\n id: parts.id ?? generateId(parts.message, parts.context),\n message: parts.message,\n ...(parts.context !== undefined ? { context: parts.context } : {}),\n ...(parts.comment !== undefined ? { comment: parts.comment } : {}),\n }\n}\n\nfunction extractDescriptorFromCallArgument(\n argument: SourceNode,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor | undefined {\n if (argument.type === 'StringLiteral') {\n return descriptorFromStaticParts({ message: (argument as StringLiteralNode).value }, idGenerator)\n }\n\n if (argument.type === 'TemplateLiteral') {\n const template = argument as TemplateLiteralNode\n if (template.expressions.length === 0) {\n const message = template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n return descriptorFromStaticParts({ message }, idGenerator)\n }\n return undefined\n }\n\n if (argument.type !== 'ObjectExpression') {\n return undefined\n }\n\n const staticParts: { id?: string; message?: string; context?: string; comment?: string } = {}\n for (const property of (argument as ObjectExpressionNode).properties) {\n if (property.type !== 'ObjectProperty') continue\n\n const objectProperty = property as ObjectPropertyNode\n if (objectProperty.computed || !isIdentifier(objectProperty.key)) continue\n\n const key = objectProperty.key.name\n if (!['id', 'message', 'context', 'comment'].includes(key)) continue\n\n const value = readStaticStringValue(objectProperty.value)\n if (value === undefined) continue\n staticParts[key as keyof typeof staticParts] = value\n }\n\n if (!staticParts.message) {\n return undefined\n }\n\n return descriptorFromStaticParts(staticParts, idGenerator)\n}\n\nconst SELECT_RESERVED_PROPS = new Set(['id', 'value', 'context', 'comment', 'options', 'other', 'tag'])\n\nfunction buildSelectICU(varName: string, cases: Record<string, string>, other: string): string {\n const options: string[] = []\n for (const [key, value] of Object.entries(cases)) {\n options.push(`${key} {${value}}`)\n }\n options.push(`other {${other}}`)\n return `{${varName}, select, ${options.join(' ')}}`\n}\n\nfunction extractSelectProps(\n openingElement: JSXOpeningElementNode,\n code: string,\n): { varName: string | undefined; id: string | undefined; context: string | undefined; comment: string | undefined; cases: Record<string, string>; other: string | undefined } {\n let varName: string | undefined\n let id: string | undefined\n let context: string | undefined\n let comment: string | undefined\n let other: string | undefined\n const cases: Record<string, string> = {}\n\n for (const attribute of openingElement.attributes) {\n if (attribute.type !== 'JSXAttribute') continue\n const attr = attribute as JSXAttributeNode\n if (attr.name.type !== 'JSXIdentifier') continue\n const name = String(attr.name['name'])\n\n if (name === 'id') {\n id = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (name === 'value') {\n const raw = attr.value ? (readStaticStringValue(attr.value) ?? readExpressionSource(attr.value, code)) : undefined\n varName = raw ? classifyExpression(raw) || raw : undefined\n continue\n }\n if (name === 'context') {\n context = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (name === 'comment') {\n comment = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (name === 'other') {\n other = attr.value ? readStaticStringValue(attr.value) : undefined\n continue\n }\n if (SELECT_RESERVED_PROPS.has(name)) continue\n\n const staticValue = attr.value ? readStaticStringValue(attr.value) : undefined\n if (staticValue === undefined) continue\n\n cases[name] = staticValue\n }\n\n return { varName, id, context, comment, cases, other }\n}\n\nfunction buildPluralICU(props: Record<string, string>): string {\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n const countVar = props['value'] ?? props['count'] ?? 'count'\n const options: string[] = []\n const offset = props['offset']\n\n for (const category of categories) {\n const value = props[category]\n if (value === undefined) continue\n const key = category === 'zero' ? '=0' : category\n options.push(`${key} {${value}}`)\n }\n\n if (options.length === 0) {\n return ''\n }\n\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction extractRichTextMessage(children: readonly SourceNode[]): string | undefined {\n let nextIndex = 0\n\n function render(nodes: readonly SourceNode[]): string | undefined {\n let message = ''\n\n for (const node of nodes) {\n if (node.type === 'JSXText') {\n message += normalizeJsxText((node as JSXTextNode).value)\n continue\n }\n\n if (node.type === 'JSXElement') {\n const idx = nextIndex++\n const inner = render((node as JSXElementNode).children)\n if (inner === undefined) return undefined\n message += `<${idx}>${inner}</${idx}>`\n continue\n }\n\n if (node.type === 'JSXFragment') {\n const inner = render((node as JSXFragmentNode).children)\n if (inner === undefined) return undefined\n message += inner\n continue\n }\n\n if (node.type === 'JSXExpressionContainer') {\n const expression = (node as JSXExpressionContainerNode).expression\n if (expression.type === 'StringLiteral') {\n message += (expression as StringLiteralNode).value\n continue\n }\n if (expression.type === 'NumericLiteral') {\n message += String((expression as NumericLiteralNode).value)\n continue\n }\n return undefined\n }\n }\n\n return message\n }\n\n const message = render(children)\n if (message === undefined) return undefined\n\n const normalized = message.replace(/\\s+/g, ' ').trim()\n return normalized || undefined\n}\n\nfunction normalizeJsxText(value: string): string {\n return value.replace(/\\s+/g, ' ')\n}\n\nfunction readStaticStringValue(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'NumericLiteral') {\n return String((node as NumericLiteralNode).value)\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readStaticStringValue((node as JSXExpressionContainerNode).expression)\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0) {\n return template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n }\n }\n\n return undefined\n}\n\nfunction readExpressionSource(node: SourceNode, code: string): string | undefined {\n if (node.start == null || node.end == null) {\n return undefined\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readExpressionSource((node as JSXExpressionContainerNode).expression, code)\n }\n\n return code.slice(node.start, node.end).trim()\n}\n\nfunction getJsxAttribute(\n openingElement: JSXOpeningElementNode,\n name: string,\n): JSXAttributeNode | undefined {\n for (const attribute of openingElement.attributes) {\n if (attribute.type !== 'JSXAttribute') continue\n\n const jsxAttribute = attribute as JSXAttributeNode\n if (jsxAttribute.name.type === 'JSXIdentifier' && jsxAttribute.name['name'] === name) {\n return jsxAttribute\n }\n }\n\n return undefined\n}\n\nfunction extractPluralProps(\n openingElement: JSXOpeningElementNode,\n code: string,\n): Record<string, string> {\n const props: Record<string, string> = {}\n const propNames = ['id', 'value', 'count', 'offset', 'zero', 'one', 'two', 'few', 'many', 'other']\n\n for (const name of propNames) {\n const attribute = getJsxAttribute(openingElement, name)\n if (!attribute?.value) continue\n\n const staticValue = readStaticStringValue(attribute.value)\n if (staticValue !== undefined) {\n props[name] = staticValue\n continue\n }\n\n const exprValue = readExpressionSource(attribute.value, code)\n if (exprValue !== undefined && (name === 'value' || name === 'count' || name === 'offset')) {\n props[name] = exprValue\n }\n }\n\n return props\n}\n\nfunction extractTaggedTemplateMessage(\n code: string,\n node: TaggedTemplateExpressionNode,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor {\n const strings = node.quasi.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw)\n const expressions = node.quasi.expressions.map((expression) => {\n if (expression.start == null || expression.end == null) {\n return ''\n }\n return code.slice(expression.start, expression.end)\n })\n const message = buildICUFromTemplate(strings, expressions)\n const generateId = idGenerator ?? createMessageId\n\n return {\n id: generateId(message),\n message,\n }\n}\n\nfunction collectDirectBindings(ast: SourceNode): Map<string, 't' | 'msg'> {\n const bindings = new Map<string, 't' | 'msg'>()\n const body = Array.isArray(ast['body']) ? ast['body'] : []\n\n for (const entry of body) {\n if (!isImportDeclaration(entry)) continue\n if (!DIRECT_T_SOURCES.has(entry.source.value)) continue\n\n for (const specifier of entry.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n const importedName = readImportedName(specifier)\n if (importedName === 't' || importedName === 'msg') {\n bindings.set(specifier.local.name, importedName as 't' | 'msg')\n }\n }\n }\n\n return bindings\n}\n\nexport function extractFromTsx(\n code: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const ast = parseSourceModule(code)\n if (!ast) {\n console.warn(`[fluenti] Failed to parse ${filename} — skipping message extraction`)\n return []\n }\n\n const messages: ExtractedMessage[] = []\n const directBindings = collectDirectBindings(ast)\n\n walkSourceAst(ast, (node: SourceNode) => {\n if (node.type === 'TaggedTemplateExpression') {\n const tagged = node as TaggedTemplateExpressionNode\n if (\n isIdentifier(tagged.tag)\n && (tagged.tag.name === 't' || directBindings.has(tagged.tag.name))\n ) {\n const descriptor = extractTaggedTemplateMessage(code, tagged, idGenerator)\n const bindingType = directBindings.get(tagged.tag.name)\n if (bindingType === 'msg') {\n descriptor.comment = 'msg tagged template'\n }\n const extracted = createExtractedMessage(\n descriptor,\n filename,\n tagged,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type === 'CallExpression') {\n const call = node as CallExpressionNode\n const callBindingType = directBindings.get(call.callee && isIdentifier(call.callee) ? call.callee.name : '')\n if (isIdentifier(call.callee) && (call.callee.name === 't' || (directBindings.has(call.callee.name) && callBindingType === 't'))) {\n if (directBindings.has(call.callee.name) && call.arguments[0]?.type !== 'ObjectExpression') {\n return\n }\n const descriptor = call.arguments[0] ? extractDescriptorFromCallArgument(call.arguments[0], idGenerator) : undefined\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, call)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n } else if (\n call.callee.type === 'MemberExpression'\n && isIdentifier(call.callee['object'])\n && directBindings.get((call.callee['object'] as IdentifierNode).name) === 'msg'\n && isIdentifier(call.callee['property'])\n && (call.callee['property'] as IdentifierNode).name === 'descriptor'\n && call.arguments[0]\n ) {\n const descriptor = extractDescriptorFromCallArgument(call.arguments[0], idGenerator)\n const extracted = descriptor ? createExtractedMessage(descriptor, filename, call) : undefined\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type !== 'JSXElement') {\n return\n }\n\n const element = node as JSXElementNode\n const openingElement = element.openingElement\n const elementName = readJsxElementName(openingElement.name)\n\n if (elementName === 'Trans') {\n const messageAttr = getJsxAttribute(openingElement, 'message')\n const idAttr = getJsxAttribute(openingElement, 'id')\n const contextAttr = getJsxAttribute(openingElement, 'context')\n const commentAttr = getJsxAttribute(openingElement, 'comment')\n\n const descriptor = messageAttr?.value\n ? buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: readStaticStringValue(messageAttr.value),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n }, idGenerator)\n : buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: extractRichTextMessage(element.children),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n }, idGenerator)\n\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, element)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n return\n }\n\n if (elementName === 'Plural') {\n const props = extractPluralProps(openingElement, code)\n const message = buildPluralICU(props)\n if (!message) {\n return\n }\n\n const generateId = idGenerator ?? createMessageId\n const extracted = createExtractedMessage(\n {\n id: props['id'] ?? generateId(message),\n message,\n },\n filename,\n element,\n )\n if (extracted) {\n messages.push(extracted)\n }\n return\n }\n\n if (elementName === 'Select') {\n const { varName, id, context, comment, cases, other } = extractSelectProps(openingElement, code)\n if (!varName || !other || Object.keys(cases).length === 0) {\n return\n }\n\n const message = buildSelectICU(varName, cases, other)\n const generateId = idGenerator ?? createMessageId\n const extracted = createExtractedMessage(\n {\n id: id ?? generateId(message, context),\n message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n },\n filename,\n element,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n })\n\n return messages\n}\n\nfunction isImportDeclaration(node: unknown): node is ImportDeclarationNode {\n return isSourceNode(node) && node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: unknown): node is ImportSpecifierNode {\n return isSourceNode(node) && node.type === 'ImportSpecifier'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n if (specifier.imported.type === 'Identifier') {\n return (specifier.imported as IdentifierNode).name\n }\n if (specifier.imported.type === 'StringLiteral') {\n return (specifier.imported as StringLiteralNode).value\n }\n return undefined\n}\n\nfunction readJsxElementName(node: SourceNode): string | undefined {\n if (node.type === 'JSXIdentifier') {\n return String(node['name'])\n }\n return undefined\n}\n\nfunction buildStaticTransDescriptor(\n parts: {\n id: string | undefined\n message: string | undefined\n context: string | undefined\n comment: string | undefined\n },\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedDescriptor | undefined {\n const payload: {\n id?: string\n message?: string\n context?: string\n comment?: string\n } = {}\n\n if (parts.id !== undefined) payload.id = parts.id\n if (parts.message !== undefined) payload.message = parts.message\n if (parts.context !== undefined) payload.context = parts.context\n if (parts.comment !== undefined) payload.comment = parts.comment\n\n return descriptorFromStaticParts(payload, idGenerator)\n}\n\nfunction isIdentifier(node: unknown): node is IdentifierNode {\n return isSourceNode(node) && node.type === 'Identifier'\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tsx-extractor.d.ts","sourceRoot":"","sources":["../src/tsx-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAuf9D,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,MAAM,GAC1D,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"tsx-extractor.d.ts","sourceRoot":"","sources":["../src/tsx-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAuf9D,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,MAAM,GAC1D,gBAAgB,EAAE,CAqJpB"}
|
package/dist/validation.d.ts
CHANGED
|
@@ -6,7 +6,10 @@ export interface ValidationResult {
|
|
|
6
6
|
extraHtmlTags: string[];
|
|
7
7
|
syntaxErrors: string[];
|
|
8
8
|
}
|
|
9
|
-
/** Extract unique ICU placeholder names from a message, sorted alphabetically
|
|
9
|
+
/** Extract unique ICU placeholder names from a message, sorted alphabetically.
|
|
10
|
+
* Uses the ICU parser so only top-level variables are returned — select/plural case
|
|
11
|
+
* body words (e.g. the `he`/`she` in `{g, select, male {he} other {she}}`) are not
|
|
12
|
+
* mistakenly treated as placeholder names. */
|
|
10
13
|
export declare function extractPlaceholders(message: string): string[];
|
|
11
14
|
/** Extract unique HTML tag names from a message, lowercased and sorted */
|
|
12
15
|
export declare function extractHtmlTags(message: string): string[];
|
package/dist/validation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAOD;;;8CAG8C;AAC9C,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA8B7D;AAiBD,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQzD;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAgCzF;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAclC"}
|
package/dist/vue-extractor.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./extract-cache-
|
|
2
|
-
`).length-1;for(let e of s)i.push({...e,origin:{...e.origin,line:e.origin.line+c}})}return i}function g(t,r,i){let a=[],{descriptor:o}=(0,n.parse)(t,{filename:r});if(o.template?.ast&&f(o.template.ast,r,a,i),o.template?.content){let t=e.t(o.template.content,r,i),n=o.template.loc.start.line-1,s=new Set(a.map(e=>e.id));for(let e of t)s.has(e.id)||a.push({...e,origin:{...e.origin,line:e.origin.line+n}});let c=h(o.template.content,r,i);for(let e of c
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./extract-cache-CGSKwh76.cjs`);const e=require(`./tsx-extractor-BOD7JJQK.cjs`);let t=require(`@fluenti/core/transform`),n=require(`@vue/compiler-sfc`);var r=1,i=2,a=7,o=6;function s(e){return e.filter(e=>e.type===i).map(e=>(e.content??``).trim()).join(``)}function c(e,t){let n=e.split(`|`).map(e=>e.trim()),r=[`one`,`other`,`zero`,`few`,`many`],i=[];if(n.length===2)i.push(`one {${n[0]}}`),i.push(`other {${n[1]}}`);else for(let e=0;e<n.length&&e<r.length;e++)i.push(`${r[e]} {${n[e]}}`);return`{${t}, plural, ${i.join(` `)}}`}var l=new Set([`id`,`value`,`context`,`comment`,`options`,`other`,`tag`]);function u(e,t,n){let r=[];for(let[e,n]of Object.entries(t))r.push(`${e} {${n}}`);return r.push(`other {${n}}`),`{${e}, select, ${r.join(` `)}}`}function d(e){let t=e.count??`count`,n=[`zero`,`one`,`two`,`few`,`many`,`other`],r=[],i=e.offset;for(let t of n)if(e[t]!==void 0){let n=t===`zero`?`=0`:t;r.push(`${n} {${e[t]}}`)}return r.length===0?``:`{${t}, plural, ${i?`offset:${i} `:``}${r.join(` `)}}`}function f(e,n,i,h){if(e.type===r){let r=e.props?.find(e=>e.type===a&&m(e)===`t`);if(r){let a=new Set([`plural`]),o=(r.modifiers??[]).map(e=>typeof e==`string`?e:e.content),l=o.includes(`plural`),u=o.filter(e=>!a.has(e)),d=r.arg?.content,f=d?[d,...u].join(`.`):void 0,p=s(e.children??[]);if(l){let e=c(p,r.exp?.content??`count`),a=f??(h??t.createMessageId)(e);i.push({id:a,message:e,origin:{file:n,line:r.loc.start.line,column:r.loc.start.column}})}else if(p){let e=f??(h??t.createMessageId)(p);i.push({id:e,message:p,origin:{file:n,line:r.loc.start.line,column:r.loc.start.column}})}}if(e.tag===`Trans`){let r=e.props?.find(e=>e.type===o&&m(e)===`message`),a=e.props?.find(e=>e.type===o&&m(e)===`id`),s=e.props?.find(e=>e.type===o&&m(e)===`context`),c=e.props?.find(e=>e.type===o&&m(e)===`comment`),l=s?.value?.content,u=c?.value?.content;if(r?.value){let o=r.value.content,s=h??t.createMessageId,c=a?.value?.content??s(o,l);i.push({id:c,message:o,...l===void 0?{}:{context:l},...u===void 0?{}:{comment:u},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}else if(e.children&&e.children.length>0){let r=p(e.children);if(r.message){let o=h??t.createMessageId,s=a?.value?.content??o(r.message,l);i.push({id:s,message:r.message,...l===void 0?{}:{context:l},...u===void 0?{}:{comment:u},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}}if(e.tag===`Plural`){let r={},s,c;for(let t of e.props??[])t.type===o&&t.value&&(r[m(t)]=t.value.content),t.type===a&&m(t)===`bind`&&t.arg?.content===`value`&&t.exp&&(s=t.exp.content),t.type===a&&m(t)===`bind`&&t.arg?.content===`offset`&&t.exp&&(c=t.exp.content);let l=s??r.count??`count`,u=c??r.offset,f=d({...r,count:l,...u===void 0?{}:{offset:u}});if(f){let a=r.id??(h??t.createMessageId)(f);i.push({id:a,message:f,origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}if(e.tag===`Select`){let r,s,c,d,f,p={};for(let t of e.props??[]){if(t.type===o&&t.value){let e=m(t);if(e===`id`){s=t.value.content;continue}if(e===`context`){c=t.value.content;continue}if(e===`comment`){d=t.value.content;continue}if(e===`other`){f=t.value.content;continue}if(l.has(e))continue;p[e]=t.value.content}t.type===a&&m(t)===`bind`&&t.arg?.content===`value`&&t.exp&&(r=t.exp.content)}if(r&&f&&Object.keys(p).length>0){let a=u(r,p,f),o=s??(h??t.createMessageId)(a,c);i.push({id:o,message:a,...c===void 0?{}:{context:c},...d===void 0?{}:{comment:d},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}}if(e.children)for(let t of e.children)f(t,n,i,h)}function p(e){let t=0,n=!1;return{message:e.map(e=>{if(e.type===i)return(e.content??``).trim()?e.content??``:``;if(e.type===r&&e.tag){n=!0;let r=t++;return`<${r}>${p(e.children??[]).message}</${r}>`}return``}).join(``).trim(),hasElements:n}}function m(e){return typeof e.name==`string`?e.name:e.name.content}function h(t,n,r){let i=[],a=/\{\{([\s\S]*?)\}\}/g,o;for(;(o=a.exec(t))!==null;){let a=o[1]?.trim();if(!a)continue;let s=e.t(a,n,r);if(s.length===0)continue;let c=t.slice(0,o.index).split(`
|
|
2
|
+
`).length-1;for(let e of s)i.push({...e,origin:{...e.origin,line:e.origin.line+c}})}return i}function g(t,r,i){let a=[],{descriptor:o}=(0,n.parse)(t,{filename:r});if(o.template?.ast&&f(o.template.ast,r,a,i),o.template?.content){let t=e.t(o.template.content,r,i),n=o.template.loc.start.line-1,s=new Set(a.map(e=>e.id));for(let e of t)s.has(e.id)||a.push({...e,origin:{...e.origin,line:e.origin.line+n}});let c=new Set(a.map(e=>e.id)),l=h(o.template.content,r,i);for(let e of l)c.has(e.id)||a.push({...e,origin:{...e.origin,line:e.origin.line+n}})}if(o.scriptSetup?.content){let t=e.t(o.scriptSetup.content,r,i),n=o.scriptSetup.loc.start.line-1;for(let e of t)a.push({...e,origin:{...e.origin,line:e.origin.line+n}})}if(o.script?.content){let t=e.t(o.script.content,r,i),n=o.script.loc.start.line-1;for(let e of t)a.push({...e,origin:{...e.origin,line:e.origin.line+n}})}return a}exports.extractFromVue=g;
|
|
3
3
|
//# sourceMappingURL=vue-extractor.cjs.map
|