UNPKG

@ipp/cli

Version:

An image build orchestrator for the modern web

111 lines (110 loc) 3.87 kB
"use strict"; /** * Image Processing Pipeline - Copyright (c) Marcus Cemes * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.saveImages = void 0; const common_1 = require("@ipp/common"); const constants_1 = require("constants"); const fs_1 = require("fs"); const path_1 = require("path"); const metadata_1 = require("../lib/metadata"); const map_parallel_1 = require("../lib/stream/operators/map_parallel"); const types_1 = require("./types"); const SAVE_CONCURRENCY = 4; const DEFAULT_TEMPLATE = "[name]-[hash:8][ext]"; function saveImages(path, flat) { const startTime = Date.now(); return (0, map_parallel_1.mapParallel)(SAVE_CONCURRENCY, async (item) => { if (!(0, types_1.isCompletedTask)(item)) return item; const errors = []; const { dir } = (0, path_1.parse)(item.file); const savedFormats = []; for (const format of item.result.formats) { const finalMetadata = { ...format.data.metadata, current: { ...format.data.metadata.current, ext: formatToExt(format.data.metadata.current.format), }, }; const template = typeof format.saveKey === "string" ? format.saveKey : DEFAULT_TEMPLATE; const interpolatedTemplate = (0, common_1.interpolateTemplates)(finalMetadata, template); const outputDir = flat ? path : (0, path_1.resolve)(path, dir); const outputPath = (0, path_1.resolve)(outputDir, interpolatedTemplate); try { await ensureDirectory(outputDir); const modified = await getLastModifiedTime(outputPath); if (modified !== null && modified > startTime) { throw new common_1.Exception(`Filename conflict! The following filename has already been used: "${outputPath}"`); } await fs_1.promises.writeFile(outputPath, format.data.buffer); savedFormats.push(formatWithNewPath(format, (0, path_1.relative)(path, outputPath))); } catch (err) { errors.push(err instanceof common_1.Exception ? err : new common_1.Exception(`Failed to save image, the manifest may be inconsistent:\n${err.message}`).extend(err)); } } return errors.length === 0 ? { savedResult: { source: item.result.source, formats: savedFormats, }, } : errors; }); } exports.saveImages = saveImages; async function ensureDirectory(path) { try { await fs_1.promises.access(path, constants_1.F_OK); const stat = await fs_1.promises.stat(path); if (!stat.isDirectory()) throw null; } catch { await fs_1.promises.mkdir(path, { recursive: true }); } } async function getLastModifiedTime(path) { try { return (await fs_1.promises.stat(path)).mtimeMs; } catch { return null; } } function formatWithNewPath(format, path) { return { ...format, data: { ...format.data, metadata: { ...format.data.metadata, current: { ...format.data.metadata.current, ...(0, metadata_1.pathMetadata)(path), }, }, }, }; } const EXTENSION_MAP = { jpeg: ".jpg", png: ".png", webp: ".webp", svg: ".svg", tiff: ".tiff", gif: ".gif", avif: ".avif", }; function formatToExt(format) { return EXTENSION_MAP[format] || `.${format}`; }