UNPKG

@inlang/paraglide-js

Version:

[![Inlang-ecosystem compatibility badge](https://cdn.jsdelivr.net/gh/opral/monorepo@main/inlang/assets/md-badges/inlang.svg)](https://inlang.com)

114 lines (113 loc) 4.65 kB
import path from "node:path"; export async function writeOutput(args) { const currentOutputHashes = await hashOutput(args.output, args.directory); // if the output hasn't changed, don't write it const changedFiles = new Set(); for (const [filePath, hash] of Object.entries(currentOutputHashes)) { if (args.previousOutputHashes?.[filePath] !== hash) { changedFiles.add(filePath); } } // Find files that have been removed in the current output const filesToDelete = new Set(); if (args.previousOutputHashes) { for (const filePath of Object.keys(args.previousOutputHashes)) { if (!currentOutputHashes[filePath]) { filesToDelete.add(filePath); } } } if (changedFiles.size === 0 && filesToDelete.size === 0) { return currentOutputHashes; } // clear the output directory // // disabled because of https://github.com/opral/inlang-paraglide-js/issues/350 // and re-enabled because of https://github.com/opral/inlang-paraglide-js/issues/420 if (args.cleanDirectory) { await args.fs.rm(args.directory, { recursive: true, force: true }); } else { await args.fs.mkdir(args.directory, { recursive: true }); } // Delete files that have been removed // ignore if cleanDirectory is true because the directory will be cleaned anyway if (filesToDelete.size > 0 && !args.cleanDirectory) { await deleteRemovedFiles(args.fs, args.directory, filesToDelete); } //Create missing directories inside the output directory await Promise.allSettled(Object.keys(args.output).map(async (filePath) => { const fullPath = path.resolve(args.directory, filePath); const directory = path.dirname(fullPath); await args.fs.mkdir(directory, { recursive: true }); })); //Write files await Promise.allSettled(Object.entries(args.output).map(async ([filePath, fileContent]) => { if (!changedFiles.has(filePath)) { return; } const fullPath = path.resolve(args.directory, filePath); await args.fs.writeFile(fullPath, fileContent); })); //Only update the previousOutputHashes if the write was successful return currentOutputHashes; } /** * Delete files that have been removed and clean up empty directories */ async function deleteRemovedFiles(fs, baseDirectory, filesToDelete) { // Collect directories that might need cleanup const potentialEmptyDirs = new Set(); // First pass: delete all files and collect parent directories await Promise.allSettled(Array.from(filesToDelete).map(async (filePath) => { const fullPath = path.resolve(baseDirectory, filePath); try { await fs.unlink(fullPath); // Add parent directory for potential cleanup const dirPath = path.dirname(fullPath); if (dirPath !== baseDirectory) { potentialEmptyDirs.add(dirPath); } } catch { // Ignore errors if the file doesn't exist } })); // Second pass: clean up empty directories, starting from deepest paths const sortedDirs = Array.from(potentialEmptyDirs).sort((a, b) => b.length - a.length); for (const dirPath of sortedDirs) { // Only process directories within the base directory if (!dirPath.startsWith(baseDirectory) || dirPath === baseDirectory) { continue; } try { const dirContents = await fs.readdir(dirPath); if (dirContents.length === 0) { await fs.rmdir(dirPath); // Add parent directory for potential cleanup const parentDir = path.dirname(dirPath); if (parentDir !== baseDirectory) { sortedDirs.push(parentDir); } } } catch { // Ignore errors during directory cleanup } } } async function hashString(input) { const encoder = new TextEncoder(); const data = encoder.encode(input); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); } async function hashOutput(output, outputDirectory) { const hashes = {}; for (const [filePath, fileContent] of Object.entries(output)) { const combinedContent = fileContent + path.resolve(outputDirectory, filePath); hashes[filePath] = await hashString(combinedContent); } return hashes; }