@vocoder/cli 0.1.11 → 0.1.13

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.
@@ -92,12 +92,13 @@ function getPackagesToInstall(detection) {
92
92
 
93
93
  // src/utils/setup-snippets.ts
94
94
  function getSetupSnippets(params) {
95
- const { framework, ecosystem, sourceLocale, translationTriggers } = params;
95
+ const { framework, ecosystem, sourceLocale, branchTriggers } = params;
96
+ const allTriggers = [...new Set(branchTriggers.flatMap((b) => b.triggers))];
96
97
  return {
97
98
  pluginStep: getPluginSnippet(framework, ecosystem),
98
99
  providerStep: getProviderSnippet(ecosystem, sourceLocale),
99
100
  wrapStep: getWrapSnippet(ecosystem),
100
- whatsNext: getWhatsNextMessage(translationTriggers)
101
+ whatsNext: getWhatsNextMessage(allTriggers)
101
102
  };
102
103
  }
103
104
  function getPluginSnippet(framework, ecosystem) {
@@ -543,4 +544,4 @@ export {
543
544
  getSetupSnippets,
544
545
  StringExtractor
545
546
  };
546
- //# sourceMappingURL=chunk-OC5N5C5X.mjs.map
547
+ //# sourceMappingURL=chunk-KPIT5ETY.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/detect-local.ts","../src/utils/setup-snippets.ts","../src/utils/extract.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\nexport type DetectedFramework =\n | 'nextjs'\n | 'vite'\n | 'remix'\n | 'nuxt'\n | 'sveltekit'\n | 'gatsby'\n | 'angular'\n | null;\n\nexport type DetectedEcosystem =\n | 'react'\n | 'vue'\n | 'svelte'\n | 'angular'\n | null;\n\nexport interface LocalDetectionResult {\n ecosystem: DetectedEcosystem;\n framework: DetectedFramework;\n packageManager: PackageManager;\n uiPackage: string | null;\n hasUnplugin: boolean;\n hasUiPackage: boolean;\n sourceLocale: string | null;\n}\n\n/**\n * Detect the local project's ecosystem, framework, and package manager\n * by inspecting filesystem artifacts. No network calls.\n */\nexport function detectLocalEcosystem(cwd: string = process.cwd()): LocalDetectionResult {\n const packageManager = detectPackageManager(cwd);\n const pkg = readPackageJson(cwd);\n\n if (!pkg) {\n return {\n ecosystem: null,\n framework: null,\n packageManager,\n uiPackage: null,\n hasUnplugin: false,\n hasUiPackage: false,\n sourceLocale: null,\n };\n }\n\n const allDeps = {\n ...((pkg.dependencies as Record<string, string>) ?? {}),\n ...((pkg.devDependencies as Record<string, string>) ?? {}),\n };\n\n const hasUnplugin = '@vocoder/unplugin' in allDeps;\n\n // Detect ecosystem + framework\n const { ecosystem, framework, uiPackage } = detectFromDeps(allDeps, cwd);\n const hasUiPackage = uiPackage !== null && uiPackage in allDeps;\n\n return {\n ecosystem,\n framework,\n packageManager,\n uiPackage,\n hasUnplugin,\n hasUiPackage,\n sourceLocale: null,\n };\n}\n\nfunction detectPackageManager(cwd: string): PackageManager {\n if (existsSync(join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(join(cwd, 'bun.lockb')) || existsSync(join(cwd, 'bun.lock'))) return 'bun';\n if (existsSync(join(cwd, 'yarn.lock'))) return 'yarn';\n return 'npm';\n}\n\nfunction readPackageJson(cwd: string): Record<string, unknown> | null {\n const pkgPath = join(cwd, 'package.json');\n if (!existsSync(pkgPath)) return null;\n try {\n return JSON.parse(readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction detectFromDeps(\n allDeps: Record<string, string>,\n cwd: string,\n): { ecosystem: DetectedEcosystem; framework: DetectedFramework; uiPackage: string | null } {\n // Vue ecosystem\n if ('vue' in allDeps) {\n const framework = 'nuxt' in allDeps ? 'nuxt' as const : null;\n return { ecosystem: 'vue', framework, uiPackage: '@vocoder/vue' };\n }\n\n // Svelte ecosystem\n if ('svelte' in allDeps) {\n const framework = '@sveltejs/kit' in allDeps ? 'sveltekit' as const : null;\n return { ecosystem: 'svelte', framework, uiPackage: '@vocoder/svelte' };\n }\n\n // Angular ecosystem\n if ('@angular/core' in allDeps || existsSync(join(cwd, 'angular.json'))) {\n return { ecosystem: 'angular', framework: 'angular', uiPackage: '@vocoder/angular' };\n }\n\n // React ecosystem (most common — check last)\n if ('react' in allDeps) {\n let framework: DetectedFramework = null;\n if ('next' in allDeps) framework = 'nextjs';\n else if ('@remix-run/react' in allDeps) framework = 'remix';\n else if ('gatsby' in allDeps) framework = 'gatsby';\n else if ('vite' in allDeps) framework = 'vite';\n return { ecosystem: 'react', framework, uiPackage: '@vocoder/react' };\n }\n\n return { ecosystem: null, framework: null, uiPackage: null };\n}\n\n/**\n * Build the install command for packages that aren't already installed.\n */\nexport function buildInstallCommand(\n packageManager: PackageManager,\n packages: string[],\n): string {\n if (packages.length === 0) return '';\n const pkgList = packages.join(' ');\n switch (packageManager) {\n case 'pnpm':\n return `pnpm add ${pkgList}`;\n case 'yarn':\n return `yarn add ${pkgList}`;\n case 'bun':\n return `bun add ${pkgList}`;\n default:\n return `npm install ${pkgList}`;\n }\n}\n\n/**\n * Get the list of packages that need to be installed.\n */\nexport function getPackagesToInstall(detection: LocalDetectionResult): string[] {\n const packages: string[] = [];\n if (!detection.hasUnplugin) packages.push('@vocoder/unplugin');\n if (detection.uiPackage && !detection.hasUiPackage) packages.push(detection.uiPackage);\n return packages;\n}\n","import type { DetectedEcosystem, DetectedFramework } from './detect-local.js';\n\nexport interface SetupSnippets {\n pluginStep: { file: string; code: string } | null;\n providerStep: { file: string; code: string } | null;\n wrapStep: { code: string };\n whatsNext: string;\n}\n\n/**\n * Generate framework-specific setup snippets.\n */\nexport function getSetupSnippets(params: {\n framework: DetectedFramework;\n ecosystem: DetectedEcosystem;\n sourceLocale: string;\n branchTriggers: Array<{ pattern: string; triggers: string[] }>;\n}): SetupSnippets {\n const { framework, ecosystem, sourceLocale, branchTriggers } = params;\n // Collect the union of all triggers across all branch configs\n const allTriggers = [...new Set(branchTriggers.flatMap((b) => b.triggers))];\n\n return {\n pluginStep: getPluginSnippet(framework, ecosystem),\n providerStep: getProviderSnippet(ecosystem, sourceLocale),\n wrapStep: getWrapSnippet(ecosystem),\n whatsNext: getWhatsNextMessage(allTriggers),\n };\n}\n\nfunction getPluginSnippet(\n framework: DetectedFramework,\n ecosystem: DetectedEcosystem,\n): { file: string; code: string } | null {\n switch (framework) {\n case 'nextjs':\n return {\n file: 'next.config.ts',\n code: `import { withVocoder } from '@vocoder/unplugin/next';\n\nexport default withVocoder({\n // your existing Next.js config\n});`,\n };\n\n case 'vite':\n case 'remix':\n return {\n file: 'vite.config.ts',\n code: `import vocoder from '@vocoder/unplugin/vite';\n\nexport default defineConfig({\n plugins: [\n vocoder(),\n // your other plugins\n ],\n});`,\n };\n\n case 'nuxt':\n return {\n file: 'nuxt.config.ts',\n code: `import vocoder from '@vocoder/unplugin/vite';\n\nexport default defineNuxtConfig({\n vite: {\n plugins: [vocoder()],\n },\n});`,\n };\n\n case 'sveltekit':\n return {\n file: 'vite.config.ts',\n code: `import vocoder from '@vocoder/unplugin/vite';\nimport { sveltekit } from '@sveltejs/kit/vite';\n\nexport default defineConfig({\n plugins: [\n sveltekit(),\n vocoder(),\n ],\n});`,\n };\n\n case 'gatsby':\n return {\n file: 'gatsby-node.js',\n code: `const vocoder = require('@vocoder/unplugin/webpack');\n\nexports.onCreateWebpackConfig = ({ actions }) => {\n actions.setWebpackConfig({\n plugins: [vocoder()],\n });\n};`,\n };\n\n case 'angular':\n return null; // Angular CLI doesn't expose plugin config easily\n\n default:\n // No known framework — if they have React/Vue/Svelte, they likely have a bundler\n // but we can't guess which config file. Give generic advice.\n if (ecosystem) {\n return {\n file: 'your bundler config',\n code: `// Vite\nimport vocoder from '@vocoder/unplugin/vite';\n// Webpack\nconst vocoder = require('@vocoder/unplugin/webpack');\n\n// Add vocoder() to your plugins array`,\n };\n }\n return null;\n }\n}\n\nfunction getProviderSnippet(\n ecosystem: DetectedEcosystem,\n sourceLocale: string,\n): { file: string; code: string } | null {\n switch (ecosystem) {\n case 'react':\n return {\n file: 'your root layout or App component',\n code: `import { VocoderProvider } from '@vocoder/react';\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n {children}\n</VocoderProvider>`,\n };\n\n case 'vue':\n return {\n file: 'your app entry',\n code: `import { createVocoder } from '@vocoder/vue';\n\nconst vocoder = createVocoder({\n defaultLocale: '${sourceLocale}',\n});\n\napp.use(vocoder);`,\n };\n\n case 'svelte':\n return {\n file: 'your root layout',\n code: `<script>\n import { VocoderProvider } from '@vocoder/svelte';\n</script>\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n <slot />\n</VocoderProvider>`,\n };\n\n default:\n return null;\n }\n}\n\nfunction getWrapSnippet(ecosystem: DetectedEcosystem): { code: string } {\n switch (ecosystem) {\n case 'react':\n return {\n code: `import { T } from '@vocoder/react';\n\n<T>Hello, world!</T>`,\n };\n\n case 'vue':\n return {\n code: `<template>\n <T>Hello, world!</T>\n</template>\n\n<script setup>\nimport { T } from '@vocoder/vue';\n</script>`,\n };\n\n case 'svelte':\n return {\n code: `<script>\n import { T } from '@vocoder/svelte';\n</script>\n\n<T>Hello, world!</T>`,\n };\n\n default:\n return {\n code: `// Wrap translatable strings with <T>\n<T>Hello, world!</T>`,\n };\n }\n}\n\nfunction getWhatsNextMessage(triggers: string[]): string {\n const parts: string[] = [];\n\n if (triggers.includes('push')) {\n parts.push('Push to a target branch to trigger translations.');\n }\n if (triggers.includes('pull_request')) {\n parts.push('Open a pull request to trigger translations.');\n }\n if (triggers.includes('manual')) {\n parts.push('Run `vocoder sync` to extract and translate.');\n }\n\n // Fallback for unknown or empty triggers\n if (parts.length === 0) {\n parts.push('Push to a target branch to trigger translations.');\n }\n\n return parts.join('\\n');\n}\n","import { createHash } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { parse } from '@babel/parser';\nimport babelTraverse from '@babel/traverse';\nimport { glob } from 'glob';\nimport { relative as pathRelative } from 'path';\nimport type { ExtractedString } from '../types.js';\n\n// Handle default export difference between ESM and CommonJS\nconst traverse = (babelTraverse as any).default || babelTraverse;\n\n/**\n * Extract translatable strings from source files\n *\n * NOTE: This is a simplified version for the CLI MVP.\n * Eventually this logic should be moved to a shared @vocoder/extraction package\n * that can be used by both the CLI and the backend.\n */\nexport class StringExtractor {\n /**\n * Extract strings from all files matching the pattern(s)\n *\n * @param pattern - Glob pattern(s) to include\n * @param projectRoot - Project root directory\n * @param excludePattern - Glob pattern(s) to exclude (optional)\n */\n async extractFromProject(\n pattern: string | string[],\n projectRoot: string = process.cwd(),\n excludePattern?: string | string[],\n ): Promise<ExtractedString[]> {\n // Normalize patterns to arrays\n const includePatterns = Array.isArray(pattern) ? pattern : [pattern];\n\n // Default ignore patterns (always excluded)\n const defaultIgnore = ['**/node_modules/**', '**/.next/**', '**/dist/**', '**/build/**'];\n\n // Merge user exclude patterns with defaults\n const ignorePatterns = excludePattern\n ? [...defaultIgnore, ...(Array.isArray(excludePattern) ? excludePattern : [excludePattern])]\n : defaultIgnore;\n\n // Find all files matching any of the include patterns (OR behavior)\n const allFiles = new Set<string>();\n\n for (const includePattern of includePatterns) {\n const files = await glob(includePattern, {\n cwd: projectRoot,\n absolute: true,\n ignore: ignorePatterns,\n });\n\n files.forEach((file: string) => allFiles.add(file));\n }\n\n const allStrings: ExtractedString[] = [];\n\n // Extract from each file\n const sortedFiles = Array.from(allFiles).sort();\n\n for (const file of sortedFiles) {\n try {\n const strings = await this.extractFromFile(file, projectRoot);\n allStrings.push(...strings);\n } catch (error) {\n console.warn(`Warning: Failed to extract from ${file}:`, error);\n }\n }\n\n // Deduplicate strings (same text = one entry)\n const unique = this.deduplicateStrings(allStrings);\n\n return unique;\n }\n\n /**\n * Extract strings from a single file\n */\n private async extractFromFile(\n filePath: string,\n projectRoot: string,\n ): Promise<ExtractedString[]> {\n const code = readFileSync(filePath, 'utf-8');\n const strings: ExtractedString[] = [];\n const relativeFilePath = pathRelative(projectRoot, filePath).split('\\\\').join('/');\n\n try {\n // Parse the code\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n // Track imports from @vocoder/react\n const vocoderImports = new Map<string, string>();\n const tFunctionNames = new Set<string>(); // Track 't' function names\n\n // Traverse the AST\n traverse(ast, {\n // Track imports of <T> component and t function\n ImportDeclaration: (path: any) => {\n const source = path.node.source.value;\n\n if (source === '@vocoder/react') {\n path.node.specifiers.forEach((spec: any) => {\n if (spec.type === 'ImportSpecifier') {\n const imported =\n spec.imported.type === 'Identifier'\n ? spec.imported.name\n : null;\n const local = spec.local.name;\n\n if (imported === 'T') {\n vocoderImports.set(local, 'T');\n }\n // Track direct import of 't' function\n if (imported === 't') {\n tFunctionNames.add(local);\n }\n // Track useVocoder hook (which provides 't')\n if (imported === 'useVocoder') {\n // We'll track destructured 't' in VariableDeclarator\n }\n }\n });\n }\n },\n\n // Track destructured 't' from useVocoder hook\n VariableDeclarator: (path: any) => {\n const init = path.node.init;\n\n // Check if this is: const { t } = useVocoder()\n if (\n init &&\n init.type === 'CallExpression' &&\n init.callee.type === 'Identifier' &&\n init.callee.name === 'useVocoder' &&\n path.node.id.type === 'ObjectPattern'\n ) {\n path.node.id.properties.forEach((prop: any) => {\n if (\n prop.type === 'ObjectProperty' &&\n prop.key.type === 'Identifier' &&\n prop.key.name === 't'\n ) {\n const localName =\n prop.value.type === 'Identifier' ? prop.value.name : 't';\n tFunctionNames.add(localName);\n }\n });\n }\n },\n\n // Extract from t() function calls\n CallExpression: (path: any) => {\n const callee = path.node.callee;\n\n // Check if this is a call to 't' function\n const isTFunction =\n callee.type === 'Identifier' && tFunctionNames.has(callee.name);\n\n if (!isTFunction) return;\n\n // Get the first argument (the string to translate)\n const firstArg = path.node.arguments[0];\n if (!firstArg) return;\n\n let text: string | null = null;\n\n // Handle string literal: t('Hello')\n if (firstArg.type === 'StringLiteral') {\n text = firstArg.value;\n }\n // Handle template literal: t(`Hello ${name}`)\n else if (firstArg.type === 'TemplateLiteral') {\n text = this.extractTemplateText(firstArg);\n }\n\n if (!text || text.trim().length === 0) return;\n\n // Get options from second argument\n const secondArg = path.node.arguments[1];\n let context: string | undefined;\n let formality: 'formal' | 'informal' | 'neutral' | 'auto' | undefined;\n let explicitKey: string | undefined;\n\n if (secondArg && secondArg.type === 'ObjectExpression') {\n secondArg.properties.forEach((prop: any) => {\n if (prop.type === 'ObjectProperty' && prop.key.type === 'Identifier') {\n if (prop.key.name === 'context' && prop.value.type === 'StringLiteral') {\n context = prop.value.value;\n }\n if (prop.key.name === 'formality' && prop.value.type === 'StringLiteral') {\n formality = prop.value.value as 'formal' | 'informal' | 'neutral' | 'auto';\n }\n if (prop.key.name === 'id' && prop.value.type === 'StringLiteral') {\n explicitKey = prop.value.value.trim();\n }\n }\n });\n }\n\n const line = path.node.loc?.start.line || 0;\n const column = path.node.loc?.start.column || 0;\n const key = explicitKey && explicitKey.length > 0\n ? explicitKey\n : this.generateStableKey({\n filePath: relativeFilePath,\n kind: 't-call',\n line,\n column,\n });\n\n strings.push({\n key,\n text: text.trim(),\n file: filePath,\n line,\n context,\n formality,\n });\n },\n\n // Extract from JSX elements\n JSXElement: (path: any) => {\n const opening = path.node.openingElement;\n const tagName =\n opening.name.type === 'JSXIdentifier'\n ? opening.name.name\n : null;\n\n if (!tagName) return;\n\n // Check if this is a <T> component (or aliased import)\n const isTranslationComponent = vocoderImports.has(tagName);\n\n if (!isTranslationComponent) return;\n\n // Check for msg attribute first (preferred for ICU messages)\n const msgAttribute = this.getStringAttribute(opening.attributes, 'msg');\n\n // Extract text - prefer msg attribute over children\n const text = msgAttribute || this.extractTextContent(path.node.children);\n\n if (!text || text.trim().length === 0) return;\n\n // Extract context and formality from props\n const id = this.getStringAttribute(opening.attributes, 'id');\n const context = this.getStringAttribute(opening.attributes, 'context');\n const formality = this.getStringAttribute(\n opening.attributes,\n 'formality',\n ) as 'formal' | 'informal' | 'neutral' | 'auto' | undefined;\n const line = path.node.loc?.start.line || 0;\n const column = path.node.loc?.start.column || 0;\n const key = id && id.trim().length > 0\n ? id.trim()\n : this.generateStableKey({\n filePath: relativeFilePath,\n kind: 'jsx',\n line,\n column,\n });\n\n strings.push({\n key,\n text: text.trim(),\n file: filePath,\n line,\n context,\n formality,\n });\n },\n });\n } catch (error) {\n throw new Error(\n `Failed to parse ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n\n return strings;\n }\n\n /**\n * Extract text from template literal\n * Converts template literals like `Hello ${name}` to `Hello {name}`\n */\n private extractTemplateText(node: any): string {\n let text = '';\n\n for (let i = 0; i < node.quasis.length; i++) {\n const quasi = node.quasis[i];\n text += quasi.value.raw;\n\n // Add placeholder for expressions\n if (i < node.expressions.length) {\n const expr = node.expressions[i];\n if (expr.type === 'Identifier') {\n text += `{${expr.name}}`;\n } else {\n // For complex expressions, use generic placeholder\n text += '{value}';\n }\n }\n }\n\n return text;\n }\n\n /**\n * Extract text content from JSX children\n */\n private extractTextContent(children: any[]): string {\n let text = '';\n\n for (const child of children) {\n if (child.type === 'JSXText') {\n text += child.value;\n } else if (child.type === 'JSXExpressionContainer') {\n const expr = child.expression;\n\n // Handle {variableName} - actual identifier\n if (expr.type === 'Identifier') {\n text += `{${expr.name}}`;\n }\n // Handle {\"{variableName}\"} - string literal placeholder\n else if (expr.type === 'StringLiteral') {\n text += expr.value;\n }\n // Handle {`${variableName}`} - template literal\n // Convert template literal syntax to ICU MessageFormat: `$${price}` → ${price}\n else if (expr.type === 'TemplateLiteral') {\n text += this.extractTemplateText(expr);\n }\n }\n }\n\n return text;\n }\n\n /**\n * Get string value from JSX attribute\n * Handles both string literals and template literals\n */\n private getStringAttribute(\n attributes: any[],\n name: string,\n ): string | undefined {\n const attr = attributes.find(\n (a) => a.type === 'JSXAttribute' && a.name.name === name,\n );\n\n if (!attr || !attr.value) return undefined;\n\n // Handle string literal: msg=\"Hello\"\n if (attr.value.type === 'StringLiteral') {\n return attr.value.value;\n }\n\n // Handle JSX expression container: msg={...}\n if (attr.value.type === 'JSXExpressionContainer') {\n const expr = attr.value.expression;\n\n // Handle template literal: msg={`Hello ${name}`}\n if (expr.type === 'TemplateLiteral') {\n return this.extractTemplateText(expr);\n }\n\n // Handle string literal in expression: msg={'Hello'}\n if (expr.type === 'StringLiteral') {\n return expr.value;\n }\n }\n\n return undefined;\n }\n\n /**\n * Deduplicate strings (keep first occurrence)\n */\n private deduplicateStrings(strings: ExtractedString[]): ExtractedString[] {\n const seen = new Map<string, number>();\n const unique: ExtractedString[] = [];\n\n for (const str of strings) {\n // Create a key based on text + context + formality\n const dedupeKey = `${str.text}|${str.context || ''}|${str.formality || ''}`;\n\n const existingIndex = seen.get(dedupeKey);\n if (existingIndex === undefined) {\n seen.set(dedupeKey, unique.length);\n unique.push(str);\n continue;\n }\n\n // Keep the lexicographically smallest key for deterministic stability\n const existing = unique[existingIndex];\n if (existing && str.key < existing.key) {\n existing.key = str.key;\n }\n }\n\n return unique;\n }\n\n private generateStableKey(params: {\n filePath: string;\n kind: 'jsx' | 't-call';\n line: number;\n column: number;\n }): string {\n const payload = `${params.filePath}|${params.kind}|${params.line}:${params.column}`;\n const digest = createHash('sha1').update(payload).digest('hex');\n return `SK_${digest.slice(0, 24).toUpperCase()}`;\n }\n}\n"],"mappings":"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","names":["readFileSync"]}
package/dist/lib.d.mts CHANGED
@@ -5,12 +5,18 @@ interface SyncPolicyConfig {
5
5
  nonBlockingMode: EffectiveSyncMode;
6
6
  defaultMaxWaitMs: number;
7
7
  }
8
+ interface BranchTriggerConfig {
9
+ pattern: string;
10
+ triggers: string[];
11
+ }
8
12
  interface APIProjectConfig {
9
13
  projectName: string;
10
14
  organizationName: string;
11
15
  sourceLocale: string;
12
16
  targetLocales: string[];
13
- targetBranches: string[];
17
+ branchTriggers: BranchTriggerConfig[];
18
+ /** Primary branch derived from branchTriggers (first non-wildcard pattern) */
19
+ primaryBranch?: string;
14
20
  syncPolicy: SyncPolicyConfig;
15
21
  }
16
22
  interface ExtractedString {
@@ -76,7 +82,6 @@ interface SyncPolicyErrorResponse {
76
82
  errorCode: 'BRANCH_NOT_ALLOWED' | 'PROJECT_REPOSITORY_MISMATCH';
77
83
  message: string;
78
84
  branch?: string;
79
- targetBranches?: string[];
80
85
  boundRepoLabel?: string | null;
81
86
  boundScopePath?: string | null;
82
87
  }
@@ -169,7 +174,10 @@ declare function getSetupSnippets(params: {
169
174
  framework: DetectedFramework;
170
175
  ecosystem: DetectedEcosystem;
171
176
  sourceLocale: string;
172
- translationTriggers: string[];
177
+ branchTriggers: Array<{
178
+ pattern: string;
179
+ triggers: string[];
180
+ }>;
173
181
  }): SetupSnippets;
174
182
 
175
183
  export { type APIProjectConfig, type DetectedEcosystem, type DetectedFramework, type ExtractedString, type LimitErrorResponse, type LocalDetectionResult, type PackageManager, type SetupSnippets, StringExtractor, type SyncPolicyConfig, type SyncPolicyErrorResponse, type TranslationBatchResponse, type TranslationSnapshotResponse, type TranslationStatusResponse, buildInstallCommand, detectLocalEcosystem, getPackagesToInstall, getSetupSnippets };
package/dist/lib.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  detectLocalEcosystem,
5
5
  getPackagesToInstall,
6
6
  getSetupSnippets
7
- } from "./chunk-OC5N5C5X.mjs";
7
+ } from "./chunk-KPIT5ETY.mjs";
8
8
  export {
9
9
  StringExtractor,
10
10
  buildInstallCommand,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocoder/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "CLI tool for Vocoder translation workflow",
5
5
  "files": [
6
6
  "dist"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/detect-local.ts","../src/utils/setup-snippets.ts","../src/utils/extract.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\nexport type DetectedFramework =\n | 'nextjs'\n | 'vite'\n | 'remix'\n | 'nuxt'\n | 'sveltekit'\n | 'gatsby'\n | 'angular'\n | null;\n\nexport type DetectedEcosystem =\n | 'react'\n | 'vue'\n | 'svelte'\n | 'angular'\n | null;\n\nexport interface LocalDetectionResult {\n ecosystem: DetectedEcosystem;\n framework: DetectedFramework;\n packageManager: PackageManager;\n uiPackage: string | null;\n hasUnplugin: boolean;\n hasUiPackage: boolean;\n sourceLocale: string | null;\n}\n\n/**\n * Detect the local project's ecosystem, framework, and package manager\n * by inspecting filesystem artifacts. No network calls.\n */\nexport function detectLocalEcosystem(cwd: string = process.cwd()): LocalDetectionResult {\n const packageManager = detectPackageManager(cwd);\n const pkg = readPackageJson(cwd);\n\n if (!pkg) {\n return {\n ecosystem: null,\n framework: null,\n packageManager,\n uiPackage: null,\n hasUnplugin: false,\n hasUiPackage: false,\n sourceLocale: null,\n };\n }\n\n const allDeps = {\n ...((pkg.dependencies as Record<string, string>) ?? {}),\n ...((pkg.devDependencies as Record<string, string>) ?? {}),\n };\n\n const hasUnplugin = '@vocoder/unplugin' in allDeps;\n\n // Detect ecosystem + framework\n const { ecosystem, framework, uiPackage } = detectFromDeps(allDeps, cwd);\n const hasUiPackage = uiPackage !== null && uiPackage in allDeps;\n\n return {\n ecosystem,\n framework,\n packageManager,\n uiPackage,\n hasUnplugin,\n hasUiPackage,\n sourceLocale: null,\n };\n}\n\nfunction detectPackageManager(cwd: string): PackageManager {\n if (existsSync(join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(join(cwd, 'bun.lockb')) || existsSync(join(cwd, 'bun.lock'))) return 'bun';\n if (existsSync(join(cwd, 'yarn.lock'))) return 'yarn';\n return 'npm';\n}\n\nfunction readPackageJson(cwd: string): Record<string, unknown> | null {\n const pkgPath = join(cwd, 'package.json');\n if (!existsSync(pkgPath)) return null;\n try {\n return JSON.parse(readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction detectFromDeps(\n allDeps: Record<string, string>,\n cwd: string,\n): { ecosystem: DetectedEcosystem; framework: DetectedFramework; uiPackage: string | null } {\n // Vue ecosystem\n if ('vue' in allDeps) {\n const framework = 'nuxt' in allDeps ? 'nuxt' as const : null;\n return { ecosystem: 'vue', framework, uiPackage: '@vocoder/vue' };\n }\n\n // Svelte ecosystem\n if ('svelte' in allDeps) {\n const framework = '@sveltejs/kit' in allDeps ? 'sveltekit' as const : null;\n return { ecosystem: 'svelte', framework, uiPackage: '@vocoder/svelte' };\n }\n\n // Angular ecosystem\n if ('@angular/core' in allDeps || existsSync(join(cwd, 'angular.json'))) {\n return { ecosystem: 'angular', framework: 'angular', uiPackage: '@vocoder/angular' };\n }\n\n // React ecosystem (most common — check last)\n if ('react' in allDeps) {\n let framework: DetectedFramework = null;\n if ('next' in allDeps) framework = 'nextjs';\n else if ('@remix-run/react' in allDeps) framework = 'remix';\n else if ('gatsby' in allDeps) framework = 'gatsby';\n else if ('vite' in allDeps) framework = 'vite';\n return { ecosystem: 'react', framework, uiPackage: '@vocoder/react' };\n }\n\n return { ecosystem: null, framework: null, uiPackage: null };\n}\n\n/**\n * Build the install command for packages that aren't already installed.\n */\nexport function buildInstallCommand(\n packageManager: PackageManager,\n packages: string[],\n): string {\n if (packages.length === 0) return '';\n const pkgList = packages.join(' ');\n switch (packageManager) {\n case 'pnpm':\n return `pnpm add ${pkgList}`;\n case 'yarn':\n return `yarn add ${pkgList}`;\n case 'bun':\n return `bun add ${pkgList}`;\n default:\n return `npm install ${pkgList}`;\n }\n}\n\n/**\n * Get the list of packages that need to be installed.\n */\nexport function getPackagesToInstall(detection: LocalDetectionResult): string[] {\n const packages: string[] = [];\n if (!detection.hasUnplugin) packages.push('@vocoder/unplugin');\n if (detection.uiPackage && !detection.hasUiPackage) packages.push(detection.uiPackage);\n return packages;\n}\n","import type { DetectedEcosystem, DetectedFramework } from './detect-local.js';\n\nexport interface SetupSnippets {\n pluginStep: { file: string; code: string } | null;\n providerStep: { file: string; code: string } | null;\n wrapStep: { code: string };\n whatsNext: string;\n}\n\n/**\n * Generate framework-specific setup snippets.\n */\nexport function getSetupSnippets(params: {\n framework: DetectedFramework;\n ecosystem: DetectedEcosystem;\n sourceLocale: string;\n translationTriggers: string[];\n}): SetupSnippets {\n const { framework, ecosystem, sourceLocale, translationTriggers } = params;\n\n return {\n pluginStep: getPluginSnippet(framework, ecosystem),\n providerStep: getProviderSnippet(ecosystem, sourceLocale),\n wrapStep: getWrapSnippet(ecosystem),\n whatsNext: getWhatsNextMessage(translationTriggers),\n };\n}\n\nfunction getPluginSnippet(\n framework: DetectedFramework,\n ecosystem: DetectedEcosystem,\n): { file: string; code: string } | null {\n switch (framework) {\n case 'nextjs':\n return {\n file: 'next.config.ts',\n code: `import { withVocoder } from '@vocoder/unplugin/next';\n\nexport default withVocoder({\n // your existing Next.js config\n});`,\n };\n\n case 'vite':\n case 'remix':\n return {\n file: 'vite.config.ts',\n code: `import vocoder from '@vocoder/unplugin/vite';\n\nexport default defineConfig({\n plugins: [\n vocoder(),\n // your other plugins\n ],\n});`,\n };\n\n case 'nuxt':\n return {\n file: 'nuxt.config.ts',\n code: `import vocoder from '@vocoder/unplugin/vite';\n\nexport default defineNuxtConfig({\n vite: {\n plugins: [vocoder()],\n },\n});`,\n };\n\n case 'sveltekit':\n return {\n file: 'vite.config.ts',\n code: `import vocoder from '@vocoder/unplugin/vite';\nimport { sveltekit } from '@sveltejs/kit/vite';\n\nexport default defineConfig({\n plugins: [\n sveltekit(),\n vocoder(),\n ],\n});`,\n };\n\n case 'gatsby':\n return {\n file: 'gatsby-node.js',\n code: `const vocoder = require('@vocoder/unplugin/webpack');\n\nexports.onCreateWebpackConfig = ({ actions }) => {\n actions.setWebpackConfig({\n plugins: [vocoder()],\n });\n};`,\n };\n\n case 'angular':\n return null; // Angular CLI doesn't expose plugin config easily\n\n default:\n // No known framework — if they have React/Vue/Svelte, they likely have a bundler\n // but we can't guess which config file. Give generic advice.\n if (ecosystem) {\n return {\n file: 'your bundler config',\n code: `// Vite\nimport vocoder from '@vocoder/unplugin/vite';\n// Webpack\nconst vocoder = require('@vocoder/unplugin/webpack');\n\n// Add vocoder() to your plugins array`,\n };\n }\n return null;\n }\n}\n\nfunction getProviderSnippet(\n ecosystem: DetectedEcosystem,\n sourceLocale: string,\n): { file: string; code: string } | null {\n switch (ecosystem) {\n case 'react':\n return {\n file: 'your root layout or App component',\n code: `import { VocoderProvider } from '@vocoder/react';\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n {children}\n</VocoderProvider>`,\n };\n\n case 'vue':\n return {\n file: 'your app entry',\n code: `import { createVocoder } from '@vocoder/vue';\n\nconst vocoder = createVocoder({\n defaultLocale: '${sourceLocale}',\n});\n\napp.use(vocoder);`,\n };\n\n case 'svelte':\n return {\n file: 'your root layout',\n code: `<script>\n import { VocoderProvider } from '@vocoder/svelte';\n</script>\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n <slot />\n</VocoderProvider>`,\n };\n\n default:\n return null;\n }\n}\n\nfunction getWrapSnippet(ecosystem: DetectedEcosystem): { code: string } {\n switch (ecosystem) {\n case 'react':\n return {\n code: `import { T } from '@vocoder/react';\n\n<T>Hello, world!</T>`,\n };\n\n case 'vue':\n return {\n code: `<template>\n <T>Hello, world!</T>\n</template>\n\n<script setup>\nimport { T } from '@vocoder/vue';\n</script>`,\n };\n\n case 'svelte':\n return {\n code: `<script>\n import { T } from '@vocoder/svelte';\n</script>\n\n<T>Hello, world!</T>`,\n };\n\n default:\n return {\n code: `// Wrap translatable strings with <T>\n<T>Hello, world!</T>`,\n };\n }\n}\n\nfunction getWhatsNextMessage(triggers: string[]): string {\n const parts: string[] = [];\n\n if (triggers.includes('push')) {\n parts.push('Push to a target branch to trigger translations.');\n }\n if (triggers.includes('pull_request')) {\n parts.push('Open a pull request to trigger translations.');\n }\n if (triggers.includes('manual')) {\n parts.push('Run `vocoder sync` to extract and translate.');\n }\n\n // Fallback for unknown or empty triggers\n if (parts.length === 0) {\n parts.push('Push to a target branch to trigger translations.');\n }\n\n return parts.join('\\n');\n}\n","import { createHash } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { parse } from '@babel/parser';\nimport babelTraverse from '@babel/traverse';\nimport { glob } from 'glob';\nimport { relative as pathRelative } from 'path';\nimport type { ExtractedString } from '../types.js';\n\n// Handle default export difference between ESM and CommonJS\nconst traverse = (babelTraverse as any).default || babelTraverse;\n\n/**\n * Extract translatable strings from source files\n *\n * NOTE: This is a simplified version for the CLI MVP.\n * Eventually this logic should be moved to a shared @vocoder/extraction package\n * that can be used by both the CLI and the backend.\n */\nexport class StringExtractor {\n /**\n * Extract strings from all files matching the pattern(s)\n *\n * @param pattern - Glob pattern(s) to include\n * @param projectRoot - Project root directory\n * @param excludePattern - Glob pattern(s) to exclude (optional)\n */\n async extractFromProject(\n pattern: string | string[],\n projectRoot: string = process.cwd(),\n excludePattern?: string | string[],\n ): Promise<ExtractedString[]> {\n // Normalize patterns to arrays\n const includePatterns = Array.isArray(pattern) ? pattern : [pattern];\n\n // Default ignore patterns (always excluded)\n const defaultIgnore = ['**/node_modules/**', '**/.next/**', '**/dist/**', '**/build/**'];\n\n // Merge user exclude patterns with defaults\n const ignorePatterns = excludePattern\n ? [...defaultIgnore, ...(Array.isArray(excludePattern) ? excludePattern : [excludePattern])]\n : defaultIgnore;\n\n // Find all files matching any of the include patterns (OR behavior)\n const allFiles = new Set<string>();\n\n for (const includePattern of includePatterns) {\n const files = await glob(includePattern, {\n cwd: projectRoot,\n absolute: true,\n ignore: ignorePatterns,\n });\n\n files.forEach((file: string) => allFiles.add(file));\n }\n\n const allStrings: ExtractedString[] = [];\n\n // Extract from each file\n const sortedFiles = Array.from(allFiles).sort();\n\n for (const file of sortedFiles) {\n try {\n const strings = await this.extractFromFile(file, projectRoot);\n allStrings.push(...strings);\n } catch (error) {\n console.warn(`Warning: Failed to extract from ${file}:`, error);\n }\n }\n\n // Deduplicate strings (same text = one entry)\n const unique = this.deduplicateStrings(allStrings);\n\n return unique;\n }\n\n /**\n * Extract strings from a single file\n */\n private async extractFromFile(\n filePath: string,\n projectRoot: string,\n ): Promise<ExtractedString[]> {\n const code = readFileSync(filePath, 'utf-8');\n const strings: ExtractedString[] = [];\n const relativeFilePath = pathRelative(projectRoot, filePath).split('\\\\').join('/');\n\n try {\n // Parse the code\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n // Track imports from @vocoder/react\n const vocoderImports = new Map<string, string>();\n const tFunctionNames = new Set<string>(); // Track 't' function names\n\n // Traverse the AST\n traverse(ast, {\n // Track imports of <T> component and t function\n ImportDeclaration: (path: any) => {\n const source = path.node.source.value;\n\n if (source === '@vocoder/react') {\n path.node.specifiers.forEach((spec: any) => {\n if (spec.type === 'ImportSpecifier') {\n const imported =\n spec.imported.type === 'Identifier'\n ? spec.imported.name\n : null;\n const local = spec.local.name;\n\n if (imported === 'T') {\n vocoderImports.set(local, 'T');\n }\n // Track direct import of 't' function\n if (imported === 't') {\n tFunctionNames.add(local);\n }\n // Track useVocoder hook (which provides 't')\n if (imported === 'useVocoder') {\n // We'll track destructured 't' in VariableDeclarator\n }\n }\n });\n }\n },\n\n // Track destructured 't' from useVocoder hook\n VariableDeclarator: (path: any) => {\n const init = path.node.init;\n\n // Check if this is: const { t } = useVocoder()\n if (\n init &&\n init.type === 'CallExpression' &&\n init.callee.type === 'Identifier' &&\n init.callee.name === 'useVocoder' &&\n path.node.id.type === 'ObjectPattern'\n ) {\n path.node.id.properties.forEach((prop: any) => {\n if (\n prop.type === 'ObjectProperty' &&\n prop.key.type === 'Identifier' &&\n prop.key.name === 't'\n ) {\n const localName =\n prop.value.type === 'Identifier' ? prop.value.name : 't';\n tFunctionNames.add(localName);\n }\n });\n }\n },\n\n // Extract from t() function calls\n CallExpression: (path: any) => {\n const callee = path.node.callee;\n\n // Check if this is a call to 't' function\n const isTFunction =\n callee.type === 'Identifier' && tFunctionNames.has(callee.name);\n\n if (!isTFunction) return;\n\n // Get the first argument (the string to translate)\n const firstArg = path.node.arguments[0];\n if (!firstArg) return;\n\n let text: string | null = null;\n\n // Handle string literal: t('Hello')\n if (firstArg.type === 'StringLiteral') {\n text = firstArg.value;\n }\n // Handle template literal: t(`Hello ${name}`)\n else if (firstArg.type === 'TemplateLiteral') {\n text = this.extractTemplateText(firstArg);\n }\n\n if (!text || text.trim().length === 0) return;\n\n // Get options from second argument\n const secondArg = path.node.arguments[1];\n let context: string | undefined;\n let formality: 'formal' | 'informal' | 'neutral' | 'auto' | undefined;\n let explicitKey: string | undefined;\n\n if (secondArg && secondArg.type === 'ObjectExpression') {\n secondArg.properties.forEach((prop: any) => {\n if (prop.type === 'ObjectProperty' && prop.key.type === 'Identifier') {\n if (prop.key.name === 'context' && prop.value.type === 'StringLiteral') {\n context = prop.value.value;\n }\n if (prop.key.name === 'formality' && prop.value.type === 'StringLiteral') {\n formality = prop.value.value as 'formal' | 'informal' | 'neutral' | 'auto';\n }\n if (prop.key.name === 'id' && prop.value.type === 'StringLiteral') {\n explicitKey = prop.value.value.trim();\n }\n }\n });\n }\n\n const line = path.node.loc?.start.line || 0;\n const column = path.node.loc?.start.column || 0;\n const key = explicitKey && explicitKey.length > 0\n ? explicitKey\n : this.generateStableKey({\n filePath: relativeFilePath,\n kind: 't-call',\n line,\n column,\n });\n\n strings.push({\n key,\n text: text.trim(),\n file: filePath,\n line,\n context,\n formality,\n });\n },\n\n // Extract from JSX elements\n JSXElement: (path: any) => {\n const opening = path.node.openingElement;\n const tagName =\n opening.name.type === 'JSXIdentifier'\n ? opening.name.name\n : null;\n\n if (!tagName) return;\n\n // Check if this is a <T> component (or aliased import)\n const isTranslationComponent = vocoderImports.has(tagName);\n\n if (!isTranslationComponent) return;\n\n // Check for msg attribute first (preferred for ICU messages)\n const msgAttribute = this.getStringAttribute(opening.attributes, 'msg');\n\n // Extract text - prefer msg attribute over children\n const text = msgAttribute || this.extractTextContent(path.node.children);\n\n if (!text || text.trim().length === 0) return;\n\n // Extract context and formality from props\n const id = this.getStringAttribute(opening.attributes, 'id');\n const context = this.getStringAttribute(opening.attributes, 'context');\n const formality = this.getStringAttribute(\n opening.attributes,\n 'formality',\n ) as 'formal' | 'informal' | 'neutral' | 'auto' | undefined;\n const line = path.node.loc?.start.line || 0;\n const column = path.node.loc?.start.column || 0;\n const key = id && id.trim().length > 0\n ? id.trim()\n : this.generateStableKey({\n filePath: relativeFilePath,\n kind: 'jsx',\n line,\n column,\n });\n\n strings.push({\n key,\n text: text.trim(),\n file: filePath,\n line,\n context,\n formality,\n });\n },\n });\n } catch (error) {\n throw new Error(\n `Failed to parse ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n\n return strings;\n }\n\n /**\n * Extract text from template literal\n * Converts template literals like `Hello ${name}` to `Hello {name}`\n */\n private extractTemplateText(node: any): string {\n let text = '';\n\n for (let i = 0; i < node.quasis.length; i++) {\n const quasi = node.quasis[i];\n text += quasi.value.raw;\n\n // Add placeholder for expressions\n if (i < node.expressions.length) {\n const expr = node.expressions[i];\n if (expr.type === 'Identifier') {\n text += `{${expr.name}}`;\n } else {\n // For complex expressions, use generic placeholder\n text += '{value}';\n }\n }\n }\n\n return text;\n }\n\n /**\n * Extract text content from JSX children\n */\n private extractTextContent(children: any[]): string {\n let text = '';\n\n for (const child of children) {\n if (child.type === 'JSXText') {\n text += child.value;\n } else if (child.type === 'JSXExpressionContainer') {\n const expr = child.expression;\n\n // Handle {variableName} - actual identifier\n if (expr.type === 'Identifier') {\n text += `{${expr.name}}`;\n }\n // Handle {\"{variableName}\"} - string literal placeholder\n else if (expr.type === 'StringLiteral') {\n text += expr.value;\n }\n // Handle {`${variableName}`} - template literal\n // Convert template literal syntax to ICU MessageFormat: `$${price}` → ${price}\n else if (expr.type === 'TemplateLiteral') {\n text += this.extractTemplateText(expr);\n }\n }\n }\n\n return text;\n }\n\n /**\n * Get string value from JSX attribute\n * Handles both string literals and template literals\n */\n private getStringAttribute(\n attributes: any[],\n name: string,\n ): string | undefined {\n const attr = attributes.find(\n (a) => a.type === 'JSXAttribute' && a.name.name === name,\n );\n\n if (!attr || !attr.value) return undefined;\n\n // Handle string literal: msg=\"Hello\"\n if (attr.value.type === 'StringLiteral') {\n return attr.value.value;\n }\n\n // Handle JSX expression container: msg={...}\n if (attr.value.type === 'JSXExpressionContainer') {\n const expr = attr.value.expression;\n\n // Handle template literal: msg={`Hello ${name}`}\n if (expr.type === 'TemplateLiteral') {\n return this.extractTemplateText(expr);\n }\n\n // Handle string literal in expression: msg={'Hello'}\n if (expr.type === 'StringLiteral') {\n return expr.value;\n }\n }\n\n return undefined;\n }\n\n /**\n * Deduplicate strings (keep first occurrence)\n */\n private deduplicateStrings(strings: ExtractedString[]): ExtractedString[] {\n const seen = new Map<string, number>();\n const unique: ExtractedString[] = [];\n\n for (const str of strings) {\n // Create a key based on text + context + formality\n const dedupeKey = `${str.text}|${str.context || ''}|${str.formality || ''}`;\n\n const existingIndex = seen.get(dedupeKey);\n if (existingIndex === undefined) {\n seen.set(dedupeKey, unique.length);\n unique.push(str);\n continue;\n }\n\n // Keep the lexicographically smallest key for deterministic stability\n const existing = unique[existingIndex];\n if (existing && str.key < existing.key) {\n existing.key = str.key;\n }\n }\n\n return unique;\n }\n\n private generateStableKey(params: {\n filePath: string;\n kind: 'jsx' | 't-call';\n line: number;\n column: number;\n }): string {\n const payload = `${params.filePath}|${params.kind}|${params.line}:${params.column}`;\n const digest = createHash('sha1').update(payload).digest('hex');\n return `SK_${digest.slice(0, 24).toUpperCase()}`;\n }\n}\n"],"mappings":"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","names":["readFileSync"]}