diff --git a/.eslintrc b/.eslintrc index e44b4e25..cd3f5264 100644 --- a/.eslintrc +++ b/.eslintrc @@ -57,13 +57,6 @@ "no-iterator": 2, "no-lone-blocks": 2, "no-loop-func": 2, - "no-magic-numbers": [ - 2, - { - "ignore": [-1, 0, 1, 2, 3, 4, 100, 255], - "ignoreArrayIndexes": true - } - ], "no-multi-str": 2, "no-native-reassign": [ 2, @@ -134,7 +127,6 @@ ], "linebreak-style": [2, "unix"], "max-nested-callbacks": [2, 5], - "newline-after-var": [2, "always"], "no-array-constructor": 2, "no-lonely-if": 2, "no-negated-condition": 2, diff --git a/package-lock.json b/package-lock.json index c090d5b6..bdd45a57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8443,11 +8443,6 @@ "minimist": "^1.2.5" } }, - "jsontoxml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jsontoxml/-/jsontoxml-1.0.1.tgz", - "integrity": "sha512-dtKGq0K8EWQBRqcAaePSgKR4Hyjfsz/LkurHSV3Cxk4H+h2fWDeaN2jzABz+ZmOJylgXS7FGeWmbZ6jgYUMdJQ==" - }, "just-debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", diff --git a/package.json b/package.json index a5e98c53..e3cd3084 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,8 @@ "node": ">=10.13.0" }, "dependencies": { - "clone": "^2.1.2", "colors": "^1.4.0", "escape-html": "^1.0.3", - "jsontoxml": "^1.0.1", "lodash.defaultsdeep": "^4.6.1", "sharp": "^0.29.1", "through2": "^4.0.2", diff --git a/src/config/defaults.ts b/src/config/defaults.ts index b171240b..52b545ae 100644 --- a/src/config/defaults.ts +++ b/src/config/defaults.ts @@ -14,6 +14,8 @@ export interface IconOptions { readonly mask?: boolean; readonly overlayGlow?: boolean; readonly overlayShadow?: boolean; + readonly purpose?: string; + readonly pixelArt?: boolean; } export interface Application { @@ -42,6 +44,7 @@ export interface FaviconOptions { readonly appleStatusBarStyle?: string; readonly display?: string; readonly orientation?: string; + readonly scope?: string; readonly start_url?: string; readonly version?: string; readonly logging?: boolean; diff --git a/src/config/files.ts b/src/config/files.ts deleted file mode 100644 index d220db3e..00000000 --- a/src/config/files.ts +++ /dev/null @@ -1,136 +0,0 @@ -export const FILES_OPTIONS = { - android: { - "manifest.json": { - name: "Favicons", - short_name: "Favicons", - description: "Favicons", - dir: "auto", - lang: "en-US", - display: "standalone", - orientation: "portrait", - scope: "/", - start_url: "./?utm_source=web_app_manifest", - background_color: "#FFFFFF", - theme_color: "#FFFFFF", - icons: [ - { - src: "android-chrome-36x36.png", - sizes: "36x36", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-48x48.png", - sizes: "48x48", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-72x72.png", - sizes: "72x72", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-96x96.png", - sizes: "96x96", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-144x144.png", - sizes: "144x144", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-192x192.png", - sizes: "192x192", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-256x256.png", - sizes: "256x256", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-384x384.png", - sizes: "384x384", - type: "image/png", - purpose: "any", - }, - { - src: "android-chrome-512x512.png", - sizes: "512x512", - type: "image/png", - purpose: "any", - }, - ], - }, - }, - firefox: { - "manifest.webapp": { - version: "1.0", - name: "Favicons", - description: "Favicon generator for Node.js", - icons: { - 60: "firefox_app_60x60.png", - 128: "firefox_app_128x128.png", - 512: "firefox_app_512x512.png", - }, - developer: { - name: "Favicons", - url: "http://favicons.io", - }, - }, - }, - windows: { - "browserconfig.xml": [ - { - name: "browserconfig", - children: [ - { - name: "msapplication", - children: [ - { - name: "tile", - children: [ - { - name: "square70x70logo", - attrs: { src: "mstile-70x70.png" }, - }, - { - name: "square150x150logo", - attrs: { src: "mstile-150x150.png" }, - }, - { - name: "wide310x150logo", - attrs: { src: "mstile-310x150.png" }, - }, - { - name: "square310x310logo", - attrs: { src: "mstile-310x310.png" }, - }, - { name: "TileColor", text: "#FFFFFF" }, - ], - }, - ], - }, - ], - }, - ], - }, - yandex: { - "yandex-browser-manifest.json": { - version: 1, - api_version: 1, - layout: { - logo: "yandex-browser-50x50.png", - color: "#FFFFFF", - show_title: true, - }, - }, - }, -}; diff --git a/src/config/icons.ts b/src/config/icons.ts index 3b4803f8..b32ecf29 100644 --- a/src/config/icons.ts +++ b/src/config/icons.ts @@ -1,9 +1,6 @@ -/* eslint-disable no-magic-numbers */ - -import { Dictionary } from "../helpers"; import { IconOptions } from "./defaults"; -function transparentIcon(width: number, height?: number): IconOptions { +export function transparentIcon(width: number, height?: number): IconOptions { return { sizes: [{ width, height: height ?? width }], offset: 0, @@ -16,7 +13,7 @@ function transparentIcon(width: number, height?: number): IconOptions { }; } -function transparentIcons(...sizes: number[]): IconOptions { +export function transparentIcons(...sizes: number[]): IconOptions { return { sizes: sizes.map((size) => ({ width: size, height: size })), offset: 0, @@ -29,7 +26,7 @@ function transparentIcons(...sizes: number[]): IconOptions { }; } -function opaqueIcon(width: number, height?: number): IconOptions { +export function opaqueIcon(width: number, height?: number): IconOptions { return { sizes: [{ width, height: height ?? width }], offset: 0, @@ -42,7 +39,7 @@ function opaqueIcon(width: number, height?: number): IconOptions { }; } -function glowIcon(width: number, height?: number): IconOptions { +export function glowIcon(width: number, height?: number): IconOptions { return { sizes: [{ width, height: height ?? width }], offset: 0, @@ -55,90 +52,6 @@ function glowIcon(width: number, height?: number): IconOptions { }; } -export const ICONS_OPTIONS: Dictionary> = { - android: { - "android-chrome-36x36.png": transparentIcon(36), - "android-chrome-48x48.png": transparentIcon(48), - "android-chrome-72x72.png": transparentIcon(72), - "android-chrome-96x96.png": transparentIcon(96), - "android-chrome-144x144.png": transparentIcon(144), - "android-chrome-192x192.png": transparentIcon(192), - "android-chrome-256x256.png": transparentIcon(256), - "android-chrome-384x384.png": transparentIcon(384), - "android-chrome-512x512.png": transparentIcon(512), - }, - android_maskable: { - "android-chrome-maskable-36x36.png": transparentIcon(36), - "android-chrome-maskable-48x48.png": transparentIcon(48), - "android-chrome-maskable-72x72.png": transparentIcon(72), - "android-chrome-maskable-96x96.png": transparentIcon(96), - "android-chrome-maskable-144x144.png": transparentIcon(144), - "android-chrome-maskable-192x192.png": transparentIcon(192), - "android-chrome-maskable-256x256.png": transparentIcon(256), - "android-chrome-maskable-384x384.png": transparentIcon(384), - "android-chrome-maskable-512x512.png": transparentIcon(512), - }, - appleIcon: { - "apple-touch-icon-57x57.png": opaqueIcon(57), - "apple-touch-icon-60x60.png": opaqueIcon(60), - "apple-touch-icon-72x72.png": opaqueIcon(72), - "apple-touch-icon-76x76.png": opaqueIcon(76), - "apple-touch-icon-114x114.png": opaqueIcon(114), - "apple-touch-icon-120x120.png": opaqueIcon(120), - "apple-touch-icon-144x144.png": opaqueIcon(144), - "apple-touch-icon-152x152.png": opaqueIcon(152), - "apple-touch-icon-167x167.png": opaqueIcon(167), - "apple-touch-icon-180x180.png": opaqueIcon(180), - "apple-touch-icon-1024x1024.png": opaqueIcon(1024), - "apple-touch-icon.png": opaqueIcon(180), - "apple-touch-icon-precomposed.png": opaqueIcon(180), - }, - appleStartup: { - "apple-touch-startup-image-640x1136.png": opaqueIcon(640, 1136), - "apple-touch-startup-image-750x1334.png": opaqueIcon(750, 1334), - "apple-touch-startup-image-828x1792.png": opaqueIcon(828, 1792), - "apple-touch-startup-image-1125x2436.png": opaqueIcon(1125, 2436), - "apple-touch-startup-image-1242x2208.png": opaqueIcon(1242, 2208), - "apple-touch-startup-image-1242x2688.png": opaqueIcon(1242, 2688), - "apple-touch-startup-image-1536x2048.png": opaqueIcon(1536, 2048), - "apple-touch-startup-image-1668x2224.png": opaqueIcon(1668, 2224), - "apple-touch-startup-image-1668x2388.png": opaqueIcon(1668, 2388), - "apple-touch-startup-image-2048x2732.png": opaqueIcon(2048, 2732), - "apple-touch-startup-image-1136x640.png": opaqueIcon(1136, 640), - "apple-touch-startup-image-2160x1620.png": opaqueIcon(2160, 1620), - "apple-touch-startup-image-1620x2160.png": opaqueIcon(1620, 2160), - "apple-touch-startup-image-1334x750.png": opaqueIcon(1334, 750), - "apple-touch-startup-image-1792x828.png": opaqueIcon(1792, 828), - "apple-touch-startup-image-2436x1125.png": opaqueIcon(2436, 1125), - "apple-touch-startup-image-2208x1242.png": opaqueIcon(2208, 1242), - "apple-touch-startup-image-2688x1242.png": opaqueIcon(2688, 1242), - "apple-touch-startup-image-2048x1536.png": opaqueIcon(2048, 1536), - "apple-touch-startup-image-2224x1668.png": opaqueIcon(2224, 1668), - "apple-touch-startup-image-2388x1668.png": opaqueIcon(2388, 1668), - "apple-touch-startup-image-2732x2048.png": opaqueIcon(2732, 2048), - }, - coast: { - "coast-228x228.png": opaqueIcon(228), - }, - favicons: { - "favicon-16x16.png": transparentIcon(16), - "favicon-32x32.png": transparentIcon(32), - "favicon-48x48.png": transparentIcon(48), - "favicon.ico": transparentIcons(16, 24, 32, 48, 64), - }, - firefox: { - "firefox_app_60x60.png": glowIcon(60), - "firefox_app_128x128.png": glowIcon(128), - "firefox_app_512x512.png": glowIcon(512), - }, - windows: { - "mstile-70x70.png": transparentIcon(70), - "mstile-144x144.png": transparentIcon(144), - "mstile-150x150.png": transparentIcon(150), - "mstile-310x150.png": transparentIcon(310, 150), - "mstile-310x310.png": transparentIcon(310), - }, - yandex: { - "yandex-browser-50x50.png": transparentIcon(50), - }, -}; +export function maskable(options: IconOptions): IconOptions { + return { ...options, purpose: "maskable" }; +} diff --git a/src/helpers.ts b/src/helpers.ts index 683bfafc..a217955b 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,10 +1,11 @@ import * as path from "path"; import * as fs from "fs"; -import { promisify } from "util"; -import { magenta, green, yellow } from "colors"; -import jsonxml from "jsontoxml"; import sharp from "sharp"; -import xml2js from "xml2js"; +import { toIco } from "./ico"; +import { FaviconImage } from "."; +import { IconOptions } from "./config/defaults"; +import { SvgTool } from "./svgtool"; +import { logContext, Logger } from "./logger"; export type Dictionary = { [key: string]: T }; @@ -16,6 +17,7 @@ export interface IconPlaneOptions { readonly width: number; readonly height: number; readonly offset?: number; + readonly pixelArt: boolean; readonly background?: string; readonly transparent: boolean; readonly rotate: boolean; @@ -24,8 +26,6 @@ export interface IconPlaneOptions { readonly overlayShadow: boolean; } -const readFileAsync = promisify(fs.readFile); - function arrayComparator(a: unknown, b: unknown): number { const aArr = [a].flat(Infinity); const bArr = [b].flat(Infinity); @@ -87,7 +87,7 @@ export async function sourceImages( return Promise.reject(new Error("Invalid image buffer")); } } else if (typeof src === "string") { - const buffer = await readFileAsync(src); + const buffer = await fs.promises.readFile(src); return await sourceImages(buffer); } else if (Array.isArray(src) && !src.some(Array.isArray)) { @@ -102,41 +102,24 @@ export async function sourceImages( } } -export interface BlankImageProps { - readonly width: number; - readonly height: number; - readonly background?: string | boolean; - readonly transparent?: boolean; +function flattenIconOptions(iconOptions: IconOptions): IconPlaneOptions[] { + return iconOptions.sizes.map((size) => ({ + ...size, + offset: iconOptions.offset ?? 0, + pixelArt: iconOptions.pixelArt ?? false, + background: asString(iconOptions.background), + transparent: iconOptions.transparent, + mask: iconOptions.mask ?? false, + overlayGlow: iconOptions.overlayGlow ?? false, + overlayShadow: iconOptions.overlayShadow ?? false, + rotate: iconOptions.rotate, + })); } -export async function createBlankImage( - properties: BlankImageProps -): Promise { - const transparent = - !properties.background || properties.background === "transparent"; - - let image = sharp({ - create: { - width: properties.width, - height: properties.height, - channels: transparent ? 4 : 3, - background: transparent ? "#00000000" : (properties.background as string), - }, - }); - - if (transparent) { - image = image.ensureAlpha(); - } - return await image.png().toBuffer(); -} - -function offsetPixels(properties: IconPlaneOptions): number { - const maximum = Math.max(properties.width, properties.height); - - return Math.round((maximum / 100) * properties.offset) || 0; -} - -function relativeTo(base: string | undefined | null, path: string): string { +export function relativeTo( + base: string | undefined | null, + path: string +): string { if (!base) { return path; } @@ -147,318 +130,226 @@ function relativeTo(base: string | undefined | null, path: string): string { return url.protocol === "resolve:" ? url.pathname : url.toString(); } -export function helpers(options) { - function log(context: string, message: string) { - if (options.logging) { - message = message.replace(/ \d+(x\d+)?/g, (item) => magenta(item)); - message = message.replace(/#([0-9a-f]{3}){1,2}/g, (item) => - magenta(item) - ); - console.log(`${green("[Favicons]")} ${yellow(context)}: ${message}...`); +export class Images { + #log: Logger; + #svgtool: SvgTool; + + constructor(logger: Logger) { + this.#log = logContext(logger, "Image"); + this.#svgtool = new SvgTool(logger); + } + + bestSource( + sourceset: SourceImage[], + width: number, + height: number + ): SourceImage { + this.#log("bestSource", `Find nearest icon to ${width}x${height}`); + const sideSize = Math.max(width, height); + return minByKey(sourceset, (icon) => { + const iconSideSize = Math.max(icon.metadata.width, icon.metadata.height); + return [ + icon.metadata.format === "svg" ? 0 : 1, // prefer SVG + iconSideSize >= sideSize ? 0 : 1, // prefer downscale + Math.abs(iconSideSize - sideSize), // prefer closest size + ]; + }); + } + + async resize( + source: SourceImage, + width: number, + height: number, + pixelArt: boolean + ): Promise { + this.#log("render", `Resizing to ${width}x${height}`); + + if (source.metadata.format === "svg") { + this.#log("render", `Rendering SVG to ${width}x${height}`); + const svgBuffer = await this.#svgtool.ensureSize(source, width, height); + return await sharp(svgBuffer) + .resize({ + width, + height, + fit: sharp.fit.contain, + background: "#00000000", + }) + .toBuffer(); + } + + return await sharp(source.data) + .ensureAlpha() + .resize({ + width, + height, + fit: sharp.fit.contain, + background: "#00000000", + kernel: + pixelArt && + width >= source.metadata.width && + height >= source.metadata.height + ? "nearest" + : "lanczos3", + }) + .toBuffer(); + } + + async createBlankImage( + width: number, + height: number, + background?: string + ): Promise { + const transparent = !background || background === "transparent"; + + let image = sharp({ + create: { + width, + height, + channels: transparent ? 4 : 3, + background: transparent ? "#00000000" : background, + }, + }); + + if (transparent) { + image = image.ensureAlpha(); } + return await image.png().toBuffer(); + } + + mask() { + return path.join(__dirname, "mask.png"); } - // sharp renders the SVG in its source width and height with 72 DPI which can - // cause a blurry result in case the source SVG is defined in lower size than - // the target size. To avoid this, resize the source SVG to the needed size - // before passing it to sharp by increasing its width and/or height - // attributes. - // - // Currently it seems this won't be fixed in sharp, so we need a workaround: - // https://github.com/lovell/sharp/issues/729#issuecomment-284708688 - // - // They suggest setting the image density to a "resized" density based on the - // target render size but this does not seem to work with favicons and may - // cause other errors with "unnecessarily high" image density values. - // - // For further information, see: - // https://github.com/itgalaxy/favicons/issues/264 - const svgtool = { - async ensureSize( - svgSource: SourceImage, - width: number, - height: number - ): Promise { - let svgWidth = svgSource.metadata.width; - let svgHeight = svgSource.metadata.height; - - if (svgWidth >= width && svgHeight >= height) { - // If the base SVG is large enough, it does not need to be modified. - return svgSource.data; - } else if (width > height) { - svgHeight = Math.round(svgHeight * (width / svgWidth)); - svgWidth = width; - } else { - // width <= height - svgWidth = Math.round(svgWidth * (height / svgHeight)); - svgHeight = height; + overlayGlow() { + return path.join(__dirname, "overlay-glow.png"); + } + + overlayShadow() { + // Gimp drop shadow filter: input: mask.png, config: X: 2, Y: 5, Offset: 5, Color: black, Opacity: 20 + return path.join(__dirname, "overlay-shadow.png"); + } + + async maskImage(image: Buffer, mask: string): Promise { + const pipeline = sharp(image); + const meta = await pipeline.metadata(); + + const maskBuffer = await sharp(mask) + .resize({ + width: meta.width, + height: meta.height, + fit: sharp.fit.contain, + background: "#00000000", + }) + .toColourspace("b-w") + .toBuffer(); + + return await pipeline.joinChannel(maskBuffer).png().toBuffer(); + } + + async overlay(image: Buffer, coverPath: string): Promise { + const pipeline = sharp(image); + const meta = await pipeline.metadata(); + + const cover = await sharp(coverPath) + .resize({ + width: meta.width, + height: meta.height, + fit: sharp.fit.contain, + }) + .png() + .toBuffer(); + + return await pipeline + .composite([{ input: cover, left: 0, top: 0 }]) + .png() + .toBuffer(); + } + + async createPlaneFavicon( + sourceset: SourceImage[], + options: IconPlaneOptions, + name: string, + raw = false + ): Promise { + this.#log( + "createPlaneFavicon", + `Creating empty ${options.width}x${options.height} canvas with ${options.background} background` + ); + + const offset = + Math.round( + (Math.max(options.width, options.height) * options.offset) / 100 + ) || 0; + const width = options.width - offset * 2; + const height = options.height - offset * 2; + + const source = this.bestSource(sourceset, width, height); + const image = await this.resize(source, width, height, options.pixelArt); + + let canvas = await this.createBlankImage( + options.width, + options.height, + options.background + ); + if (options.mask) { + this.#log("createPlaneFavicon", "Masking composite image on circle"); + + canvas = await this.maskImage(canvas, this.mask()); + + if (options.overlayGlow) { + canvas = await this.overlay(canvas, this.overlayGlow()); + } + if (options.overlayShadow) { + canvas = await this.overlay(canvas, this.overlayShadow()); } + } - // Modify the source SVG's width and height attributes for sharp to render - // it correctly. - log("svgtool:ensureSize", `Resizing SVG to ${svgWidth}x${svgHeight}`); - return await this.resize(svgSource.data, svgWidth, svgHeight); - }, - - async resize( - svgFile: Buffer, - width: number, - height: number - ): Promise { - const xmlDoc = await xml2js.parseStringPromise(svgFile); - - xmlDoc.svg.$.width = width; - xmlDoc.svg.$.height = height; - - const builder = new xml2js.Builder(); - const modifiedSvg = builder.buildObject(xmlDoc); - - return Buffer.from(modifiedSvg); - }, - }; - - return { - log, - - HTML: { - render(htmlTemplate) { - return htmlTemplate({ - ...options, - relative(path: string): string { - return relativeTo(options.path, path); - }, - }); - }, - }, - - Files: { - create(properties, name) { - log("Files:create", `Creating file: ${name}`); - const basePath = options.manifestRelativePaths ? null : options.path; - - if (name === "manifest.json") { - properties.name = options.appName; - properties.short_name = options.appShortName || options.appName; - properties.description = options.appDescription; - properties.dir = options.dir; - properties.lang = options.lang; - properties.display = options.display; - properties.orientation = options.orientation; - properties.scope = options.scope; - properties.start_url = options.start_url; - properties.background_color = options.background; - properties.theme_color = options.theme_color; - - // Defaults to false, so omit the value https://developer.mozilla.org/en-US/docs/Web/Manifest/prefer_related_applications - if (options.preferRelatedApplications) { - properties.prefer_related_applications = - options.preferRelatedApplications; - } - // Only include related_applications if a lengthy array is provided. - if ( - Array.isArray(options.relatedApplications) && - options.relatedApplications.length > 0 - ) { - properties.related_applications = options.relatedApplications; - } - - properties.icons.forEach((icon) => { - icon.src = relativeTo(basePath, icon.src); - icon.purpose = - options.manifestMaskable === true ? "any maskable" : "any"; - }); - // If manifestMaskable is set but is not a boolean - // assume a file (or an array) is passed, and we should link - // the generated files with maskable as purpose. - if ( - options.manifestMaskable && - typeof options.manifestMaskable !== "boolean" - ) { - const maskableIcons = properties.icons.map((icon) => ({ - ...icon, - src: icon.src.replace( - /android-chrome-(.+)\.png$/, - "android-chrome-maskable-$1.png" - ), - purpose: "maskable", - })); - - properties.icons = [...properties.icons, ...maskableIcons]; - } - properties = JSON.stringify(properties, null, 2); - } else if (name === "manifest.webapp") { - properties.version = options.version; - properties.name = options.appName; - properties.description = options.appDescription; - properties.developer.name = options.developerName; - properties.developer.url = options.developerURL; - properties.icons = mapValues(properties.icons, (icon: string) => - relativeTo(basePath, icon) - ); - properties = JSON.stringify(properties, null, 2); - } else if (name === "browserconfig.xml") { - properties[0].children[0].children[0].children.map((property) => { - if (property.name === "TileColor") { - property.text = options.background; - } else { - property.attrs.src = relativeTo(basePath, property.attrs.src); - } - }); - properties = jsonxml(properties, { - prettyPrint: true, - xmlHeader: true, - indent: " ", - }); - } else if (name === "yandex-browser-manifest.json") { - properties.version = options.version; - properties.api_version = 1; - properties.layout.logo = relativeTo(basePath, properties.layout.logo); - properties.layout.color = options.background; - properties = JSON.stringify(properties, null, 2); - } else { - return Promise.reject(`Unknown format of file ${name}.`); - } - return Promise.resolve({ name, contents: properties }); - }, - }, - - Images: { - async render( - sourceset: SourceImage[], - properties: IconPlaneOptions - ): Promise { - const offset = offsetPixels(properties); - const width = properties.width - offset * 2; - const height = properties.height - offset * 2; - - const svgSource = sourceset.find( - (source) => source.metadata.format === "svg" - ); - - if (svgSource) { - log("Image:render", `Rendering SVG to ${width}x${height}`); - const svgBuffer = await svgtool.ensureSize(svgSource, width, height); - - return await sharp(svgBuffer) - .resize({ - width, - height, - fit: sharp.fit.contain, - background: "#00000000", - }) - .toBuffer(); - } - - log( - "Image:render", - `Find nearest icon to ${width}x${height} with offset ${offset}` - ); - const sideSize = Math.max(width, height); - const nearest = minByKey(sourceset, (icon) => { - const iconSideSize = Math.max( - icon.metadata.width, - icon.metadata.height - ); - - return [ - iconSideSize >= sideSize ? 0 : 1, - Math.abs(iconSideSize - sideSize), - ]; - }); - - log("Images:render", `Resizing PNG to ${width}x${height}`); - - const image = await sharp(nearest.data).ensureAlpha(); - const metadata = await image.metadata(); - - return await image - .resize({ - width, - height, - fit: sharp.fit.contain, - background: "#00000000", - kernel: - options.pixel_art && - width >= metadata.width && - height >= metadata.height - ? "nearest" - : "lanczos3", - }) - .toBuffer(); - }, + let pipeline = sharp(canvas).composite([ + { input: image, left: offset, top: offset }, + ]); - mask: path.join(__dirname, "mask.png"), - overlayGlow: path.join(__dirname, "overlay-glow.png"), - // Gimp drop shadow filter: input: mask.png, config: X: 2, Y: 5, Offset: 5, Color: black, Opacity: 20 - overlayShadow: path.join(__dirname, "overlay-shadow.png"), - - async maskImage(image: Buffer, mask: string): Promise { - const pipeline = sharp(image); - const meta = await pipeline.metadata(); - - const maskBuffer = await sharp(mask) - .resize({ - width: meta.width, - height: meta.height, - fit: sharp.fit.contain, - background: "#00000000", - }) - .toColourspace("b-w") - .toBuffer(); - - return await pipeline.joinChannel(maskBuffer).png().toBuffer(); - }, + if (options.rotate) { + const degrees = 90; + this.#log("createPlaneFavicon", `Rotating image by ${degrees}`); + pipeline = pipeline.rotate(degrees); + } - async overlay(image: Buffer, coverPath: string): Promise { - const pipeline = sharp(image); - const meta = await pipeline.metadata(); - - const cover = await sharp(coverPath) - .resize({ - width: meta.width, - height: meta.height, - fit: sharp.fit.contain, - }) - .png() - .toBuffer(); - - return await pipeline - .composite([{ input: cover, left: 0, top: 0 }]) - .png() - .toBuffer(); - }, + const contents = raw + ? await pipeline + .toColorspace("srgb") + .raw({ depth: "uchar" }) + .toBuffer({ resolveWithObject: true }) + : await pipeline.png().toBuffer(); - async composite( - canvas: Buffer, - image: Buffer, - properties: IconPlaneOptions, - raw = false - ): Promise { - log( - "Images:composite", - `Compositing favicon on ${properties.width}x${properties.height} canvas with offset ${properties.offset}` - ); - - const offset = offsetPixels(properties); - let pipeline = sharp(canvas).composite([ - { input: image, left: offset, top: offset }, - ]); - - if (properties.rotate) { - const degrees = 90; - - log("Images:render", `Rotating image by ${degrees}`); - pipeline = pipeline.rotate(degrees); - } - - if (raw) { - return await pipeline - .toColorspace("srgb") - .raw({ depth: "uchar" }) - .toBuffer({ resolveWithObject: true }); - } - return await pipeline.png().toBuffer(); - }, - }, - }; + return { name, contents }; + } + + async createFavicon( + sourceset: SourceImage[], + name: string, + iconOptions: IconOptions + ): Promise { + const properties = flattenIconOptions(iconOptions); + + if (path.extname(name) === ".ico" || properties.length !== 1) { + const images = await Promise.all( + properties.map((props) => + this.createPlaneFavicon( + sourceset, + props, + `${props.width}x${props.height}.rawdata`, + true + ) + ) + ); + const contents = toIco(images.map((image) => image.contents as RawImage)); + + return { + name, + contents, + }; + } + + return await this.createPlaneFavicon(sourceset, properties[0], name, false); + } } diff --git a/src/index.ts b/src/index.ts index 1f1a094d..1fc090e7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,27 +3,12 @@ // TO_DO: More comments to know what's going on, for future maintainers import through2 from "through2"; -import clone from "clone"; import defaultsDeep from "lodash.defaultsdeep"; -import * as path from "path"; import File from "vinyl"; -import { FaviconOptions, defaultOptions, IconOptions } from "./config/defaults"; -import { FILES_OPTIONS } from "./config/files"; -import { HTML_TEMPLATES } from "./config/html"; -import { ICONS_OPTIONS } from "./config/icons"; -import { - asString, - createBlankImage, - Dictionary, - filterKeys, - helpers, - IconPlaneOptions, - mapValues, - RawImage, - SourceImage, - sourceImages, -} from "./helpers"; -import { toIco } from "./ico"; +import { FaviconOptions, defaultOptions } from "./config/defaults"; +import { RawImage, sourceImages } from "./helpers"; +import { getPlatform } from "./platforms"; +import { dummyLog, Logger, prettyLog } from "./logger"; export interface FaviconImage { readonly name: string; @@ -37,9 +22,6 @@ export interface FaviconFile { export const config = { defaults: defaultOptions, - files: FILES_OPTIONS, - html: HTML_TEMPLATES, - icons: ICONS_OPTIONS, }; export type FaviconHtmlElement = string; @@ -50,6 +32,40 @@ export interface FaviconResponse { readonly html: FaviconHtmlElement[]; } +async function createFavicons( + source: string | string[] | Buffer | Buffer[], + options: FaviconOptions +): Promise { + options = defaultsDeep(options, defaultOptions); + + const log: Logger = options.logging ? prettyLog : dummyLog; + + log("General:source", `Source type is ${typeof source}`); + const sourceset = await sourceImages(source); + + const platforms = Object.keys(options.icons) + .filter((platform) => options.icons[platform]) + .sort((a, b) => { + if (a === "favicons") return -1; + if (b === "favicons") return 1; + return a.localeCompare(b); + }); + + const responses = []; + + for (const platformName of platforms) { + const platform = getPlatform(platformName, options, log); + + responses.push(await platform.create(sourceset)); + } + + return { + images: responses.flatMap((r) => r.images), + files: responses.flatMap((r) => r.files), + html: responses.flatMap((r) => r.html), + }; +} + /** * @typedef FaviconCallback * @type {(error: Error|null, response: FaviconResponse) => any} @@ -73,194 +89,7 @@ export function favicons( .then((response) => next(null, response)) .catch(next); } - - options = defaultsDeep(options, defaultOptions); - - const configCopy = clone(config); - const µ = helpers(options); - - async function createFavicon( - sourceset: SourceImage[], - properties: IconPlaneOptions[], - name: string, - raw = false - ): Promise { - if (path.extname(name) === ".ico" || properties.length !== 1) { - const images = await Promise.all( - properties.map((props) => - createPlaneFavicon( - sourceset, - props, - `${props.width}x${props.height}.rawdata`, - true - ) - ) - ); - const contents = toIco(images.map((image) => image.contents as RawImage)); - - return { - name, - contents, - }; - } - - return await createPlaneFavicon(sourceset, properties[0], name, raw); - } - - async function createPlaneFavicon( - sourceset: SourceImage[], - properties: IconPlaneOptions, - name: string, - raw = false - ): Promise { - µ.log( - "Image:create", - `Creating empty ${properties.width}x${properties.height} canvas with ${properties.background} background` - ); - - let canvas = await createBlankImage(properties); - - if (properties.mask) { - µ.log("Images:composite", "Masking composite image on circle"); - - canvas = await µ.Images.maskImage(canvas, µ.Images.mask); - - if (properties.overlayGlow) { - canvas = await µ.Images.overlay(canvas, µ.Images.overlayGlow); - } - if (properties.overlayShadow) { - canvas = await µ.Images.overlay(canvas, µ.Images.overlayShadow); - } - } - - const image = await µ.Images.render(sourceset, properties); - const contents = await µ.Images.composite(canvas, image, properties, raw); - - return { name, contents }; - } - - async function createHTML(platform): Promise { - if (!options.output.html) return []; - return await Promise.all( - (configCopy.html[platform] || []).map(µ.HTML.render) - ); - } - - function createFiles(platform) { - if (!options.output.files) return []; - return Promise.all( - Object.keys(configCopy.files[platform] || {}).map((name) => - µ.Files.create(configCopy.files[platform][name], name) - ) - ); - } - - function uniformIconOptions(platform: string): Dictionary { - const platformConfig: Dictionary = - configCopy.icons[platform] ?? {}; - - const iconsChoice = options.icons[platform]; - - if (Array.isArray(iconsChoice)) { - return filterKeys(platformConfig, (name) => iconsChoice.includes(name)); - } else if (typeof iconsChoice === "object") { - return mapValues(platformConfig, (iconOptions: IconOptions) => ({ - ...iconOptions, - ...iconsChoice, - })); - } - return platformConfig; - } - - function flattenIconOptions(iconOptions: IconOptions): IconPlaneOptions[] { - return iconOptions.sizes.map((size) => ({ - ...size, - offset: iconOptions.offset ?? 0, - background: - iconOptions.background === true - ? options.background - : asString(iconOptions.background), - transparent: iconOptions.transparent, - mask: iconOptions.mask ?? false, - overlayGlow: iconOptions.overlayGlow ?? false, - overlayShadow: iconOptions.overlayShadow ?? false, - rotate: iconOptions.rotate, - })); - } - - async function createFavicons( - sourceset: SourceImage[], - platform: string - ): Promise { - if (!options.output.images) return []; - - const iconOptions = uniformIconOptions(platform); - - return await Promise.all( - Object.entries(iconOptions).map(([iconName, iconOptions]) => { - const iconPlaneOptions = flattenIconOptions(iconOptions); - - return createFavicon(sourceset, iconPlaneOptions, iconName); - }) - ); - } - - async function createPlatform( - sourceset: SourceImage[], - platform - ): Promise { - const imagesPromise = createFavicons(sourceset, platform); - const filesPromise = createFiles(platform); - const htmlPromise = createHTML(platform); - - return { - images: await imagesPromise, - files: await filesPromise, - html: await htmlPromise, - }; - } - - async function create(sourceset: SourceImage[]): Promise { - const responses = []; - - const platforms = Object.keys(options.icons) - .filter((platform) => options.icons[platform]) - .sort((a, b) => { - if (a === "favicons") return -1; - if (b === "favicons") return 1; - return a.localeCompare(b); - }); - - for (const platform of platforms) { - responses.push(await createPlatform(sourceset, platform)); - } - - // Generate android maskable images from a different source set - if ( - options.icons.android && - options.manifestMaskable && - typeof options.manifestMaskable !== "boolean" - ) { - µ.log( - "General:source", - `Maskable source type is ${typeof options.manifestMaskable}` - ); - const maskableSourceset = await sourceImages(options.manifestMaskable); - - responses.push( - await createPlatform(maskableSourceset, "android_maskable") - ); - } - - return { - images: responses.flatMap((r) => r.images), - files: responses.flatMap((r) => r.files), - html: responses.flatMap((r) => r.html), - }; - } - - µ.log("General:source", `Source type is ${typeof source}`); - return sourceImages(source).then(create); + return createFavicons(source, options); } export default favicons; diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 00000000..22d2bdd0 --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,19 @@ +import { magenta, green, yellow } from "colors"; + +export type Logger = (context: string, message: string) => void; + +export function dummyLog() { + // do nothing +} + +export function prettyLog(context: string, message: string) { + message = message.replace(/ \d+(x\d+)?/g, (item) => magenta(item)); + message = message.replace(/#([0-9a-f]{3}){1,2}/g, (item) => magenta(item)); + console.log(`${green("[Favicons]")} ${yellow(context)}: ${message}...`); +} + +export function logContext(logger: Logger, context: string): Logger { + return (innerContext: string, message: string) => { + logger(`${context}:${innerContext}`, message); + }; +} diff --git a/src/platforms/android.ts b/src/platforms/android.ts new file mode 100644 index 00000000..10fc278f --- /dev/null +++ b/src/platforms/android.ts @@ -0,0 +1,166 @@ +import escapeHtml from "escape-html"; +import { FaviconFile, FaviconHtmlElement, FaviconImage } from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { maskable, transparentIcon } from "../config/icons"; +import { + Dictionary, + Images, + relativeTo, + SourceImage, + sourceImages, +} from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "android-chrome-36x36.png": transparentIcon(36), + "android-chrome-48x48.png": transparentIcon(48), + "android-chrome-72x72.png": transparentIcon(72), + "android-chrome-96x96.png": transparentIcon(96), + "android-chrome-144x144.png": transparentIcon(144), + "android-chrome-192x192.png": transparentIcon(192), + "android-chrome-256x256.png": transparentIcon(256), + "android-chrome-384x384.png": transparentIcon(384), + "android-chrome-512x512.png": transparentIcon(512), +}; + +const ICONS_OPTIONS_MASKABLE: Dictionary = { + "android-chrome-maskable-36x36.png": maskable(transparentIcon(36)), + "android-chrome-maskable-48x48.png": maskable(transparentIcon(48)), + "android-chrome-maskable-72x72.png": maskable(transparentIcon(72)), + "android-chrome-maskable-96x96.png": maskable(transparentIcon(96)), + "android-chrome-maskable-144x144.png": maskable(transparentIcon(144)), + "android-chrome-maskable-192x192.png": maskable(transparentIcon(192)), + "android-chrome-maskable-256x256.png": maskable(transparentIcon(256)), + "android-chrome-maskable-384x384.png": maskable(transparentIcon(384)), + "android-chrome-maskable-512x512.png": maskable(transparentIcon(512)), +}; + +function androidManifest( + options: FaviconOptions, + iconOptions: Dictionary +): FaviconFile { + const basePath = options.manifestRelativePaths ? null : options.path; + + const properties: Dictionary = { + name: options.appName, + short_name: options.appShortName || options.appName, + description: options.appDescription, + dir: options.dir, + lang: options.lang, + display: options.display, + orientation: options.orientation, + scope: options.scope, + start_url: options.start_url, + background_color: options.background, + theme_color: options.theme_color, + }; + + // Defaults to false, so omit the value https://developer.mozilla.org/en-US/docs/Web/Manifest/prefer_related_applications + if (options.preferRelatedApplications) { + properties.prefer_related_applications = options.preferRelatedApplications; + } + // Only include related_applications if a lengthy array is provided. + if ( + Array.isArray(options.relatedApplications) && + options.relatedApplications.length > 0 + ) { + properties.related_applications = options.relatedApplications; + } + + let icons = iconOptions; + + // If manifestMaskable is set but is not a boolean + // assume a file (or an array) is passed, and we should link + // the generated files with maskable as purpose. + if ( + options.manifestMaskable && + typeof options.manifestMaskable !== "boolean" + ) { + icons = { + ...icons, + ...ICONS_OPTIONS_MASKABLE, + }; + } + + const defaultPurpose = + options.manifestMaskable === true ? "any maskable" : "any"; + + properties.icons = Object.entries(icons).map(([name, iconOptions]) => { + const { width, height } = iconOptions.sizes[0]; + + return { + src: relativeTo(basePath, name), + sizes: `${width}x${height}`, + type: "image/png", + purpose: iconOptions.purpose ?? defaultPurpose, + }; + }); + + return { + name: "manifest.json", + contents: JSON.stringify(properties, null, 2), + }; +} + +export class AndroidPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.android, ICONS_OPTIONS), + logContext(logger, "android") + ); + } + + async createImages(sourceset: SourceImage[]): Promise { + const images = new Images(this.log); + + let icons = await Promise.all( + Object.entries(this.iconOptions).map(([iconName, iconOption]) => + images.createFavicon(sourceset, iconName, iconOption) + ) + ); + + // Generate android maskable images from a different source set + if ( + this.options.manifestMaskable && + typeof this.options.manifestMaskable !== "boolean" + ) { + this.log( + "General:source", + `Maskable source type is ${typeof this.options.manifestMaskable}` + ); + const maskableSourceset = await sourceImages( + this.options.manifestMaskable + ); + + const maskable = await Promise.all( + Object.entries(ICONS_OPTIONS_MASKABLE).map(([iconName, iconOption]) => + images.createFavicon(maskableSourceset, iconName, iconOption) + ) + ); + + icons = [...icons, ...maskable]; + } + + return icons; + } + + async createFiles(): Promise { + return [androidManifest(this.options, this.iconOptions)]; + } + + async createHtml(): Promise { + // prettier-ignore + return [ + this.options.loadManifestWithCredentials + ? `` + : ``, + ``, + ``, + this.options.appName + ? `` + : ``, + ]; + } +} diff --git a/src/platforms/appleIcon.ts b/src/platforms/appleIcon.ts new file mode 100644 index 00000000..0b1ff70a --- /dev/null +++ b/src/platforms/appleIcon.ts @@ -0,0 +1,56 @@ +import escapeHtml from "escape-html"; +import { FaviconHtmlElement } from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { opaqueIcon } from "../config/icons"; +import { Dictionary } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "apple-touch-icon-57x57.png": opaqueIcon(57), + "apple-touch-icon-60x60.png": opaqueIcon(60), + "apple-touch-icon-72x72.png": opaqueIcon(72), + "apple-touch-icon-76x76.png": opaqueIcon(76), + "apple-touch-icon-114x114.png": opaqueIcon(114), + "apple-touch-icon-120x120.png": opaqueIcon(120), + "apple-touch-icon-144x144.png": opaqueIcon(144), + "apple-touch-icon-152x152.png": opaqueIcon(152), + "apple-touch-icon-167x167.png": opaqueIcon(167), + "apple-touch-icon-180x180.png": opaqueIcon(180), + "apple-touch-icon-1024x1024.png": opaqueIcon(1024), + "apple-touch-icon.png": opaqueIcon(180), + "apple-touch-icon-precomposed.png": opaqueIcon(180), +}; + +export class AppleIconPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.appleIcon, ICONS_OPTIONS), + logContext(logger, "appleIcon") + ); + } + + async createHtml(): Promise { + const icons = Object.entries(this.iconOptions) + .filter(([name]) => /\d/.test(name)) // with a size in a name + .map(([name, options]) => { + const { width, height } = options.sizes[0]; + + // prettier-ignore + return ``; + }); + + const name = this.options.appShortName || this.options.appName; + + // prettier-ignore + return [ + ...icons, + ``, + ``, + name + ? `` + : `` + ]; + } +} diff --git a/src/config/html.ts b/src/platforms/appleStartup.ts similarity index 55% rename from src/config/html.ts rename to src/platforms/appleStartup.ts index 7cc08fe3..a1d0abed 100644 --- a/src/config/html.ts +++ b/src/platforms/appleStartup.ts @@ -1,10 +1,36 @@ -/* eslint-disable */ -import escapeHtml from "escape-html"; +import { FaviconHtmlElement } from ".."; +import { FaviconOptions, IconOptions, IconSize } from "../config/defaults"; +import { opaqueIcon } from "../config/icons"; +import { Dictionary } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; -const appleIconSizes = [57, 60, 72, 76, 114, 120, 144, 152, 167, 180, 1024]; +const ICONS_OPTIONS: Dictionary = { + "apple-touch-startup-image-640x1136.png": opaqueIcon(640, 1136), + "apple-touch-startup-image-750x1334.png": opaqueIcon(750, 1334), + "apple-touch-startup-image-828x1792.png": opaqueIcon(828, 1792), + "apple-touch-startup-image-1125x2436.png": opaqueIcon(1125, 2436), + "apple-touch-startup-image-1242x2208.png": opaqueIcon(1242, 2208), + "apple-touch-startup-image-1242x2688.png": opaqueIcon(1242, 2688), + "apple-touch-startup-image-1536x2048.png": opaqueIcon(1536, 2048), + "apple-touch-startup-image-1668x2224.png": opaqueIcon(1668, 2224), + "apple-touch-startup-image-1668x2388.png": opaqueIcon(1668, 2388), + "apple-touch-startup-image-2048x2732.png": opaqueIcon(2048, 2732), + "apple-touch-startup-image-1136x640.png": opaqueIcon(1136, 640), + "apple-touch-startup-image-2160x1620.png": opaqueIcon(2160, 1620), + "apple-touch-startup-image-1620x2160.png": opaqueIcon(1620, 2160), + "apple-touch-startup-image-1334x750.png": opaqueIcon(1334, 750), + "apple-touch-startup-image-1792x828.png": opaqueIcon(1792, 828), + "apple-touch-startup-image-2436x1125.png": opaqueIcon(2436, 1125), + "apple-touch-startup-image-2208x1242.png": opaqueIcon(2208, 1242), + "apple-touch-startup-image-2688x1242.png": opaqueIcon(2688, 1242), + "apple-touch-startup-image-2048x1536.png": opaqueIcon(2048, 1536), + "apple-touch-startup-image-2224x1668.png": opaqueIcon(2224, 1668), + "apple-touch-startup-image-2388x1668.png": opaqueIcon(2388, 1668), + "apple-touch-startup-image-2732x2048.png": opaqueIcon(2732, 2048), +}; -const appleStartupItems = [ - // +const ITEMS = [ // Device Portrait size Landscape size Screen size Pixel ratio // iPhone SE 640px × 1136px 1136px × 640px 320px × 568px 2 // iPhone 8 750px × 1334px 1334px × 750px 375px × 667px 2 @@ -111,7 +137,6 @@ const appleStartupItems = [ width: 1620, height: 2160, }, - { dwidth: 320, dheight: 568, @@ -202,86 +227,31 @@ const appleStartupItems = [ }, ]; -const coastSizes = [228]; - -const faviconSizes = [16, 32, 48]; - -function ctxHasIcons(icons, icon) { - if (Array.isArray(icons)) return icons.includes(icon); - return icons; -} - -function appleIconGen(size, { relative, icons }) { - const iconName = `apple-touch-icon-${size}x${size}.png`; - - return !ctxHasIcons(icons.appleIcon, iconName) - ? "" - : ``; -} - -function appleStartupGen( - { width, height, dwidth, dheight, pixelRatio, orientation }, - { relative, icons } -) { - const iconName = `apple-touch-startup-image-${width}x${height}.png`; +export class AppleStartupPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.appleStartup, ICONS_OPTIONS), + logContext(logger, "appleStartup") + ); + } - return !ctxHasIcons(icons.appleStartup, iconName) - ? "" - : ``; -} + findBySize({ width, height }: IconSize): [string, IconOptions] | undefined { + return Object.entries(this.iconOptions).find((entry) => + entry[1].sizes.find( + (size) => size.width === width && size.height === height + ) + ); + } -function coastGen(size, { relative, icons }) { - const iconName = `coast-${size}x${size}.png`; + async createHtml(): Promise { + return ITEMS.map((item) => { + const icon = this.findBySize(item); - return !ctxHasIcons(icons.coast, iconName) - ? "" - : ``; + // prettier-ignore + return icon + ? `` + : ""; + }); + } } - -function faviconGen(size, { relative, icons }) { - const iconName = `favicon-${size}x${size}.png`; - return !ctxHasIcons(icons.favicons, iconName) - ? "" - : ``; -} - -// prettier-ignore -export const HTML_TEMPLATES = { - android: [ - ({ relative, loadManifestWithCredentials }) => - loadManifestWithCredentials - ? `` - : ``, - () => ``, - ({ theme_color, background }) => ``, - ({ appName }) => appName ? `` : `` - ], - appleIcon: [ - ...appleIconSizes.map(size => ctx => appleIconGen(size, ctx)), - () => ``, - ({ appleStatusBarStyle }) => ``, - ({ appShortName, appName }) => (appShortName || appName) ? `` : `` - ], - appleStartup: appleStartupItems.map(item => ctx => appleStartupGen(item, ctx)), - coast: coastSizes.map(size => ctx => coastGen(size, ctx)), - favicons: [ - ({ relative, icons }) => !ctxHasIcons(icons.favicons, "favicon.ico") ? "" : ``, - ...faviconSizes.map(size => ctx => faviconGen(size, ctx)), - ], - windows: [ - ({ background }) => ``, - ({ relative, icons }) => !ctxHasIcons(icons.windows, "mstile-144x144.png") ? "" : ``, - ({ relative }) => `` - ], - yandex: [ - ({ relative }) => `` - ] -}; diff --git a/src/platforms/base.ts b/src/platforms/base.ts new file mode 100644 index 00000000..d0188e43 --- /dev/null +++ b/src/platforms/base.ts @@ -0,0 +1,90 @@ +import { + FaviconFile, + FaviconHtmlElement, + FaviconImage, + FaviconResponse, +} from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { + asString, + Dictionary, + filterKeys, + Images, + mapValues, + relativeTo, + SourceImage, +} from "../helpers"; +import { Logger } from "../logger"; + +export function uniformIconOptions( + options: FaviconOptions, + iconsChoice: IconOptions | boolean | string[] | undefined, + platformConfig: Dictionary +): Dictionary { + let result = platformConfig; + if (Array.isArray(iconsChoice)) { + result = filterKeys(platformConfig, (name) => iconsChoice.includes(name)); + } else if (typeof iconsChoice === "object") { + result = mapValues(platformConfig, (iconOptions: IconOptions) => ({ + ...iconOptions, + ...iconsChoice, + })); + } + + result = mapValues(result, (iconOptions: IconOptions) => ({ + pixelArt: options.pixel_art, + ...iconOptions, + background: + iconOptions.background === true + ? options.background + : asString(iconOptions.background), + })); + + return result; +} + +export class Platform { + protected options: FaviconOptions; + protected iconOptions: Dictionary; + protected log: Logger; + + constructor( + options: FaviconOptions, + iconOptions: Dictionary, + logger: Logger + ) { + this.options = options; + this.iconOptions = iconOptions; + this.log = logger; + } + + async create(sourceset: SourceImage[]): Promise { + const { output } = this.options; + return { + images: output.images ? await this.createImages(sourceset) : [], + files: output.files ? await this.createFiles() : [], + html: output.html ? await this.createHtml() : [], + }; + } + + async createImages(sourceset: SourceImage[]): Promise { + const images = new Images(this.log); + return await Promise.all( + Object.entries(this.iconOptions).map(([iconName, iconOption]) => + images.createFavicon(sourceset, iconName, iconOption) + ) + ); + } + + async createFiles(): Promise { + return []; + } + + async createHtml(): Promise { + return []; + } + + protected relative(path: string): string { + return relativeTo(this.options.path, path); + } +} diff --git a/src/platforms/coast.ts b/src/platforms/coast.ts new file mode 100644 index 00000000..a6f3cdd8 --- /dev/null +++ b/src/platforms/coast.ts @@ -0,0 +1,29 @@ +import { FaviconHtmlElement } from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { opaqueIcon } from "../config/icons"; +import { Dictionary } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "coast-228x228.png": opaqueIcon(228), +}; + +export class CoastPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.coast, ICONS_OPTIONS), + logContext(logger, "coast") + ); + } + + async createHtml(): Promise { + return Object.entries(this.iconOptions).map(([name, options]) => { + const { width, height } = options.sizes[0]; + + // prettier-ignore + return ``; + }); + } +} diff --git a/src/platforms/favicons.ts b/src/platforms/favicons.ts new file mode 100644 index 00000000..ce2aba6a --- /dev/null +++ b/src/platforms/favicons.ts @@ -0,0 +1,36 @@ +import { FaviconHtmlElement } from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { transparentIcon, transparentIcons } from "../config/icons"; +import { Dictionary } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "favicon.ico": transparentIcons(16, 24, 32, 48, 64), + "favicon-16x16.png": transparentIcon(16), + "favicon-32x32.png": transparentIcon(32), + "favicon-48x48.png": transparentIcon(48), +}; + +export class FaviconsPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.favicons, ICONS_OPTIONS), + logContext(logger, "favicons") + ); + } + + async createHtml(): Promise { + return Object.entries(this.iconOptions).map(([name, options]) => { + if (name.endsWith(".ico")) { + return ``; + } + + const { width, height } = options.sizes[0]; + + // prettier-ignore + return ``; + }); + } +} diff --git a/src/platforms/firefox.ts b/src/platforms/firefox.ts new file mode 100644 index 00000000..9782d5bc --- /dev/null +++ b/src/platforms/firefox.ts @@ -0,0 +1,54 @@ +import { FaviconFile } from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { glowIcon } from "../config/icons"; +import { Dictionary, relativeTo } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "firefox_app_60x60.png": glowIcon(60), + "firefox_app_128x128.png": glowIcon(128), + "firefox_app_512x512.png": glowIcon(512), +}; + +function firefoxManifest( + options: FaviconOptions, + iconOptions: Dictionary +): FaviconFile { + const basePath = options.manifestRelativePaths ? null : options.path; + const properties = { + version: options.version ?? "1.0", + name: options.appName, + description: options.appDescription, + icons: {}, + developer: { + name: options.developerName, + url: options.developerURL, + }, + }; + + for (const [name, { sizes }] of Object.entries(iconOptions)) { + const size = sizes[0].width; // any size + + properties.icons[size] = relativeTo(basePath, name); + } + + return { + name: "manifest.webapp", + contents: JSON.stringify(properties, null, 2), + }; +} + +export class FirefoxPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.firefox, ICONS_OPTIONS), + logContext(logger, "firefox") + ); + } + + async createFiles(): Promise { + return [firefoxManifest(this.options, this.iconOptions)]; + } +} diff --git a/src/platforms/index.ts b/src/platforms/index.ts new file mode 100644 index 00000000..188d94cb --- /dev/null +++ b/src/platforms/index.ts @@ -0,0 +1,38 @@ +import { FaviconOptions } from "../config/defaults"; +import { Logger } from "../logger"; +import { Platform } from "./base"; +import { AndroidPlatform } from "./android"; +import { AppleIconPlatform } from "./appleIcon"; +import { AppleStartupPlatform } from "./appleStartup"; +import { CoastPlatform } from "./coast"; +import { FaviconsPlatform } from "./favicons"; +import { FirefoxPlatform } from "./firefox"; +import { WindowsPlatform } from "./windows"; +import { YandexPlatform } from "./yandex"; + +export function getPlatform( + name: string, + options: FaviconOptions, + logger: Logger +): Platform { + switch (name) { + case "android": + return new AndroidPlatform(options, logger); + case "appleIcon": + return new AppleIconPlatform(options, logger); + case "appleStartup": + return new AppleStartupPlatform(options, logger); + case "coast": + return new CoastPlatform(options, logger); + case "favicons": + return new FaviconsPlatform(options, logger); + case "firefox": + return new FirefoxPlatform(options, logger); + case "windows": + return new WindowsPlatform(options, logger); + case "yandex": + return new YandexPlatform(options, logger); + default: + throw new Error(`Unsupported platform ${name}`); + } +} diff --git a/src/platforms/windows.ts b/src/platforms/windows.ts new file mode 100644 index 00000000..36f52da0 --- /dev/null +++ b/src/platforms/windows.ts @@ -0,0 +1,92 @@ +import xml2js from "xml2js"; +import { FaviconFile, FaviconHtmlElement } from ".."; +import { FaviconOptions, IconOptions, IconSize } from "../config/defaults"; +import { transparentIcon } from "../config/icons"; +import { Dictionary, relativeTo } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "mstile-70x70.png": transparentIcon(70), + "mstile-144x144.png": transparentIcon(144), + "mstile-150x150.png": transparentIcon(150), + "mstile-310x150.png": transparentIcon(310, 150), + "mstile-310x310.png": transparentIcon(310), +}; + +const SUPPORTED_TILES = [ + { name: "square70x70logo", width: 70, height: 70 }, + { name: "square150x150logo", width: 150, height: 150 }, + { name: "wide310x150logo", width: 310, height: 150 }, + { name: "square310x310logo", width: 310, height: 310 }, +]; + +function hasSize(size: IconSize, icon: IconOptions): boolean { + return ( + icon.sizes.length === 1 && + icon.sizes[0].width === size.width && + icon.sizes[0].height === size.height + ); +} + +function browserConfig( + options: FaviconOptions, + iconOptions: Dictionary +): FaviconFile { + const basePath = options.manifestRelativePaths ? null : options.path; + + const tile: Dictionary = {}; + + for (const { name, ...size } of SUPPORTED_TILES) { + const icon = Object.entries(iconOptions).find((icon) => + hasSize(size, icon[1]) + ); + + if (icon) { + tile[name] = { + $: { src: relativeTo(basePath, icon[0]) }, + }; + } + } + + const browserconfig = { + browserconfig: { + msapplication: { + tile: { ...tile, TileColor: { _: options.background } }, + }, + }, + }; + + const contents = new xml2js.Builder({ + xmldec: { version: "1.0", encoding: "utf-8", standalone: null }, + }).buildObject(browserconfig); + + return { name: "browserconfig.xml", contents }; +} + +export class WindowsPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.windows, ICONS_OPTIONS), + logContext(logger, "windows") + ); + } + + async createFiles(): Promise { + return [browserConfig(this.options, this.iconOptions)]; + } + + async createHtml(): Promise { + const tile = "mstile-144x144.png"; + + // prettier-ignore + return [ + ``, + tile in this.iconOptions + ? `` + : "", + ``, + ]; + } +} diff --git a/src/platforms/yandex.ts b/src/platforms/yandex.ts new file mode 100644 index 00000000..524e5ae9 --- /dev/null +++ b/src/platforms/yandex.ts @@ -0,0 +1,55 @@ +import { FaviconFile, FaviconHtmlElement } from ".."; +import { FaviconOptions, IconOptions } from "../config/defaults"; +import { transparentIcon } from "../config/icons"; +import { Dictionary, relativeTo } from "../helpers"; +import { logContext, Logger } from "../logger"; +import { Platform, uniformIconOptions } from "./base"; + +const ICONS_OPTIONS: Dictionary = { + "yandex-browser-50x50.png": transparentIcon(50), +}; + +function yandexManifest( + options: FaviconOptions, + iconOptions: Dictionary +): FaviconFile { + const basePath = options.manifestRelativePaths ? null : options.path; + + const logo = Object.keys(iconOptions)[0]; + + const properties = { + version: options.version, + api_version: 1, + layout: { + logo: relativeTo(basePath, logo), + color: options.background, + show_title: true, + }, + }; + + return { + name: "yandex-browser-manifest.json", + contents: JSON.stringify(properties, null, 2), + }; +} + +export class YandexPlatform extends Platform { + constructor(options: FaviconOptions, logger: Logger) { + super( + options, + uniformIconOptions(options, options.icons.yandex, ICONS_OPTIONS), + logContext(logger, "yandex") + ); + } + + async createFiles(): Promise { + return [yandexManifest(this.options, this.iconOptions)]; + } + + async createHtml(): Promise { + // prettier-ignore + return [ + `` + ]; + } +} diff --git a/src/svgtool.ts b/src/svgtool.ts new file mode 100644 index 00000000..49b78755 --- /dev/null +++ b/src/svgtool.ts @@ -0,0 +1,68 @@ +import xml2js from "xml2js"; +import { SourceImage } from "./helpers"; +import { logContext, Logger } from "./logger"; + +// sharp renders the SVG in its source width and height with 72 DPI which can +// cause a blurry result in case the source SVG is defined in lower size than +// the target size. To avoid this, resize the source SVG to the needed size +// before passing it to sharp by increasing its width and/or height +// attributes. +// +// Currently it seems this won't be fixed in sharp, so we need a workaround: +// https://github.com/lovell/sharp/issues/729#issuecomment-284708688 +// +// They suggest setting the image density to a "resized" density based on the +// target render size but this does not seem to work with favicons and may +// cause other errors with "unnecessarily high" image density values. +// +// For further information, see: +// https://github.com/itgalaxy/favicons/issues/264 +export class SvgTool { + #log: Logger; + + constructor(logger: Logger) { + this.#log = logContext(logger, "svgtool"); + } + + async ensureSize( + svgSource: SourceImage, + width: number, + height: number + ): Promise { + let svgWidth = svgSource.metadata.width; + let svgHeight = svgSource.metadata.height; + + if (svgWidth >= width && svgHeight >= height) { + // If the base SVG is large enough, it does not need to be modified. + return svgSource.data; + } else if (width > height) { + svgHeight = Math.round(svgHeight * (width / svgWidth)); + svgWidth = width; + } else { + // width <= height + svgWidth = Math.round(svgWidth * (height / svgHeight)); + svgHeight = height; + } + + // Modify the source SVG's width and height attributes for sharp to render + // it correctly. + this.#log("ensureSize", `Resizing SVG to ${svgWidth}x${svgHeight}`); + return await this.resize(svgSource.data, svgWidth, svgHeight); + } + + async resize( + svgFile: Buffer, + width: number, + height: number + ): Promise { + const xmlDoc = await xml2js.parseStringPromise(svgFile); + + xmlDoc.svg.$.width = width; + xmlDoc.svg.$.height = height; + + const builder = new xml2js.Builder(); + const modifiedSvg = builder.buildObject(xmlDoc); + + return Buffer.from(modifiedSvg); + } +} diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/63_android-chrome-maskable-36x36.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/18_android-chrome-maskable-36x36.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/63_android-chrome-maskable-36x36.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/18_android-chrome-maskable-36x36.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/64_android-chrome-maskable-48x48.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/19_android-chrome-maskable-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/64_android-chrome-maskable-48x48.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/19_android-chrome-maskable-48x48.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/65_android-chrome-maskable-72x72.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/20_android-chrome-maskable-72x72.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/65_android-chrome-maskable-72x72.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/20_android-chrome-maskable-72x72.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/66_android-chrome-maskable-96x96.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/21_android-chrome-maskable-96x96.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/66_android-chrome-maskable-96x96.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/21_android-chrome-maskable-96x96.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/67_android-chrome-maskable-144x144.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/22_android-chrome-maskable-144x144.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/67_android-chrome-maskable-144x144.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/22_android-chrome-maskable-144x144.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/68_android-chrome-maskable-192x192.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/23_android-chrome-maskable-192x192.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/68_android-chrome-maskable-192x192.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/23_android-chrome-maskable-192x192.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/69_android-chrome-maskable-256x256.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/24_android-chrome-maskable-256x256.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/69_android-chrome-maskable-256x256.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/24_android-chrome-maskable-256x256.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/70_android-chrome-maskable-384x384.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/25_android-chrome-maskable-384x384.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/70_android-chrome-maskable-384x384.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/25_android-chrome-maskable-384x384.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/71_android-chrome-maskable-512x512.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/26_android-chrome-maskable-512x512.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/71_android-chrome-maskable-512x512.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/26_android-chrome-maskable-512x512.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/18_apple-touch-icon-57x57.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/27_apple-touch-icon-57x57.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/18_apple-touch-icon-57x57.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/27_apple-touch-icon-57x57.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/19_apple-touch-icon-60x60.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/28_apple-touch-icon-60x60.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/19_apple-touch-icon-60x60.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/28_apple-touch-icon-60x60.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/20_apple-touch-icon-72x72.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/29_apple-touch-icon-72x72.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/20_apple-touch-icon-72x72.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/29_apple-touch-icon-72x72.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/21_apple-touch-icon-76x76.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/30_apple-touch-icon-76x76.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/21_apple-touch-icon-76x76.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/30_apple-touch-icon-76x76.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/22_apple-touch-icon-114x114.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/31_apple-touch-icon-114x114.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/22_apple-touch-icon-114x114.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/31_apple-touch-icon-114x114.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/23_apple-touch-icon-120x120.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/32_apple-touch-icon-120x120.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/23_apple-touch-icon-120x120.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/32_apple-touch-icon-120x120.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/24_apple-touch-icon-144x144.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/33_apple-touch-icon-144x144.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/24_apple-touch-icon-144x144.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/33_apple-touch-icon-144x144.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/25_apple-touch-icon-152x152.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/34_apple-touch-icon-152x152.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/25_apple-touch-icon-152x152.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/34_apple-touch-icon-152x152.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/26_apple-touch-icon-167x167.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/35_apple-touch-icon-167x167.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/26_apple-touch-icon-167x167.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/35_apple-touch-icon-167x167.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/27_apple-touch-icon-180x180.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/36_apple-touch-icon-180x180.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/27_apple-touch-icon-180x180.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/36_apple-touch-icon-180x180.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/28_apple-touch-icon-1024x1024.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/37_apple-touch-icon-1024x1024.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/28_apple-touch-icon-1024x1024.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/37_apple-touch-icon-1024x1024.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/29_apple-touch-icon.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/38_apple-touch-icon.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/29_apple-touch-icon.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/38_apple-touch-icon.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/30_apple-touch-icon-precomposed.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/39_apple-touch-icon-precomposed.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/30_apple-touch-icon-precomposed.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/39_apple-touch-icon-precomposed.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/31_apple-touch-startup-image-640x1136.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/40_apple-touch-startup-image-640x1136.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/31_apple-touch-startup-image-640x1136.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/40_apple-touch-startup-image-640x1136.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/32_apple-touch-startup-image-750x1334.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/41_apple-touch-startup-image-750x1334.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/32_apple-touch-startup-image-750x1334.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/41_apple-touch-startup-image-750x1334.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/33_apple-touch-startup-image-828x1792.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/42_apple-touch-startup-image-828x1792.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/33_apple-touch-startup-image-828x1792.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/42_apple-touch-startup-image-828x1792.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/34_apple-touch-startup-image-1125x2436.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/43_apple-touch-startup-image-1125x2436.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/34_apple-touch-startup-image-1125x2436.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/43_apple-touch-startup-image-1125x2436.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/35_apple-touch-startup-image-1242x2208.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/44_apple-touch-startup-image-1242x2208.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/35_apple-touch-startup-image-1242x2208.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/44_apple-touch-startup-image-1242x2208.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/36_apple-touch-startup-image-1242x2688.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/45_apple-touch-startup-image-1242x2688.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/36_apple-touch-startup-image-1242x2688.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/45_apple-touch-startup-image-1242x2688.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/37_apple-touch-startup-image-1536x2048.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/46_apple-touch-startup-image-1536x2048.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/37_apple-touch-startup-image-1536x2048.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/46_apple-touch-startup-image-1536x2048.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/38_apple-touch-startup-image-1668x2224.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/47_apple-touch-startup-image-1668x2224.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/38_apple-touch-startup-image-1668x2224.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/47_apple-touch-startup-image-1668x2224.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/39_apple-touch-startup-image-1668x2388.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/48_apple-touch-startup-image-1668x2388.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/39_apple-touch-startup-image-1668x2388.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/48_apple-touch-startup-image-1668x2388.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/40_apple-touch-startup-image-2048x2732.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/49_apple-touch-startup-image-2048x2732.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/40_apple-touch-startup-image-2048x2732.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/49_apple-touch-startup-image-2048x2732.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/41_apple-touch-startup-image-1136x640.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/50_apple-touch-startup-image-1136x640.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/41_apple-touch-startup-image-1136x640.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/50_apple-touch-startup-image-1136x640.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/42_apple-touch-startup-image-2160x1620.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/51_apple-touch-startup-image-2160x1620.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/42_apple-touch-startup-image-2160x1620.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/51_apple-touch-startup-image-2160x1620.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/43_apple-touch-startup-image-1620x2160.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/52_apple-touch-startup-image-1620x2160.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/43_apple-touch-startup-image-1620x2160.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/52_apple-touch-startup-image-1620x2160.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/44_apple-touch-startup-image-1334x750.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/53_apple-touch-startup-image-1334x750.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/44_apple-touch-startup-image-1334x750.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/53_apple-touch-startup-image-1334x750.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/45_apple-touch-startup-image-1792x828.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/54_apple-touch-startup-image-1792x828.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/45_apple-touch-startup-image-1792x828.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/54_apple-touch-startup-image-1792x828.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/46_apple-touch-startup-image-2436x1125.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/55_apple-touch-startup-image-2436x1125.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/46_apple-touch-startup-image-2436x1125.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/55_apple-touch-startup-image-2436x1125.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/47_apple-touch-startup-image-2208x1242.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/56_apple-touch-startup-image-2208x1242.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/47_apple-touch-startup-image-2208x1242.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/56_apple-touch-startup-image-2208x1242.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/48_apple-touch-startup-image-2688x1242.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/57_apple-touch-startup-image-2688x1242.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/48_apple-touch-startup-image-2688x1242.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/57_apple-touch-startup-image-2688x1242.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/49_apple-touch-startup-image-2048x1536.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/58_apple-touch-startup-image-2048x1536.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/49_apple-touch-startup-image-2048x1536.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/58_apple-touch-startup-image-2048x1536.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/50_apple-touch-startup-image-2224x1668.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/59_apple-touch-startup-image-2224x1668.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/50_apple-touch-startup-image-2224x1668.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/59_apple-touch-startup-image-2224x1668.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/51_apple-touch-startup-image-2388x1668.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/60_apple-touch-startup-image-2388x1668.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/51_apple-touch-startup-image-2388x1668.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/60_apple-touch-startup-image-2388x1668.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/52_apple-touch-startup-image-2732x2048.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/61_apple-touch-startup-image-2732x2048.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/52_apple-touch-startup-image-2732x2048.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/61_apple-touch-startup-image-2732x2048.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/53_coast-228x228.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/62_coast-228x228.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/53_coast-228x228.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/62_coast-228x228.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/54_firefox_app_60x60.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/63_firefox_app_60x60.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/54_firefox_app_60x60.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/63_firefox_app_60x60.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/55_firefox_app_128x128.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/64_firefox_app_128x128.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/55_firefox_app_128x128.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/64_firefox_app_128x128.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/56_firefox_app_512x512.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/65_firefox_app_512x512.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/56_firefox_app_512x512.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/65_firefox_app_512x512.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/57_mstile-70x70.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/66_mstile-70x70.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/57_mstile-70x70.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/66_mstile-70x70.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/58_mstile-144x144.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/67_mstile-144x144.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/58_mstile-144x144.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/67_mstile-144x144.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/59_mstile-150x150.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/68_mstile-150x150.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/59_mstile-150x150.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/68_mstile-150x150.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/60_mstile-310x150.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/69_mstile-310x150.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/60_mstile-310x150.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/69_mstile-310x150.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/61_mstile-310x310.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/70_mstile-310x310.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/61_mstile-310x310.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/70_mstile-310x310.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/62_yandex-browser-50x50.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/71_yandex-browser-50x50.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/62_yandex-browser-50x50.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/71_yandex-browser-50x50.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/manifestMaskable should accept an array of either buffers or paths to source images/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should accept an array of either buffers or paths to source images/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should accept an array of either buffers or paths to source images/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should accept an array of either buffers or paths to source images/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should accept an array of either buffers or paths to source images/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should add `maskable` to manifest purpose when manifestMaskable is true/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow configuring background color on selected platforms/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should allow configuring background color on selected platforms/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow configuring background color on selected platforms/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should allow configuring background color on selected platforms/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow offsetting the icon on selected platforms/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should allow offsetting the icon on selected platforms/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow offsetting the icon on selected platforms/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should allow offsetting the icon on selected platforms/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow setting an URL prefix/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should allow setting an URL prefix/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow setting an URL prefix/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should allow setting an URL prefix/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should allow specifying metadata/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should allow specifying metadata/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should allow specifying metadata/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should allow specifying metadata/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should generate the expected default result/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should generate the expected default result/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should generate the expected default result/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should generate the expected default result/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should generate the expected default result/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should generate the expected default result/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should generate the expected default result/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should generate the expected default result/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should generate the expected default result/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should generate the expected default result/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should generate the expected default result/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should provide stream interface/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should provide stream interface/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should provide stream interface/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should provide stream interface/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should provide stream interface/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should provide stream interface/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should provide stream interface/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should provide stream interface/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should provide stream interface/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should provide stream interface/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should provide stream interface/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should provide stream interface/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should provide stream interface/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should provide stream interface/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should provide stream interface/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should provide stream interface/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should provide stream interface/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should provide stream interface/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should select best source image by its size/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should select best source image by its size/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should select best source image by its size/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should select best source image by its size/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should select best source image by its size/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should select best source image by its size/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should select best source image by its size/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should select best source image by its size/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should select best source image by its size/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should select best source image by its size/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should select best source image by its size/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should support pixel art/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should support pixel art/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should support pixel art/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should support pixel art/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should support pixel art/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should support pixel art/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should support pixel art/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should support pixel art/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should support pixel art/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should support pixel art/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should support pixel art/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should support pixel art/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should support pixel art/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should support pixel art/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should support pixel art/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should support pixel art/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support pixel art/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should support pixel art/8_favicon-48x48.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/4_favicon.ico_16x16.png-snap.png b/test/__image_snapshots__/should support svg images/1_favicon.ico_16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/4_favicon.ico_16x16.png-snap.png rename to test/__image_snapshots__/should support svg images/1_favicon.ico_16x16.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/5_favicon.ico_24x24.png-snap.png b/test/__image_snapshots__/should support svg images/2_favicon.ico_24x24.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/5_favicon.ico_24x24.png-snap.png rename to test/__image_snapshots__/should support svg images/2_favicon.ico_24x24.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/6_favicon.ico_32x32.png-snap.png b/test/__image_snapshots__/should support svg images/3_favicon.ico_32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/6_favicon.ico_32x32.png-snap.png rename to test/__image_snapshots__/should support svg images/3_favicon.ico_32x32.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/7_favicon.ico_48x48.png-snap.png b/test/__image_snapshots__/should support svg images/4_favicon.ico_48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/7_favicon.ico_48x48.png-snap.png rename to test/__image_snapshots__/should support svg images/4_favicon.ico_48x48.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/8_favicon.ico_64x64.png-snap.png b/test/__image_snapshots__/should support svg images/5_favicon.ico_64x64.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/8_favicon.ico_64x64.png-snap.png rename to test/__image_snapshots__/should support svg images/5_favicon.ico_64x64.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/1_favicon-16x16.png-snap.png b/test/__image_snapshots__/should support svg images/6_favicon-16x16.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/1_favicon-16x16.png-snap.png rename to test/__image_snapshots__/should support svg images/6_favicon-16x16.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/2_favicon-32x32.png-snap.png b/test/__image_snapshots__/should support svg images/7_favicon-32x32.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/2_favicon-32x32.png-snap.png rename to test/__image_snapshots__/should support svg images/7_favicon-32x32.png-snap.png diff --git a/test/__image_snapshots__/should support svg images/3_favicon-48x48.png-snap.png b/test/__image_snapshots__/should support svg images/8_favicon-48x48.png-snap.png similarity index 100% rename from test/__image_snapshots__/should support svg images/3_favicon-48x48.png-snap.png rename to test/__image_snapshots__/should support svg images/8_favicon-48x48.png-snap.png diff --git a/test/__snapshots__/array.test.js.snap b/test/__snapshots__/array.test.js.snap index 281d376a..9b375426 100644 --- a/test/__snapshots__/array.test.js.snap +++ b/test/__snapshots__/array.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, @@ -505,20 +501,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -588,19 +580,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/background.test.js.snap b/test/__snapshots__/background.test.js.snap index 65063c5f..12d48f4a 100644 --- a/test/__snapshots__/background.test.js.snap +++ b/test/__snapshots__/background.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/default.test.js.snap b/test/__snapshots__/default.test.js.snap index 4770acfb..ed847bf1 100644 --- a/test/__snapshots__/default.test.js.snap +++ b/test/__snapshots__/default.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/manifestMaskable.test.js.snap b/test/__snapshots__/manifestMaskable.test.js.snap index 563876bb..7d9d78fa 100644 --- a/test/__snapshots__/manifestMaskable.test.js.snap +++ b/test/__snapshots__/manifestMaskable.test.js.snap @@ -148,20 +148,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -231,19 +227,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, @@ -281,6 +277,42 @@ Object { "contents": null, "name": "android-chrome-512x512.png", }, + Object { + "contents": null, + "name": "android-chrome-maskable-36x36.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-48x48.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-72x72.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-96x96.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-144x144.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-192x192.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-256x256.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-384x384.png", + }, + Object { + "contents": null, + "name": "android-chrome-maskable-512x512.png", + }, Object { "contents": null, "name": "apple-touch-icon-57x57.png", @@ -461,42 +493,6 @@ Object { "contents": null, "name": "yandex-browser-50x50.png", }, - Object { - "contents": null, - "name": "android-chrome-maskable-36x36.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-48x48.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-72x72.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-96x96.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-144x144.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-192x192.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-256x256.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-384x384.png", - }, - Object { - "contents": null, - "name": "android-chrome-maskable-512x512.png", - }, ], } `; @@ -595,20 +591,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -678,19 +670,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/manifestRelativePaths.test.js.snap b/test/__snapshots__/manifestRelativePaths.test.js.snap index e11f84e0..ee44646a 100644 --- a/test/__snapshots__/manifestRelativePaths.test.js.snap +++ b/test/__snapshots__/manifestRelativePaths.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { diff --git a/test/__snapshots__/meta.test.js.snap b/test/__snapshots__/meta.test.js.snap index c8ee313f..567f4a1d 100644 --- a/test/__snapshots__/meta.test.js.snap +++ b/test/__snapshots__/meta.test.js.snap @@ -95,20 +95,16 @@ Object { Object { "contents": " - - - - - - - #333 - - - - - - -", + + + + + + + #333 + + +", "name": "browserconfig.xml", }, Object { @@ -178,19 +174,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/offset.test.js.snap b/test/__snapshots__/offset.test.js.snap index c0df77cf..75a61543 100644 --- a/test/__snapshots__/offset.test.js.snap +++ b/test/__snapshots__/offset.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/pixelart.test.js.snap b/test/__snapshots__/pixelart.test.js.snap index eba009d1..75ae54d2 100644 --- a/test/__snapshots__/pixelart.test.js.snap +++ b/test/__snapshots__/pixelart.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/prefixed.test.js.snap b/test/__snapshots__/prefixed.test.js.snap index 702f64bc..aae4f3be 100644 --- a/test/__snapshots__/prefixed.test.js.snap +++ b/test/__snapshots__/prefixed.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/stream.test.js.snap b/test/__snapshots__/stream.test.js.snap index 4c63d291..93847975 100644 --- a/test/__snapshots__/stream.test.js.snap +++ b/test/__snapshots__/stream.test.js.snap @@ -1763,8 +1763,6 @@ Object { 10, 32, 32, - 32, - 32, 60, 109, 115, @@ -1785,10 +1783,6 @@ Object { 32, 32, 32, - 32, - 32, - 32, - 32, 60, 116, 105, @@ -1802,12 +1796,6 @@ Object { 32, 32, 32, - 32, - 32, - 32, - 32, - 32, - 32, 60, 115, 113, @@ -1857,12 +1845,6 @@ Object { 32, 32, 32, - 32, - 32, - 32, - 32, - 32, - 32, 60, 115, 113, @@ -1916,12 +1898,6 @@ Object { 32, 32, 32, - 32, - 32, - 32, - 32, - 32, - 32, 60, 119, 105, @@ -1973,12 +1949,6 @@ Object { 32, 32, 32, - 32, - 32, - 32, - 32, - 32, - 32, 60, 115, 113, @@ -2032,12 +2002,6 @@ Object { 32, 32, 32, - 32, - 32, - 32, - 32, - 32, - 32, 60, 84, 105, @@ -2066,11 +2030,6 @@ Object { 114, 62, 10, - 10, - 32, - 32, - 32, - 32, 32, 32, 32, @@ -2083,9 +2042,6 @@ Object { 101, 62, 10, - 10, - 32, - 32, 32, 32, 60, @@ -2105,7 +2061,6 @@ Object { 110, 62, 10, - 10, 60, 47, 98, @@ -2122,7 +2077,6 @@ Object { 105, 103, 62, - 10, ], "type": "Buffer", }, @@ -2286,19 +2240,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null, diff --git a/test/__snapshots__/svg.test.js.snap b/test/__snapshots__/svg.test.js.snap index 6049675b..00f804fa 100644 --- a/test/__snapshots__/svg.test.js.snap +++ b/test/__snapshots__/svg.test.js.snap @@ -94,20 +94,16 @@ Object { Object { "contents": " - - - - - - - #fff - - - - - - -", + + + + + + + #fff + + +", "name": "browserconfig.xml", }, Object { @@ -177,19 +173,19 @@ Object { "images": Array [ Object { "contents": null, - "name": "favicon-16x16.png", + "name": "favicon.ico", }, Object { "contents": null, - "name": "favicon-32x32.png", + "name": "favicon-16x16.png", }, Object { "contents": null, - "name": "favicon-48x48.png", + "name": "favicon-32x32.png", }, Object { "contents": null, - "name": "favicon.ico", + "name": "favicon-48x48.png", }, Object { "contents": null,