@ipp/cli
Version:
An image build orchestrator for the modern web
111 lines (110 loc) • 3.87 kB
JavaScript
;
/**
* 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}`;
}