regime/src/sync.ts
2026-05-02 03:21:33 +02:00

124 lines
3.8 KiB
TypeScript

import { dirname, relative, join } from "node:path"
import { existsSync } from "node:fs"
import { writeFile } from "node:fs/promises"
import {
type RegimeConfig,
findRegimeConfigs,
resolveTemplateChain,
getStrategy,
interpolate,
readFileSync,
deepMerge,
mergeTemplateJsonFiles,
detectIndent,
} from "./shared"
const green = Bun.color("green", "ansi")
const yellow = Bun.color("orange", "ansi")
const red = Bun.color("red", "ansi")
const purple = Bun.color("purple", "ansi")
const reset = "\x1b[0m"
export async function sync(targetDir: string): Promise<void> {
const rcFiles = await findRegimeConfigs(targetDir)
if (rcFiles.length === 0) {
console.log("No regime.config.json files found.")
return
}
for (const rcFile of rcFiles) {
const rcDir = dirname(rcFile)
const relDir = relative(targetDir, rcDir) || "."
console.log(`\n${purple}${relDir}/${reset}`)
const rc: RegimeConfig = JSON.parse(readFileSync(rcFile))
const templateNames = Array.isArray(rc.templates) ? rc.templates : [rc.templates]
const vars = rc.vars ?? {}
const { files, patterns } = resolveTemplateChain(templateNames)
if (files.size === 0) {
console.log(" (no template files)")
continue
}
let allSynced = true
for (const [relPath, templatePaths] of files) {
const targetPath = join(rcDir, relPath)
const strategy = getStrategy(relPath, patterns)
// Check target directory exists
const targetFileDir = dirname(targetPath)
if (!existsSync(targetFileDir)) {
console.log(` ${relPath}: ${yellow}warning: directory does not exist, skipping${reset}`)
continue
}
if (strategy === "merge json") {
let templateObj: any
try {
templateObj = mergeTemplateJsonFiles(templatePaths, vars, relPath)
} catch (e) {
console.log(` ${relPath}: ${red}failed to parse template JSON${reset} - ${e}`)
continue
}
if (existsSync(targetPath)) {
const existingContent = readFileSync(targetPath)
let existingObj: any
try {
existingObj = JSON.parse(existingContent)
} catch (e) {
console.log(` ${relPath}: ${red}failed to parse existing JSON${reset} - ${e}`)
continue
}
const merged = deepMerge(existingObj, templateObj)
const indent = detectIndent(existingContent)
const mergedContent = JSON.stringify(merged, null, indent) + "\n"
if (mergedContent === existingContent) {
// already in sync
continue
}
await writeFile(targetPath, mergedContent)
console.log(` ${relPath}: ${green}updated${reset}`)
allSynced = false
} else {
const content = JSON.stringify(templateObj, null, " ") + "\n"
await writeFile(targetPath, content)
console.log(` ${relPath}: ${green}created${reset}`)
allSynced = false
}
} else if (strategy === "overwrite") {
const templateContent = interpolate(
readFileSync(templatePaths[templatePaths.length - 1]),
vars,
relPath,
)
if (existsSync(targetPath)) {
const existingContent = readFileSync(targetPath)
if (existingContent === templateContent) {
// already in sync
continue
}
await writeFile(targetPath, templateContent)
console.log(` ${relPath}: ${green}updated${reset}`)
allSynced = false
} else {
await writeFile(targetPath, templateContent)
console.log(` ${relPath}: ${green}created${reset}`)
allSynced = false
}
}
}
if (allSynced) {
console.log(` ${green}in sync${reset}`)
}
}
}