{"version":3,"file":"writeFileIfChanged.cjs","names":[],"sources":["../../src/writeFileIfChanged.ts"],"sourcesContent":["import { createHash, randomBytes } from 'node:crypto';\nimport { createReadStream, rmSync } from 'node:fs';\nimport { chmod, mkdir, rename, rm, stat, writeFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\n\nconst activeTempFiles = new Set<string>();\n\n// Synchronous cleanup on process exit\nprocess.on('exit', () => {\n  for (const file of activeTempFiles) {\n    try {\n      rmSync(file, { force: true });\n    } catch {}\n  }\n});\n\n// Helper to hash existing file via stream\nconst getFileHash = (path: string): Promise<string | null> => {\n  return new Promise((resolve) => {\n    const hash = createHash('sha256');\n    const stream = createReadStream(path);\n    stream.on('data', (chunk) => hash.update(chunk));\n    stream.on('end', () => resolve(hash.digest('hex')));\n    stream.on('error', () => resolve(null));\n  });\n};\n\nexport const writeFileIfChanged = async (\n  path: string,\n  data: string,\n  {\n    encoding = 'utf8',\n    tempDir,\n  }: { encoding?: BufferEncoding; tempDir?: string } = {}\n): Promise<boolean> => {\n  const newDataHash = createHash('sha256').update(data, encoding).digest('hex');\n  const existingHash = await getFileHash(path);\n\n  if (newDataHash === existingHash) {\n    return false;\n  }\n\n  if (tempDir) {\n    await mkdir(tempDir, { recursive: true });\n  }\n\n  const tempFileName = `${basename(path)}.${Date.now()}-${randomBytes(4).toString('hex')}.tmp`;\n  const tempPath = tempDir\n    ? join(tempDir, tempFileName)\n    : `${path}.${tempFileName}`;\n  activeTempFiles.add(tempPath);\n\n  try {\n    let mode: number | undefined;\n    try {\n      mode = (await stat(path)).mode;\n    } catch {}\n\n    await writeFile(tempPath, data, { encoding });\n\n    if (mode !== undefined) {\n      await chmod(tempPath, mode);\n    }\n\n    await rename(tempPath, path);\n  } catch (error) {\n    try {\n      await rm(tempPath, { force: true });\n    } catch {}\n    throw error;\n  } finally {\n    activeTempFiles.delete(tempPath);\n  }\n\n  return true;\n};\n"],"mappings":";;;;;;;;AAKA,MAAM,kCAAkB,IAAI,KAAa;AAGzC,QAAQ,GAAG,cAAc;AACvB,MAAK,MAAM,QAAQ,gBACjB,KAAI;AACF,sBAAO,MAAM,EAAE,OAAO,MAAM,CAAC;SACvB;EAEV;AAGF,MAAM,eAAe,SAAyC;AAC5D,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,mCAAkB,SAAS;EACjC,MAAM,uCAA0B,KAAK;AACrC,SAAO,GAAG,SAAS,UAAU,KAAK,OAAO,MAAM,CAAC;AAChD,SAAO,GAAG,aAAa,QAAQ,KAAK,OAAO,MAAM,CAAC,CAAC;AACnD,SAAO,GAAG,eAAe,QAAQ,KAAK,CAAC;GACvC;;AAGJ,MAAa,qBAAqB,OAChC,MACA,MACA,EACE,WAAW,QACX,YACmD,EAAE,KAClC;AAIrB,iCAH+B,SAAS,CAAC,OAAO,MAAM,SAAS,CAAC,OAAO,MAGxD,KAAK,MAFO,YAAY,KAAK,CAG1C,QAAO;AAGT,KAAI,QACF,mCAAY,SAAS,EAAE,WAAW,MAAM,CAAC;CAG3C,MAAM,eAAe,2BAAY,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,gCAAe,EAAE,CAAC,SAAS,MAAM,CAAC;CACvF,MAAM,WAAW,8BACR,SAAS,aAAa,GAC3B,GAAG,KAAK,GAAG;AACf,iBAAgB,IAAI,SAAS;AAE7B,KAAI;EACF,IAAI;AACJ,MAAI;AACF,WAAQ,iCAAW,KAAK,EAAE;UACpB;AAER,wCAAgB,UAAU,MAAM,EAAE,UAAU,CAAC;AAE7C,MAAI,SAAS,OACX,mCAAY,UAAU,KAAK;AAG7B,qCAAa,UAAU,KAAK;UACrB,OAAO;AACd,MAAI;AACF,kCAAS,UAAU,EAAE,OAAO,MAAM,CAAC;UAC7B;AACR,QAAM;WACE;AACR,kBAAgB,OAAO,SAAS;;AAGlC,QAAO"}