UNPKG

@realfavicongenerator/check-favicon

Version:
226 lines (225 loc) 9.11 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.reportHasWarnings = exports.reportHasErrors = exports.fetchFetcher = exports.filePathToDataUrl = exports.bufferToDataUrl = exports.parseSizesAttribute = exports.mergeUrlAndPath = exports.checkIcon = exports.pathToMimeType = exports.readableStreamToBuffer = exports.readableStreamToString = exports.stringToReadableStream = exports.filePathToString = exports.filePathToReadableStream = void 0; const promises_1 = __importDefault(require("fs/promises")); const types_1 = require("./types"); const sharp_1 = __importDefault(require("sharp")); const filePathToReadableStream = (path) => __awaiter(void 0, void 0, void 0, function* () { const file = yield promises_1.default.open(path, 'r'); const stream = file.createReadStream(); return new ReadableStream({ start(controller) { stream.on('data', (chunk) => { controller.enqueue(chunk); }); stream.on('close', () => { controller.close(); }); } }); }); exports.filePathToReadableStream = filePathToReadableStream; const filePathToString = (path) => __awaiter(void 0, void 0, void 0, function* () { return (promises_1.default.readFile(path, 'utf-8')); }); exports.filePathToString = filePathToString; const stringToReadableStream = (str) => { const encoder = new TextEncoder(); const uint8Array = encoder.encode(str); return new ReadableStream({ start(controller) { controller.enqueue(uint8Array); controller.close(); } }); }; exports.stringToReadableStream = stringToReadableStream; const readableStreamToString = (readableStream) => __awaiter(void 0, void 0, void 0, function* () { const reader = readableStream.getReader(); const chunks = []; let done = false; while (!done) { const { value, done: doneValue } = yield reader.read(); done = doneValue; if (value) { chunks.push(value); } } const concatenatedChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); let offset = 0; for (const chunk of chunks) { concatenatedChunks.set(chunk, offset); offset += chunk.length; } return new TextDecoder("utf-8").decode(concatenatedChunks); }); exports.readableStreamToString = readableStreamToString; const readableStreamToBuffer = (readableStream) => __awaiter(void 0, void 0, void 0, function* () { const reader = readableStream.getReader(); const chunks = []; let done = false; while (!done) { const { value, done: doneValue } = yield reader.read(); done = doneValue; if (value) { chunks.push(value); } } const concatenatedChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); let offset = 0; for (const chunk of chunks) { concatenatedChunks.set(chunk, offset); offset += chunk.length; } return Buffer.from(concatenatedChunks); }); exports.readableStreamToBuffer = readableStreamToBuffer; const pathToMimeType = (path) => { const ext = path.split('.').pop(); switch (ext) { case 'png': return 'image/png'; case 'svg': return 'image/svg+xml'; case 'ico': return 'image/x-icon'; case 'jpg': case 'jpeg': return 'image/jpeg'; default: return 'application/octet-stream'; } }; exports.pathToMimeType = pathToMimeType; const checkIcon = (iconUrl, processor, fetcher, mimeType, expectedWidthHeight) => __awaiter(void 0, void 0, void 0, function* () { if (!iconUrl) { processor.noHref(); return null; } const res = yield fetcher(iconUrl, mimeType); if (res.status === 404) { processor.icon404(); } else if (res.status >= 300) { processor.cannotGet(res.status); } else if (res.readableStream) { processor.downloadable(); const rawContent = yield (0, exports.readableStreamToBuffer)(res.readableStream); const meta = yield (0, sharp_1.default)(rawContent).metadata(); const contentType = res.contentType || (0, exports.pathToMimeType)(iconUrl); const content = yield (0, exports.bufferToDataUrl)(rawContent, contentType); if (meta.width && meta.height) { if (meta.width !== meta.height) { processor.notSquare(meta.width, meta.height); } else { processor.square(meta.width); if (expectedWidthHeight) { if (meta.width === expectedWidthHeight) { processor.rightSize(meta.width); } else { processor.wrongSize(meta.width); } } } } return { content, url: iconUrl, width: meta.width || null, height: meta.height || null }; } return { content: null, url: iconUrl, width: null, height: null }; }); exports.checkIcon = checkIcon; const mergeUrlAndPath = (baseUrl, absoluteOrRelativePath) => { // If the path is a full URL, return it as is if (absoluteOrRelativePath.startsWith('http://') || absoluteOrRelativePath.startsWith('https://')) { return absoluteOrRelativePath; } const url = new URL(baseUrl); // Protocol-relative URL if (absoluteOrRelativePath.startsWith('//')) { return `${url.protocol}${absoluteOrRelativePath}`; } else if (absoluteOrRelativePath.startsWith('/')) { // If the path starts with a slash, replace the pathname return `${url.origin}${absoluteOrRelativePath}`; } else { // Otherwise, append the path to the existing pathname return `${url.href}${url.href.endsWith('/') ? '' : '/'}${absoluteOrRelativePath}`; } }; exports.mergeUrlAndPath = mergeUrlAndPath; const parseSizesAttribute = (sizes) => { if (!sizes) { return null; } const match = sizes.match(/(\d+)x(\d+)/); if (match) { if (match[1] !== match[2]) { return null; } return parseInt(match[1]); } return null; }; exports.parseSizesAttribute = parseSizesAttribute; const bufferToDataUrl = (buffer, mimeType) => { return `data:${mimeType};base64,${buffer.toString('base64')}`; }; exports.bufferToDataUrl = bufferToDataUrl; const filePathToDataUrl = (filePath) => __awaiter(void 0, void 0, void 0, function* () { const readStream = yield (0, exports.filePathToReadableStream)(filePath); const rawContent = yield (0, exports.readableStreamToBuffer)(readStream); const contentType = (0, exports.pathToMimeType)(filePath); return (0, exports.bufferToDataUrl)(rawContent, contentType); }); exports.filePathToDataUrl = filePathToDataUrl; const fetchFetcher = (url, contentType) => __awaiter(void 0, void 0, void 0, function* () { const res = yield fetch(url, { headers: { 'Content-Type': contentType || (0, exports.pathToMimeType)(url), 'user-agent': 'RealFaviconGenerator Favicon Checker' } }); return { status: res.status, contentType: res.headers.get('Content-Type') || null, readableStream: res.body }; }); exports.fetchFetcher = fetchFetcher; const reportHasErrors = (report) => { return report.desktop.messages.some(message => message.status === types_1.CheckerStatus.Error) || report.touchIcon.messages.some(message => message.status === types_1.CheckerStatus.Error) || report.webAppManifest.messages.some(message => message.status === types_1.CheckerStatus.Error); }; exports.reportHasErrors = reportHasErrors; const reportHasWarnings = (report) => { return report.desktop.messages.some(message => message.status === types_1.CheckerStatus.Warning) || report.touchIcon.messages.some(message => message.status === types_1.CheckerStatus.Warning) || report.webAppManifest.messages.some(message => message.status === types_1.CheckerStatus.Warning); }; exports.reportHasWarnings = reportHasWarnings;