Comparing version 1.0.0-alpha.47 to 1.0.0-alpha.48
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.0.0-alpha.48](https://github.com/axe312ger/sqip/compare/sqip@1.0.0-alpha.47...sqip@1.0.0-alpha.48) (2024-03-22) | ||
### Bug Fixes | ||
* BREAKING - up minimum node version to 18.12.1 and configure typescript to output for that node version ([f1e051f](https://github.com/axe312ger/sqip/commit/f1e051f4962e094308116a9bbf47f063abf7dc8b)) | ||
# [1.0.0-alpha.47](https://github.com/axe312ger/sqip/compare/sqip@1.0.0-alpha.46...sqip@1.0.0-alpha.47) (2024-03-22) | ||
@@ -8,0 +19,0 @@ |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -46,4 +14,4 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
const debug = (0, debug_1.default)('sqip'); | ||
const loadSVG = (svg) => __awaiter(void 0, void 0, void 0, function* () { | ||
const { createSVGWindow } = yield Promise.resolve().then(() => __importStar(require('svgdom'))); | ||
const loadSVG = async (svg) => { | ||
const { createSVGWindow } = await import('svgdom'); | ||
const window = createSVGWindow(); | ||
@@ -53,3 +21,3 @@ const document = window.document; | ||
return (0, svg_js_1.SVG)(svg); | ||
}); | ||
}; | ||
exports.loadSVG = loadSVG; | ||
@@ -60,33 +28,32 @@ function isError(error) { | ||
exports.isError = isError; | ||
function locateFiles(input) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const enhancedInput = (0, expand_tilde_1.default)(input); | ||
let globPattern = enhancedInput; | ||
try { | ||
const stat = yield fs_extra_1.default.lstat(enhancedInput); | ||
if (stat.isFile()) { | ||
debug(`input ${input} is a file. Skip file search.`); | ||
return [enhancedInput]; | ||
} | ||
if (stat.isDirectory()) { | ||
debug(`input ${input} is a directory. Enhancing with * to match all files.`); | ||
globPattern = `${path_1.default.resolve(enhancedInput)}/*`; | ||
} | ||
async function locateFiles(input) { | ||
const enhancedInput = (0, expand_tilde_1.default)(input); | ||
let globPattern = enhancedInput; | ||
try { | ||
const stat = await fs_extra_1.default.lstat(enhancedInput); | ||
if (stat.isFile()) { | ||
debug(`input ${input} is a file. Skip file search.`); | ||
return [enhancedInput]; | ||
} | ||
catch (err) { | ||
if (isError(err) && err instanceof TypeError) { | ||
if (err.code === 'ENOENT') { | ||
throw err; | ||
} | ||
if (stat.isDirectory()) { | ||
debug(`input ${input} is a directory. Enhancing with * to match all files.`); | ||
globPattern = `${path_1.default.resolve(enhancedInput)}/*`; | ||
} | ||
} | ||
catch (err) { | ||
if (isError(err) && err instanceof TypeError) { | ||
if (err.code === 'ENOENT') { | ||
throw err; | ||
} | ||
} | ||
// Find all files matching the enhanced glob | ||
const files = yield (0, fast_glob_1.default)(globPattern, { | ||
onlyFiles: true, | ||
extglob: true, | ||
absolute: true | ||
}); | ||
// Test if files are found | ||
if (!files.length) { | ||
throw new Error(`Unable to find any files via ${globPattern}. Make sure the file exists. | ||
} | ||
// Find all files matching the enhanced glob | ||
const files = await (0, fast_glob_1.default)(globPattern, { | ||
onlyFiles: true, | ||
extglob: true, | ||
absolute: true | ||
}); | ||
// Test if files are found | ||
if (!files.length) { | ||
throw new Error(`Unable to find any files via ${globPattern}. Make sure the file exists. | ||
@@ -96,13 +63,11 @@ If you are using globbing patterns, the following features are supported: | ||
https://github.com/micromatch/micromatch#matching-features`); | ||
} | ||
return files; | ||
}); | ||
} | ||
return files; | ||
} | ||
exports.locateFiles = locateFiles; | ||
function parseColor({ palette, color }) { | ||
var _a; | ||
// @todo test, fallback to or detect transparent as color (for bg) | ||
return ((_a = palette[color]) === null || _a === void 0 ? void 0 : _a.hex) || color; | ||
return palette[color]?.hex || color; | ||
} | ||
exports.parseColor = parseColor; | ||
//# sourceMappingURL=helpers.js.map |
512
dist/sqip.js
@@ -28,11 +28,2 @@ "use strict"; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -76,2 +67,5 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
class SqipPlugin { | ||
sqipConfig; | ||
options; | ||
static cliOptions; | ||
constructor(options) { | ||
@@ -90,277 +84,269 @@ const { sqipConfig } = options; | ||
// Array of plugin names or config objects, even mixed. | ||
function resolvePlugins(plugins) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return Promise.all(plugins.map((plugin) => __awaiter(this, void 0, void 0, function* () { | ||
if (typeof plugin === 'string') { | ||
plugin = { name: plugin }; | ||
} | ||
const { name } = plugin; | ||
if (!name) { | ||
throw new Error(`Unable to read plugin name from:\n${JSON.stringify(plugin, null, 2)}`); | ||
} | ||
const moduleName = name.indexOf('sqip-plugin-') !== -1 ? name : `sqip-plugin-${name}`; | ||
try { | ||
debug(`Loading ${moduleName}`); | ||
const Plugin = yield Promise.resolve(`${moduleName}`).then(s => __importStar(require(s))); | ||
return Object.assign(Object.assign({}, plugin), { Plugin: Plugin.default }); | ||
} | ||
catch (err) { | ||
console.error(err); | ||
throw new Error(`Unable to load plugin "${moduleName}". Try installing it via:\n\n npm install ${moduleName}`); | ||
} | ||
}))); | ||
}); | ||
async function resolvePlugins(plugins) { | ||
return Promise.all(plugins.map(async (plugin) => { | ||
if (typeof plugin === 'string') { | ||
plugin = { name: plugin }; | ||
} | ||
const { name } = plugin; | ||
if (!name) { | ||
throw new Error(`Unable to read plugin name from:\n${JSON.stringify(plugin, null, 2)}`); | ||
} | ||
const moduleName = name.indexOf('sqip-plugin-') !== -1 ? name : `sqip-plugin-${name}`; | ||
try { | ||
debug(`Loading ${moduleName}`); | ||
const Plugin = await import(moduleName); | ||
return { ...plugin, Plugin: Plugin.default }; | ||
} | ||
catch (err) { | ||
console.error(err); | ||
throw new Error(`Unable to load plugin "${moduleName}". Try installing it via:\n\n npm install ${moduleName}`); | ||
} | ||
})); | ||
} | ||
exports.resolvePlugins = resolvePlugins; | ||
function processFile({ filePath, buffer, outputFileName, config }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { output, silent, parseableOutput, print } = config; | ||
const result = yield processImage({ filePath, buffer, config }); | ||
const { content, metadata } = result; | ||
let outputPath; | ||
debug(`Processed ${outputFileName}`); | ||
// Write result svg if desired | ||
if (output) { | ||
try { | ||
// Test if output path already exists | ||
const stats = yield fs_extra_1.default.stat(output); | ||
// Throw if it is a file and already exists | ||
if (!stats.isDirectory()) { | ||
throw new Error(`File ${output} already exists. Overwriting is not yet supported.`); | ||
} | ||
outputPath = path_1.default.resolve(output, `${outputFileName}.svg`); | ||
async function processFile({ filePath, buffer, outputFileName, config }) { | ||
const { output, silent, parseableOutput, print } = config; | ||
const result = await processImage({ filePath, buffer, config }); | ||
const { content, metadata } = result; | ||
let outputPath; | ||
debug(`Processed ${outputFileName}`); | ||
// Write result svg if desired | ||
if (output) { | ||
try { | ||
// Test if output path already exists | ||
const stats = await fs_extra_1.default.stat(output); | ||
// Throw if it is a file and already exists | ||
if (!stats.isDirectory()) { | ||
throw new Error(`File ${output} already exists. Overwriting is not yet supported.`); | ||
} | ||
catch (err) { | ||
// Output directory or file does not exist. We will create it later on. | ||
outputPath = output; | ||
} | ||
debug(`Writing ${outputPath}`); | ||
yield fs_extra_1.default.writeFile(outputPath, content); | ||
outputPath = path_1.default.resolve(output, `${outputFileName}.svg`); | ||
} | ||
// Gather CLI output information | ||
if (!silent) { | ||
if (outputPath) { | ||
console.log(`Stored at: ${outputPath}`); | ||
} | ||
// Generate preview | ||
if (!parseableOutput) { | ||
// Convert to png for image preview | ||
const preview = yield (0, sharp_1.default)(Buffer.from(content)).png().toBuffer(); | ||
try { | ||
(0, term_img_1.default)(preview, { | ||
fallback: () => { | ||
// SVG results can still be outputted as string | ||
if (metadata.type === 'svg') { | ||
console.log(content.toString()); | ||
return; | ||
} | ||
// No fallback preview solution yet for non-svg files. | ||
console.log(`Unable to render a preview for ${metadata.type} files on this machine. Try using https://iterm2.com/`); | ||
catch (err) { | ||
// Output directory or file does not exist. We will create it later on. | ||
outputPath = output; | ||
} | ||
debug(`Writing ${outputPath}`); | ||
await fs_extra_1.default.writeFile(outputPath, content); | ||
} | ||
// Gather CLI output information | ||
if (!silent) { | ||
if (outputPath) { | ||
console.log(`Stored at: ${outputPath}`); | ||
} | ||
// Generate preview | ||
if (!parseableOutput) { | ||
// Convert to png for image preview | ||
const preview = await (0, sharp_1.default)(Buffer.from(content)).png().toBuffer(); | ||
try { | ||
(0, term_img_1.default)(preview, { | ||
fallback: () => { | ||
// SVG results can still be outputted as string | ||
if (metadata.type === 'svg') { | ||
console.log(content.toString()); | ||
return; | ||
} | ||
}); | ||
} | ||
catch (err) { | ||
if (err instanceof term_img_1.UnsupportedTerminalError) { | ||
if (err.name === 'UnsupportedTerminalError') { | ||
throw err; | ||
} | ||
// No fallback preview solution yet for non-svg files. | ||
console.log(`Unable to render a preview for ${metadata.type} files on this machine. Try using https://iterm2.com/`); | ||
} | ||
} | ||
}); | ||
} | ||
// Metadata | ||
const tableConfig = parseableOutput | ||
? { | ||
chars: { | ||
top: '', | ||
'top-mid': '', | ||
'top-left': '', | ||
'top-right': '', | ||
bottom: '', | ||
'bottom-mid': '', | ||
'bottom-left': '', | ||
'bottom-right': '', | ||
left: '', | ||
'left-mid': '', | ||
mid: '', | ||
'mid-mid': '', | ||
right: '', | ||
'right-mid': '', | ||
middle: ' ' | ||
}, | ||
style: { 'padding-left': 0, 'padding-right': 0 } | ||
catch (err) { | ||
if (err instanceof term_img_1.UnsupportedTerminalError) { | ||
if (err.name === 'UnsupportedTerminalError') { | ||
throw err; | ||
} | ||
} | ||
: undefined; | ||
// Figure out which metadata keys to show | ||
// @todo why is this unused? | ||
// const allKeys = [...mainKeys, 'palette'] | ||
const mainTable = new cli_table3_1.default(tableConfig); | ||
mainTable.push(mainKeys); | ||
mainTable.push(mainKeys.map((key) => String(metadata[key]) || 'can not display')); | ||
console.log(mainTable.toString()); | ||
// Show color palette | ||
const paletteTable = new cli_table3_1.default(tableConfig); | ||
paletteTable.push(PALETTE_KEYS); | ||
paletteTable.push(PALETTE_KEYS.map((key) => { var _a; return (_a = metadata.palette[key]) === null || _a === void 0 ? void 0 : _a.hex; }) | ||
.filter((hex) => typeof hex === 'string') | ||
.map((hex) => chalk_1.default.hex(hex)(hex))); | ||
console.log(paletteTable.toString()); | ||
Object.keys(metadata) | ||
.filter((key) => ![...mainKeys, 'palette'].includes(key)) | ||
.forEach((key) => { | ||
console.log(chalk_1.default.bold(`${key}:`)); | ||
console.log(metadata[key]); | ||
}); | ||
if (metadata.type === 'svg' && print) { | ||
console.log(`Resulting SVG:\n${result.content.toString()}`); | ||
} | ||
} | ||
return result; | ||
}); | ||
} | ||
function processImage({ filePath, buffer, config }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Extract the palette from the image. We delegate to node-vibrant (which is | ||
// using jimp internally), and it only supports some image formats. In | ||
// particular, it does not support WebP and HEIC yet. | ||
// | ||
// So we try with the given image buffer, and if the code throws an exception | ||
// we try again after converting to TIFF. If that fails again we give up. | ||
const paletteResult = yield (() => __awaiter(this, void 0, void 0, function* () { | ||
const getPalette = (buffer) => sharp_vibrant_1.default.from(buffer).quality(0).getPalette(); | ||
try { | ||
return yield getPalette(buffer); | ||
// Metadata | ||
const tableConfig = parseableOutput | ||
? { | ||
chars: { | ||
top: '', | ||
'top-mid': '', | ||
'top-left': '', | ||
'top-right': '', | ||
bottom: '', | ||
'bottom-mid': '', | ||
'bottom-left': '', | ||
'bottom-right': '', | ||
left: '', | ||
'left-mid': '', | ||
mid: '', | ||
'mid-mid': '', | ||
right: '', | ||
'right-mid': '', | ||
middle: ' ' | ||
}, | ||
style: { 'padding-left': 0, 'padding-right': 0 } | ||
} | ||
catch (_a) { | ||
return getPalette(yield (0, sharp_1.default)(buffer).tiff().toBuffer()); | ||
} | ||
}))(); | ||
const { name: filename } = path_1.default.parse(filePath); | ||
const mimeType = mime_1.default.getType(filePath) || 'unknown'; | ||
const metadata = { | ||
filename, | ||
mimeType, | ||
originalWidth: paletteResult.imageDimensions.width, | ||
originalHeight: paletteResult.imageDimensions.height, | ||
palette: paletteResult.palette, | ||
// @todo this should be set by plugins and detected initially | ||
type: 'unknown', | ||
width: 0, | ||
height: 0 | ||
}; | ||
// Load plugins | ||
const plugins = yield resolvePlugins(config.plugins); | ||
// Determine output image size | ||
if (config.width && config.width > 0) { | ||
// Resize to desired output width | ||
try { | ||
buffer = yield (0, sharp_1.default)(buffer).resize(config.width).toBuffer(); | ||
const resizedMetadata = yield (0, sharp_1.default)(buffer).metadata(); | ||
metadata.width = resizedMetadata.width || 0; | ||
metadata.height = resizedMetadata.height || 0; | ||
} | ||
catch (err) { | ||
throw new Error('Unable to resize'); | ||
} | ||
: undefined; | ||
// Figure out which metadata keys to show | ||
// @todo why is this unused? | ||
// const allKeys = [...mainKeys, 'palette'] | ||
const mainTable = new cli_table3_1.default(tableConfig); | ||
mainTable.push(mainKeys); | ||
mainTable.push(mainKeys.map((key) => String(metadata[key]) || 'can not display')); | ||
console.log(mainTable.toString()); | ||
// Show color palette | ||
const paletteTable = new cli_table3_1.default(tableConfig); | ||
paletteTable.push(PALETTE_KEYS); | ||
paletteTable.push(PALETTE_KEYS.map((key) => metadata.palette[key]?.hex) | ||
.filter((hex) => typeof hex === 'string') | ||
.map((hex) => chalk_1.default.hex(hex)(hex))); | ||
console.log(paletteTable.toString()); | ||
Object.keys(metadata) | ||
.filter((key) => ![...mainKeys, 'palette'].includes(key)) | ||
.forEach((key) => { | ||
console.log(chalk_1.default.bold(`${key}:`)); | ||
console.log(metadata[key]); | ||
}); | ||
if (metadata.type === 'svg' && print) { | ||
console.log(`Resulting SVG:\n${result.content.toString()}`); | ||
} | ||
else { | ||
// Fall back to original size, keep image as is | ||
metadata.width = metadata.originalWidth; | ||
metadata.height = metadata.originalHeight; | ||
} | ||
return result; | ||
} | ||
async function processImage({ filePath, buffer, config }) { | ||
// Extract the palette from the image. We delegate to node-vibrant (which is | ||
// using jimp internally), and it only supports some image formats. In | ||
// particular, it does not support WebP and HEIC yet. | ||
// | ||
// So we try with the given image buffer, and if the code throws an exception | ||
// we try again after converting to TIFF. If that fails again we give up. | ||
const paletteResult = await (async () => { | ||
const getPalette = (buffer) => sharp_vibrant_1.default.from(buffer).quality(0).getPalette(); | ||
try { | ||
return await getPalette(buffer); | ||
} | ||
// Interate through plugins and apply them to last returned image | ||
for (const { name, options: pluginOptions, Plugin } of plugins) { | ||
try { | ||
debug(`Construct ${name}`); | ||
const plugin = new Plugin({ | ||
sqipConfig: config, | ||
pluginOptions: pluginOptions || {}, | ||
options: {} | ||
}); | ||
debug(`Apply ${name}`); | ||
buffer = yield plugin.apply(buffer, metadata); | ||
} | ||
catch (err) { | ||
console.log(`Error thrown in plugin ${name}.`); | ||
console.dir({ metadata }, { depth: 3 }); | ||
throw err; | ||
} | ||
catch { | ||
return getPalette(await (0, sharp_1.default)(buffer).tiff().toBuffer()); | ||
} | ||
return { content: buffer, metadata }; | ||
}); | ||
} | ||
function sqip(options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Build configuration based on passed options and default options | ||
const defaultOptions = { | ||
plugins: [ | ||
{ name: 'primitive', options: { numberOfPrimitives: 8, mode: 0 } }, | ||
'blur', | ||
'svgo', | ||
'data-uri' | ||
], | ||
width: 300, | ||
parseableOutput: false, | ||
silent: true, | ||
print: false | ||
}; | ||
const config = Object.assign({}, defaultOptions, options); | ||
const { input, outputFileName, parseableOutput, silent } = config; | ||
if (parseableOutput) { | ||
chalk_1.default.level = 0; | ||
})(); | ||
const { name: filename } = path_1.default.parse(filePath); | ||
const mimeType = mime_1.default.getType(filePath) || 'unknown'; | ||
const metadata = { | ||
filename, | ||
mimeType, | ||
originalWidth: paletteResult.imageDimensions.width, | ||
originalHeight: paletteResult.imageDimensions.height, | ||
palette: paletteResult.palette, | ||
// @todo this should be set by plugins and detected initially | ||
type: 'unknown', | ||
width: 0, | ||
height: 0 | ||
}; | ||
// Load plugins | ||
const plugins = await resolvePlugins(config.plugins); | ||
// Determine output image size | ||
if (config.width && config.width > 0) { | ||
// Resize to desired output width | ||
try { | ||
buffer = await (0, sharp_1.default)(buffer).resize(config.width).toBuffer(); | ||
const resizedMetadata = await (0, sharp_1.default)(buffer).metadata(); | ||
metadata.width = resizedMetadata.width || 0; | ||
metadata.height = resizedMetadata.height || 0; | ||
} | ||
// Validate configuration | ||
if (!input || input.length === 0) { | ||
throw new Error('Please provide an input image, e.g. sqip({ input: "input.jpg" })'); | ||
catch (err) { | ||
throw new Error('Unable to resize'); | ||
} | ||
// If input is a Buffer | ||
if (Buffer.isBuffer(input)) { | ||
if (!outputFileName) { | ||
throw new Error('OutputFileName is required when passing image as buffer'); | ||
} | ||
return processFile({ | ||
filePath: '-', | ||
buffer: input, | ||
outputFileName, | ||
config | ||
} | ||
else { | ||
// Fall back to original size, keep image as is | ||
metadata.width = metadata.originalWidth; | ||
metadata.height = metadata.originalHeight; | ||
} | ||
// Interate through plugins and apply them to last returned image | ||
for (const { name, options: pluginOptions, Plugin } of plugins) { | ||
try { | ||
debug(`Construct ${name}`); | ||
const plugin = new Plugin({ | ||
sqipConfig: config, | ||
pluginOptions: pluginOptions || {}, | ||
options: {} | ||
}); | ||
debug(`Apply ${name}`); | ||
buffer = await plugin.apply(buffer, metadata); | ||
} | ||
const files = yield (0, helpers_1.locateFiles)(input); | ||
debug('Found files:'); | ||
debug(files); | ||
// Test if all files are accessable | ||
for (const file of files) { | ||
try { | ||
debug('check file ' + file); | ||
yield fs_extra_1.default.access(file, fs_extra_1.default.constants.R_OK); | ||
} | ||
catch (err) { | ||
throw new Error(`Unable to read file ${file}`); | ||
} | ||
catch (err) { | ||
console.log(`Error thrown in plugin ${name}.`); | ||
console.dir({ metadata }, { depth: 3 }); | ||
throw err; | ||
} | ||
// Iterate over all files | ||
const results = []; | ||
for (const filePath of files) { | ||
// Apply plugins to files | ||
if (!silent) { | ||
console.log(`Processing: ${filePath}`); | ||
} | ||
else { | ||
debug(`Processing ${filePath}`); | ||
} | ||
const buffer = yield fs_extra_1.default.readFile(filePath); | ||
const result = yield processFile({ | ||
filePath, | ||
buffer, | ||
outputFileName: outputFileName || path_1.default.parse(filePath).name, | ||
config | ||
}); | ||
results.push(result); | ||
} | ||
return { content: buffer, metadata }; | ||
} | ||
async function sqip(options) { | ||
// Build configuration based on passed options and default options | ||
const defaultOptions = { | ||
plugins: [ | ||
{ name: 'primitive', options: { numberOfPrimitives: 8, mode: 0 } }, | ||
'blur', | ||
'svgo', | ||
'data-uri' | ||
], | ||
width: 300, | ||
parseableOutput: false, | ||
silent: true, | ||
print: false | ||
}; | ||
const config = Object.assign({}, defaultOptions, options); | ||
const { input, outputFileName, parseableOutput, silent } = config; | ||
if (parseableOutput) { | ||
chalk_1.default.level = 0; | ||
} | ||
// Validate configuration | ||
if (!input || input.length === 0) { | ||
throw new Error('Please provide an input image, e.g. sqip({ input: "input.jpg" })'); | ||
} | ||
// If input is a Buffer | ||
if (Buffer.isBuffer(input)) { | ||
if (!outputFileName) { | ||
throw new Error('OutputFileName is required when passing image as buffer'); | ||
} | ||
debug(`Finished`); | ||
// Return as array when input was array or results is only one file | ||
if (Array.isArray(input) || results.length === 0) { | ||
return results; | ||
return processFile({ | ||
filePath: '-', | ||
buffer: input, | ||
outputFileName, | ||
config | ||
}); | ||
} | ||
const files = await (0, helpers_1.locateFiles)(input); | ||
debug('Found files:'); | ||
debug(files); | ||
// Test if all files are accessable | ||
for (const file of files) { | ||
try { | ||
debug('check file ' + file); | ||
await fs_extra_1.default.access(file, fs_extra_1.default.constants.R_OK); | ||
} | ||
return results[0]; | ||
}); | ||
catch (err) { | ||
throw new Error(`Unable to read file ${file}`); | ||
} | ||
} | ||
// Iterate over all files | ||
const results = []; | ||
for (const filePath of files) { | ||
// Apply plugins to files | ||
if (!silent) { | ||
console.log(`Processing: ${filePath}`); | ||
} | ||
else { | ||
debug(`Processing ${filePath}`); | ||
} | ||
const buffer = await fs_extra_1.default.readFile(filePath); | ||
const result = await processFile({ | ||
filePath, | ||
buffer, | ||
outputFileName: outputFileName || path_1.default.parse(filePath).name, | ||
config | ||
}); | ||
results.push(result); | ||
} | ||
debug(`Finished`); | ||
// Return as array when input was array or results is only one file | ||
if (Array.isArray(input) || results.length === 0) { | ||
return results; | ||
} | ||
return results[0]; | ||
} | ||
@@ -367,0 +353,0 @@ exports.sqip = sqip; |
{ | ||
"name": "sqip", | ||
"version": "1.0.0-alpha.47", | ||
"version": "1.0.0-alpha.48", | ||
"description": "> TODO: description", | ||
@@ -14,3 +14,3 @@ "author": "Benedikt Rötsch <info@benedikt-roetsch.de>", | ||
"engines": { | ||
"node": ">=14.0.0" | ||
"node": ">=18.12.1" | ||
}, | ||
@@ -71,3 +71,3 @@ "types": "dist/sqip.d.ts", | ||
}, | ||
"gitHead": "bdc25c885ea57659ea00cd0a9e85403b74cd9f3e" | ||
"gitHead": "5a90f4e138f6682391ba551b94d0c16c931b4801" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
2
43486
520