@realfavicongenerator/check-favicon
Version:
Check the favicon of a website
240 lines (239 loc) • 10.6 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkDesktopFavicon = exports.checkPngFavicon = exports.checkSvgFaviconFile = exports.checkSvgFavicon = exports.PngFaviconFileSize = void 0;
const types_1 = require("../types");
const sharp_1 = __importDefault(require("sharp"));
const helper_1 = require("../helper");
const ico_1 = require("./ico");
exports.PngFaviconFileSize = 96;
const checkSvgFavicon = (baseUrl_1, head_1, ...args_1) => __awaiter(void 0, [baseUrl_1, head_1, ...args_1], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
const messages = [];
if (!head) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.noHead,
text: 'No <head> element'
});
return {
messages,
icon: { content: null, url: null, width: null, height: null }
};
}
const svgs = head === null || head === void 0 ? void 0 : head.querySelectorAll("link[rel='icon'][type='image/svg+xml']");
if (svgs.length === 0) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.noSvgFavicon,
text: 'There is no SVG favicon'
});
}
else if (svgs.length > 1) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.multipleSvgFavicons,
text: `There are ${svgs.length} SVG favicons`
});
}
else {
messages.push({
status: types_1.CheckerStatus.Ok,
id: types_1.MessageId.svgFaviconDeclared,
text: 'The SVG favicon is declared'
});
const href = svgs[0].attributes.href;
if (!href) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.noSvgFaviconHref,
text: 'The SVG markup has no href attribute'
});
}
else {
const iconReport = yield (0, exports.checkSvgFaviconFile)(baseUrl, href, fetcher);
return {
messages: [...messages, ...iconReport.messages],
icon: iconReport.icon
};
}
}
return {
messages,
icon: { content: null, url: null, width: null, height: null }
};
});
exports.checkSvgFavicon = checkSvgFavicon;
const checkSvgFaviconFile = (baseUrl, url, fetcher) => __awaiter(void 0, void 0, void 0, function* () {
const messages = [];
const svgUrl = (0, helper_1.mergeUrlAndPath)(baseUrl, url);
const res = yield fetcher(svgUrl, 'image/svg+xml');
let content;
let width = null;
let height = null;
if (res.status === 404) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.svgFavicon404,
text: `The SVG icon file \`${url}\` does not exist (404 error)`
});
}
else if (res.status >= 300) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.svgFaviconCannotGet,
text: `Cannot get the SVG icon file at \`${url}\` (${res.status} error)`
});
}
else if (res.readableStream) {
messages.push({
status: types_1.CheckerStatus.Ok,
id: types_1.MessageId.svgFaviconDownloadable,
text: `The SVG favicon is accessible at \`${url}\``
});
content = yield (0, helper_1.readableStreamToString)(res.readableStream);
const meta = yield (0, sharp_1.default)(Buffer.from(content)).metadata();
width = meta.width || null;
height = meta.height || null;
if (width && height && width !== height) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.svgFaviconNotSquare,
text: `The SVG is not square (${width}x${height})`
});
}
else {
messages.push({
status: types_1.CheckerStatus.Ok,
id: types_1.MessageId.svgFaviconSquare,
text: `The SVG is square (${width}x${height})`
});
}
}
return {
messages,
icon: {
content: content ? yield (0, helper_1.bufferToDataUrl)(Buffer.from(content), 'image/svg+xml') : null,
url: svgUrl,
width, height
}
};
});
exports.checkSvgFaviconFile = checkSvgFaviconFile;
const checkPngFavicon = (baseUrl_2, head_2, ...args_2) => __awaiter(void 0, [baseUrl_2, head_2, ...args_2], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
const messages = [];
if (!head) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.noHead,
text: 'No <head> element'
});
return { messages, icon: { content: null, url: null, width: null, height: null } };
}
const icons = head === null || head === void 0 ? void 0 : head.querySelectorAll("link[rel='icon'][type='image/png']");
if (icons.length === 0) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.noDesktopPngFavicon,
text: 'There is no desktop PNG favicon'
});
}
else {
const size = `${exports.PngFaviconFileSize}x${exports.PngFaviconFileSize}`;
const sizedIconMarkup = icons.filter(icon => icon.attributes.sizes === size);
if (sizedIconMarkup.length === 0) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.no96x96DesktopPngFavicon,
text: `There is no ${size} desktop PNG favicon`
});
}
else {
messages.push({
status: types_1.CheckerStatus.Ok,
id: types_1.MessageId.desktopPngFaviconDeclared,
text: `The ${size} desktop PNG favicon is declared`
});
const href = sizedIconMarkup[0].attributes.href;
if (!href) {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.noDesktopPngFaviconHref,
text: `The ${size} desktop favicon markup has no href attribute`
});
}
else {
const iconUrl = (0, helper_1.mergeUrlAndPath)(baseUrl, href);
const processor = {
cannotGet: (httpStatus) => {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.desktopPngFaviconCannotGet,
text: `Cannot get the ${size} desktop PNG favicon at \`${iconUrl}\` (${httpStatus} error)`
});
},
downloadable: () => {
messages.push({
status: types_1.CheckerStatus.Ok,
id: types_1.MessageId.desktopPngFaviconDownloadable,
text: `The ${size} desktop PNG favicon is accessible`
});
},
icon404: () => {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.desktopPngFavicon404,
text: `The ${size} desktop PNG favicon does not exist (404 error)`
});
},
notSquare: (width, height) => { }, // Ignore this message
wrongSize: (widthHeight) => {
messages.push({
status: types_1.CheckerStatus.Error,
id: types_1.MessageId.desktopPngFaviconWrongSize,
text: `The ${size} desktop PNG favicon has the wrong size (${widthHeight}x${widthHeight})`
});
},
rightSize(widthHeight) {
messages.push({
status: types_1.CheckerStatus.Ok,
id: types_1.MessageId.desktopPngFaviconRightSize,
text: `The ${size} desktop PNG favicon has the right size`
});
},
square: (widthHeight) => { }, // Ignore this message,
noHref: () => { } // Ignore this message
};
const icon = yield (0, helper_1.checkIcon)(iconUrl, processor, fetcher, icons[0].attributes.mimeType || 'image/png', exports.PngFaviconFileSize);
return { messages, icon };
}
}
}
return { messages, icon: { content: null, url: null, width: null, height: null } };
});
exports.checkPngFavicon = checkPngFavicon;
const checkDesktopFavicon = (baseUrl_3, head_3, ...args_3) => __awaiter(void 0, [baseUrl_3, head_3, ...args_3], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
const svgReport = yield (0, exports.checkSvgFavicon)(baseUrl, head, fetcher);
const pngReport = yield (0, exports.checkPngFavicon)(baseUrl, head, fetcher);
const icoReport = yield (0, ico_1.checkIcoFavicon)(baseUrl, head, fetcher);
return {
messages: [...svgReport.messages, ...pngReport.messages, ...icoReport.messages],
icon: pngReport.icon ? pngReport.icon.content : null,
icons: {
png: pngReport.icon,
ico: icoReport.icon,
svg: svgReport.icon
}
};
});
exports.checkDesktopFavicon = checkDesktopFavicon;