orca/config/scripts/wrap-localized-search-expor...

136 lines
4.2 KiB
JavaScript

import fs from 'node:fs/promises'
import path from 'node:path'
import process from 'node:process'
const ROOT = process.cwd()
const RENDERER_SRC = path.join(ROOT, 'src', 'renderer', 'src')
const LOCALIZED_CATALOG_IMPORT =
"import { createLocalizedCatalog } from '@/i18n/localized-catalog'\n"
function getterName(exportName) {
if (exportName.endsWith('_ENTRIES')) {
const stem = exportName.slice(0, -'_ENTRIES'.length)
return `get${stem
.toLowerCase()
.split('_')
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join('')}Entries`
}
if (exportName.endsWith('_ENTRY')) {
const stem = exportName.slice(0, -'_ENTRY'.length)
return `get${stem
.toLowerCase()
.split('_')
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join('')}Entry`
}
if (exportName === 'STATUS_BAR_TOGGLES') {
return 'getStatusBarToggles'
}
return `get${exportName
.toLowerCase()
.split('_')
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join('')}`
}
function wrapExportConst(sourceText) {
const exportPattern =
/export const ([A-Z][A-Z0-9_]*)\s*(?::[^=]+)?=\s*(\[[\s\S]*?\]|{[\s\S]*?})\s*(?=\n(?:export |$))/g
const replacements = []
let match
while ((match = exportPattern.exec(sourceText)) !== null) {
const [fullMatch, exportName, value] = match
if (!value.includes('translate(')) {
continue
}
const getter = getterName(exportName)
const wrapped = `export const ${getter} = createLocalizedCatalog(() => ${value.trim()})`
replacements.push({ exportName, getter, fullMatch, wrapped })
}
if (replacements.length === 0) {
return { sourceText, replacements: [] }
}
let next = sourceText
for (const replacement of replacements.sort((a, b) => b.fullMatch.length - a.fullMatch.length)) {
next = next.replace(replacement.fullMatch, `${replacement.wrapped}\n`)
}
if (!next.includes("from '@/i18n/localized-catalog'")) {
const translateImport = next.match(/^import[\s\S]*?from\s*['"]@\/i18n\/i18n['"]\n/m)
if (translateImport) {
const insertAt = (translateImport.index ?? 0) + translateImport[0].length
next = `${next.slice(0, insertAt)}${LOCALIZED_CATALOG_IMPORT}${next.slice(insertAt)}`
} else {
next = `${LOCALIZED_CATALOG_IMPORT}${next}`
}
}
return { sourceText: next, replacements }
}
async function collectFiles(dir) {
const entries = await fs.readdir(dir, { withFileTypes: true })
const files = []
for (const entry of entries) {
const fullPath = path.join(dir, entry.name)
if (entry.isDirectory()) {
if (!['node_modules', 'dist', 'out', 'assets', '__snapshots__'].includes(entry.name)) {
files.push(...(await collectFiles(fullPath)))
}
continue
}
if (
entry.isFile() &&
/\.(?:ts|tsx)$/.test(entry.name) &&
!entry.name.endsWith('.d.ts') &&
!entry.name.includes('.test.') &&
!entry.name.includes('.spec.')
) {
files.push(fullPath)
}
}
return files
}
async function main() {
const files = await collectFiles(RENDERER_SRC)
const mapping = new Map()
for (const filePath of files) {
const sourceText = await fs.readFile(filePath, 'utf8')
const { sourceText: next, replacements } = wrapExportConst(sourceText)
if (replacements.length === 0) {
continue
}
await fs.writeFile(filePath, next)
for (const replacement of replacements) {
mapping.set(replacement.exportName, replacement.getter)
}
console.log(`wrapped ${replacements.length} exports in ${path.relative(ROOT, filePath)}`)
}
const allFiles = await collectFiles(path.join(ROOT, 'src'))
for (const filePath of allFiles) {
let sourceText = await fs.readFile(filePath, 'utf8')
let changed = false
for (const [exportName, getter] of mapping.entries()) {
const pattern = new RegExp(`\\b${exportName}\\b`, 'g')
const next = sourceText.replace(pattern, `${getter}()`)
if (next !== sourceText) {
sourceText = next
changed = true
}
}
if (changed) {
await fs.writeFile(filePath, sourceText)
console.log(`updated references in ${path.relative(ROOT, filePath)}`)
}
}
}
await main()