UNPKG

@supernaut/next-image-storyblok-loader

Version:
258 lines (245 loc) 8.04 kB
'use strict'; // src/lib/constants.ts var DEFAULT_HOST = "a.storyblok.com"; // src/lib/get-storyblok-src-host.ts function getStoryblokSrcHost(override) { const pattern = /^\w+(\.\w+)*(:\d+)?$/; if (override && pattern.test(override)) { return override; } if (process.env.STORYBLOK_IMAGE_LOADER_HOST && pattern.test(process.env.STORYBLOK_IMAGE_LOADER_HOST)) { return process.env.STORYBLOK_IMAGE_LOADER_HOST; } return DEFAULT_HOST; } // src/lib/parse-storyblok-src.ts var SIZE_PATTERN = /^(\d+)x(\d+)$/; var FOCAL_PATTERN = /focal\((\d+)x(\d+):(\d+)x(\d+)\)/; var ALLOWED_FORMATS = [ "avif", "jpeg", "png", "webp" ]; function parseStoryblokSrc(src, options) { let url; try { url = new URL(src); } catch (error) { console.error(error); throw new TypeError(`Invalid Storyblok image URL: ${src}`); } url.host = getStoryblokSrcHost(options?.host); const pathSegments = url.pathname.split("/").filter(Boolean); const mIndex = pathSegments.indexOf("m"); const baseSegments = mIndex >= 0 ? pathSegments.slice(0, mIndex) : pathSegments; const basePath = `/${baseSegments.join("/")}`; const filename = new URL(basePath, url).href; const result = { filename }; if (mIndex >= 0) { const sizeCandidate = pathSegments[mIndex + 1]; const sizeMatch = SIZE_PATTERN.exec(sizeCandidate || ""); if (sizeMatch) { const width = Number.parseInt(sizeMatch[1], 10); const height = Number.parseInt(sizeMatch[2], 10); if (!Number.isNaN(width) && !Number.isNaN(height)) { const resize = { height, width }; result.resize = resize; } } } const filtersSegment = pathSegments.find( (segment) => segment.startsWith("filters:") ); const { focus, format, quality } = parseFilters(filtersSegment); if (typeof quality !== "undefined") { result.quality = quality; } if (typeof format !== "undefined") { result.format = format; } if (typeof focus !== "undefined") { result.focus = focus; } return result; } function parseFilters(segment) { if (!segment || !segment.startsWith("filters:")) return {}; const rawFilters = segment.substring("filters:".length).replace(/:([a-z])/g, "__$1").split("__"); const parsed = {}; for (const filter of rawFilters) { if (filter.startsWith("quality")) { const value = Number.parseInt( filter.replace(/quality\((.+)\)/, "$1"), 10 ); if (!Number.isNaN(value) && value >= 1 && value <= 100) { parsed.quality = value; } } else if (filter.startsWith("format")) { const value = filter.replace( /format\((.+)\)/, "$1" ); if (ALLOWED_FORMATS.includes(value)) { parsed.format = value; } } else if (filter.startsWith("focal") && FOCAL_PATTERN.test(filter)) { parsed.focus = filter.replace( FOCAL_PATTERN, "$1x$2:$3x$4" ); } } return parsed; } // src/lib/get-storyblok-image-filename.ts function getStoryblokImageFilename(image, imageOptions) { let filename = ""; const options = imageOptions || {}; if (image && typeof image !== "string" && !!image?.focus) { options.focus = image?.focus; } if (typeof image === "string") { const parsed = parseStoryblokSrc(image, options); filename = parsed.filename; if (typeof parsed.focus !== "undefined") { options.focus = parsed.focus; } if (typeof parsed.format !== "undefined") { options.format = parsed.format; } if (typeof parsed.quality !== "undefined") { options.quality = parsed.quality; } if (typeof parsed.resize !== "undefined") { options.resize = parsed.resize; } } if (typeof image !== "string" && image?.filename) { filename = image?.filename; } return { filename, options }; } // src/lib/get-storyblok-image-quality.ts function getStoryblokImageQuality(input) { const quality = Math.floor(Math.max(0, Math.min(100, input))); return `quality(${quality})`; } // src/lib/get-storyblok-image-filters.ts function getStoryblokImageFilters(options) { const filters = []; if (options?.format) { filters.push(`format(${options.format})`); } if (typeof options?.quality === "number") { filters.push(getStoryblokImageQuality(options.quality)); } if (options?.resize && options?.focus) { filters.push(`focal(${options.focus})`); } const filtersString = filters.filter(Boolean).join(":"); return filtersString ? `filters:${filtersString}` : void 0; } // src/lib/storyblok-image-size-limit.ts var STORYBLOK_IMAGE_SIZE_LIMIT = 4e3; // src/lib/get-storyblok-image-size.ts function getStoryblokImageSize(resize) { if (!resize.width) { return; } let { height = 0, width } = resize; if (width > height && width > STORYBLOK_IMAGE_SIZE_LIMIT) { width = STORYBLOK_IMAGE_SIZE_LIMIT; height = resize.height ? Math.floor(resize.height / resize.width * width) : 0; } if (resize.height && height > width && height > STORYBLOK_IMAGE_SIZE_LIMIT) { height = STORYBLOK_IMAGE_SIZE_LIMIT; width = Math.floor(resize.width / resize.height * height); } return `${width}x${height}`; } // src/lib/img-src-is-storyblok.ts function imgSrcIsStoryblok(src, host = DEFAULT_HOST) { const url = new URL(src); return url.host.includes(host); } // src/lib/get-storyblok-src.ts function getStoryblokSrc(image, imageOptions) { if (typeof image === "string" && !imgSrcIsStoryblok(image, imageOptions?.host)) { return image; } const { filename, options } = getStoryblokImageFilename(image, imageOptions); if (!filename) { return; } const parts = [filename, "m"]; if (options?.resize) { parts.push(getStoryblokImageSize(options.resize)); } if ((options?.resize || options?.focus) && options?.smart !== false) { parts.push("smart"); } if (typeof options !== "undefined") { parts.push(getStoryblokImageFilters(options)); } const src = parts.filter(Boolean).join("/"); if (imageOptions?.prefix || process.env.STORYBLOK_IMAGE_LOADER_PREFIX) { const prefix = imageOptions?.prefix || process.env.STORYBLOK_IMAGE_LOADER_PREFIX; const url = new URL(src); return `${prefix}${url.pathname}`.replace("//", "/"); } return src; } // src/lib/get-storyblok-image-loader.ts function getStoryblokImageLoader(options = {}) { return ({ quality, src, width: inputWidth }) => { if (!imgSrcIsStoryblok(src, options.host)) { return src; } const url = new URL(src); const parsed = parseStoryblokSrc(src); const parts = url.pathname.split("/"); const size = parts[3]?.split("x"); if (!size || size.length < 2) { const loaderOptions = { ...options, resize: { width: inputWidth } }; if (typeof quality === "number") { loaderOptions.quality = quality; } return getStoryblokSrc(src, loaderOptions) || src; } const originalWidth = Number.parseInt(size[0], 10); const originalHeight = Number.parseInt(size[1], 10); const originalAspectRatio = originalWidth / originalHeight; let resizedAspectRatio = originalAspectRatio; if (parsed.resize?.height) { resizedAspectRatio = parsed.resize.width / parsed.resize.height; } const resize = { height: resizedAspectRatio ? Math.floor(inputWidth / resizedAspectRatio) : 0, width: inputWidth }; if (typeof quality !== "undefined") { options.quality = quality; } if (inputWidth !== void 0 && typeof resize !== "undefined") { options.resize = resize; } return getStoryblokSrc(src, options) || src; }; } // src/lib/storyblok-image-loader.ts var storyblokImageLoader = getStoryblokImageLoader(); exports.getStoryblokImageLoader = getStoryblokImageLoader; exports.getStoryblokSrc = getStoryblokSrc; exports.imgSrcIsStoryblok = imgSrcIsStoryblok; exports.parseStoryblokSrc = parseStoryblokSrc; exports.storyblokImageLoader = storyblokImageLoader; //# sourceMappingURL=index.cjs.map //# sourceMappingURL=index.cjs.map