@realfavicongenerator/check-favicon 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/helper.js ADDED
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.fetchFetcher = exports.bufferToDataUrl = exports.parseSizesAttribute = exports.mergeUrlAndPath = exports.checkIcon = exports.pathToMimeType = exports.readableStreamToBuffer = exports.readableStreamToString = exports.stringToReadableStream = exports.filePathToString = exports.filePathToReadableStream = void 0;
16
+ const promises_1 = __importDefault(require("fs/promises"));
17
+ const sharp_1 = __importDefault(require("sharp"));
18
+ const filePathToReadableStream = (path) => __awaiter(void 0, void 0, void 0, function* () {
19
+ const file = yield promises_1.default.open(path, 'r');
20
+ const stream = file.createReadStream();
21
+ return new ReadableStream({
22
+ start(controller) {
23
+ stream.on('data', (chunk) => {
24
+ controller.enqueue(chunk);
25
+ });
26
+ stream.on('close', () => {
27
+ controller.close();
28
+ });
29
+ }
30
+ });
31
+ });
32
+ exports.filePathToReadableStream = filePathToReadableStream;
33
+ const filePathToString = (path) => __awaiter(void 0, void 0, void 0, function* () {
34
+ return (promises_1.default.readFile(path, 'utf-8'));
35
+ });
36
+ exports.filePathToString = filePathToString;
37
+ const stringToReadableStream = (str) => {
38
+ return new ReadableStream({
39
+ start(controller) {
40
+ controller.enqueue(str);
41
+ controller.close();
42
+ }
43
+ });
44
+ };
45
+ exports.stringToReadableStream = stringToReadableStream;
46
+ const readableStreamToString = (readableStream) => __awaiter(void 0, void 0, void 0, function* () {
47
+ const reader = readableStream.getReader();
48
+ const chunks = [];
49
+ let done = false;
50
+ while (!done) {
51
+ const { value, done: doneValue } = yield reader.read();
52
+ done = doneValue;
53
+ if (value) {
54
+ chunks.push(value);
55
+ }
56
+ }
57
+ const concatenatedChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
58
+ let offset = 0;
59
+ for (const chunk of chunks) {
60
+ concatenatedChunks.set(chunk, offset);
61
+ offset += chunk.length;
62
+ }
63
+ return new TextDecoder("utf-8").decode(concatenatedChunks);
64
+ });
65
+ exports.readableStreamToString = readableStreamToString;
66
+ const readableStreamToBuffer = (readableStream) => __awaiter(void 0, void 0, void 0, function* () {
67
+ const reader = readableStream.getReader();
68
+ const chunks = [];
69
+ let done = false;
70
+ while (!done) {
71
+ const { value, done: doneValue } = yield reader.read();
72
+ done = doneValue;
73
+ if (value) {
74
+ chunks.push(value);
75
+ }
76
+ }
77
+ const concatenatedChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
78
+ let offset = 0;
79
+ for (const chunk of chunks) {
80
+ concatenatedChunks.set(chunk, offset);
81
+ offset += chunk.length;
82
+ }
83
+ return Buffer.from(concatenatedChunks);
84
+ });
85
+ exports.readableStreamToBuffer = readableStreamToBuffer;
86
+ const pathToMimeType = (path) => {
87
+ const ext = path.split('.').pop();
88
+ switch (ext) {
89
+ case 'png':
90
+ return 'image/png';
91
+ case 'svg':
92
+ return 'image/svg+xml';
93
+ case 'ico':
94
+ return 'image/x-icon';
95
+ case 'jpg':
96
+ case 'jpeg':
97
+ return 'image/jpeg';
98
+ default:
99
+ return 'application/octet-stream';
100
+ }
101
+ };
102
+ exports.pathToMimeType = pathToMimeType;
103
+ const checkIcon = (iconUrl, processor, fetcher, mimeType, expectedWidthHeight) => __awaiter(void 0, void 0, void 0, function* () {
104
+ if (!iconUrl) {
105
+ processor.noHref();
106
+ return null;
107
+ }
108
+ const res = yield fetcher(iconUrl, mimeType);
109
+ if (res.status === 404) {
110
+ processor.icon404();
111
+ }
112
+ else if (res.status >= 300) {
113
+ processor.cannotGet(res.status);
114
+ }
115
+ else if (res.readableStream) {
116
+ processor.downloadable();
117
+ const content = yield (0, exports.readableStreamToBuffer)(res.readableStream);
118
+ const meta = yield (0, sharp_1.default)(content).metadata();
119
+ const contentType = res.contentType || (0, exports.pathToMimeType)(iconUrl);
120
+ if (meta.width && meta.height) {
121
+ if (meta.width !== meta.height) {
122
+ processor.notSquare(meta.width, meta.height);
123
+ return null;
124
+ }
125
+ else {
126
+ processor.square(meta.width);
127
+ if (expectedWidthHeight) {
128
+ if (meta.width === expectedWidthHeight) {
129
+ processor.rightSize(meta.width);
130
+ }
131
+ else {
132
+ processor.wrongSize(meta.width);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ return (0, exports.bufferToDataUrl)(content, contentType);
138
+ }
139
+ return null;
140
+ });
141
+ exports.checkIcon = checkIcon;
142
+ const mergeUrlAndPath = (baseUrl, absoluteOrRelativePath) => {
143
+ // If the path is a full URL, return it as is
144
+ if (absoluteOrRelativePath.startsWith('http://') || absoluteOrRelativePath.startsWith('https://')) {
145
+ return absoluteOrRelativePath;
146
+ }
147
+ const url = new URL(baseUrl);
148
+ // If the path starts with a slash, replace the pathname
149
+ if (absoluteOrRelativePath.startsWith('/')) {
150
+ return `${url.origin}${absoluteOrRelativePath}`;
151
+ }
152
+ else {
153
+ // Otherwise, append the path to the existing pathname
154
+ return `${url.href}${url.href.endsWith('/') ? '' : '/'}${absoluteOrRelativePath}`;
155
+ }
156
+ };
157
+ exports.mergeUrlAndPath = mergeUrlAndPath;
158
+ const parseSizesAttribute = (sizes) => {
159
+ if (!sizes) {
160
+ return null;
161
+ }
162
+ const match = sizes.match(/(\d+)x(\d+)/);
163
+ if (match) {
164
+ if (match[1] !== match[2]) {
165
+ return null;
166
+ }
167
+ return parseInt(match[1]);
168
+ }
169
+ return null;
170
+ };
171
+ exports.parseSizesAttribute = parseSizesAttribute;
172
+ const bufferToDataUrl = (buffer, mimeType) => {
173
+ return `data:${mimeType};base64,${buffer.toString('base64')}`;
174
+ };
175
+ exports.bufferToDataUrl = bufferToDataUrl;
176
+ const fetchFetcher = (url, contentType) => __awaiter(void 0, void 0, void 0, function* () {
177
+ const res = yield fetch(url, {
178
+ headers: {
179
+ 'Content-Type': contentType || (0, exports.pathToMimeType)(url),
180
+ 'user-agent': 'RealFaviconGenerator Favicon Checker'
181
+ }
182
+ });
183
+ return {
184
+ status: res.status,
185
+ contentType: res.headers.get('Content-Type') || null,
186
+ readableStream: res.body
187
+ };
188
+ });
189
+ exports.fetchFetcher = fetchFetcher;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const helper_1 = require("./helper");
13
+ const test_helper_1 = require("./test-helper");
14
+ const getTestProcessor = () => {
15
+ const messages = [];
16
+ const processor = {
17
+ noHref: () => { messages.push('noHref'); },
18
+ icon404: () => { messages.push('icon404'); },
19
+ cannotGet: (httpStatusCode) => { messages.push(`cannotGet ${httpStatusCode}`); },
20
+ downloadable: () => { messages.push('downloadable'); },
21
+ square: (widthHeight) => { messages.push(`square ${widthHeight}`); },
22
+ notSquare: (width, Height) => { messages.push(`notSquare ${width}x${Height}`); },
23
+ rightSize: (width) => { messages.push(`rightSize ${width}x${width}`); },
24
+ wrongSize: (widthHeight) => { messages.push(`wrongSize ${widthHeight}x${widthHeight}`); }
25
+ };
26
+ return { processor, messages };
27
+ };
28
+ const testIcon = './fixtures/logo-transparent.png';
29
+ const nonSquareIcon = './fixtures/non-square.png';
30
+ test('checkIcon - noHref', () => __awaiter(void 0, void 0, void 0, function* () {
31
+ const processor = getTestProcessor();
32
+ expect(yield (0, helper_1.checkIcon)(undefined, processor.processor, (0, test_helper_1.testFetcher)({}), 'image/png')).toBeNull();
33
+ expect(processor.messages).toEqual(['noHref']);
34
+ }));
35
+ test('checkIcon - icon404', () => __awaiter(void 0, void 0, void 0, function* () {
36
+ const processor = getTestProcessor();
37
+ expect(yield (0, helper_1.checkIcon)('/does-not-exist.png', processor.processor, (0, test_helper_1.testFetcher)({}), 'image/png')).toBeNull();
38
+ expect(processor.messages).toEqual(['icon404']);
39
+ }));
40
+ test('checkIcon - icon404', () => __awaiter(void 0, void 0, void 0, function* () {
41
+ const processor = getTestProcessor();
42
+ expect(yield (0, helper_1.checkIcon)('/bad-icon.png', processor.processor, (0, test_helper_1.testFetcher)({
43
+ '/bad-icon.png': {
44
+ contentType: 'image/png',
45
+ status: 500
46
+ }
47
+ }), 'image/png')).toBeNull();
48
+ expect(processor.messages).toEqual(['cannotGet 500']);
49
+ }));
50
+ test('checkIcon - downloadable & square', () => __awaiter(void 0, void 0, void 0, function* () {
51
+ const processor = getTestProcessor();
52
+ expect(yield (0, helper_1.checkIcon)('/some-icon.png', processor.processor, (0, test_helper_1.testFetcher)({
53
+ '/some-icon.png': {
54
+ status: 200,
55
+ contentType: 'image/png',
56
+ readableStream: yield (0, helper_1.filePathToReadableStream)(testIcon)
57
+ }
58
+ }), 'image/png')).not.toBeNull();
59
+ expect(processor.messages).toEqual([
60
+ 'downloadable',
61
+ 'square 754'
62
+ ]);
63
+ }));
64
+ test('checkIcon - downloadable & rightSize', () => __awaiter(void 0, void 0, void 0, function* () {
65
+ const processor = getTestProcessor();
66
+ expect(yield (0, helper_1.checkIcon)('/some-icon.png', processor.processor, (0, test_helper_1.testFetcher)({
67
+ '/some-icon.png': {
68
+ status: 200,
69
+ contentType: 'image/png',
70
+ readableStream: yield (0, helper_1.filePathToReadableStream)(testIcon)
71
+ }
72
+ }), 'image/png', 754)).not.toBeNull();
73
+ expect(processor.messages).toEqual([
74
+ 'downloadable',
75
+ 'square 754',
76
+ 'rightSize 754x754'
77
+ ]);
78
+ }));
79
+ test('checkIcon - downloadable & wrongSize', () => __awaiter(void 0, void 0, void 0, function* () {
80
+ const processor = getTestProcessor();
81
+ expect(yield (0, helper_1.checkIcon)('/some-icon.png', processor.processor, (0, test_helper_1.testFetcher)({
82
+ '/some-icon.png': {
83
+ status: 200,
84
+ contentType: 'image/png',
85
+ readableStream: yield (0, helper_1.filePathToReadableStream)(testIcon)
86
+ }
87
+ }), 'image/png', 500)).not.toBeNull();
88
+ expect(processor.messages).toEqual([
89
+ 'downloadable',
90
+ 'square 754',
91
+ 'wrongSize 754x754'
92
+ ]);
93
+ }));
94
+ test('checkIcon - downloadable & notSquare', () => __awaiter(void 0, void 0, void 0, function* () {
95
+ const processor = getTestProcessor();
96
+ expect(yield (0, helper_1.checkIcon)('/non-square-icon.png', processor.processor, (0, test_helper_1.testFetcher)({
97
+ '/non-square-icon.png': {
98
+ status: 200,
99
+ contentType: 'image/png',
100
+ readableStream: yield (0, helper_1.filePathToReadableStream)(nonSquareIcon)
101
+ }
102
+ }), 'image/png', 500)).toBeNull();
103
+ expect(processor.messages).toEqual([
104
+ 'downloadable',
105
+ 'notSquare 240x180'
106
+ ]);
107
+ }));
108
+ test('mergeUrlAndPath', () => {
109
+ expect((0, helper_1.mergeUrlAndPath)('https://example.com', '/some-path')).toBe('https://example.com/some-path');
110
+ expect((0, helper_1.mergeUrlAndPath)('https://example.com', 'some/path')).toBe('https://example.com/some/path');
111
+ expect((0, helper_1.mergeUrlAndPath)('https://example.com', 'some/path?some=param&and=other-param')).toBe('https://example.com/some/path?some=param&and=other-param');
112
+ expect((0, helper_1.mergeUrlAndPath)('https://example.com/sub-page', '/some-path')).toBe('https://example.com/some-path');
113
+ expect((0, helper_1.mergeUrlAndPath)('https://example.com/sub-page', 'some/path')).toBe('https://example.com/sub-page/some/path');
114
+ expect((0, helper_1.mergeUrlAndPath)('https://example.com', 'https://elsewhere.com/some-path')).toBe('https://elsewhere.com/some-path');
115
+ });
116
+ test('parseSizesAttribute', () => {
117
+ expect((0, helper_1.parseSizesAttribute)(null)).toEqual(null);
118
+ expect((0, helper_1.parseSizesAttribute)('dummy')).toEqual(null);
119
+ expect((0, helper_1.parseSizesAttribute)("16x16")).toEqual(16);
120
+ expect((0, helper_1.parseSizesAttribute)("50x170")).toEqual(null);
121
+ });
@@ -0,0 +1,4 @@
1
+ export { CheckerStatus, MessageId, CheckerMessage, DesktopFaviconReport, TouchIconTitleReport, TouchIconIconReport, WebManifestReport, FaviconReport, TouchIconReport } from './types';
2
+ export { checkDesktopFavicon, checkSvgFavicon } from "./desktop/desktop";
3
+ export { checkTouchIcon } from "./touch-icon";
4
+ export { checkWebManifest } from "./web-manifest";
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkWebManifest = exports.checkTouchIcon = exports.checkSvgFavicon = exports.checkDesktopFavicon = exports.MessageId = exports.CheckerStatus = void 0;
4
+ var types_1 = require("./types");
5
+ Object.defineProperty(exports, "CheckerStatus", { enumerable: true, get: function () { return types_1.CheckerStatus; } });
6
+ Object.defineProperty(exports, "MessageId", { enumerable: true, get: function () { return types_1.MessageId; } });
7
+ var desktop_1 = require("./desktop/desktop");
8
+ Object.defineProperty(exports, "checkDesktopFavicon", { enumerable: true, get: function () { return desktop_1.checkDesktopFavicon; } });
9
+ Object.defineProperty(exports, "checkSvgFavicon", { enumerable: true, get: function () { return desktop_1.checkSvgFavicon; } });
10
+ var touch_icon_1 = require("./touch-icon");
11
+ Object.defineProperty(exports, "checkTouchIcon", { enumerable: true, get: function () { return touch_icon_1.checkTouchIcon; } });
12
+ var web_manifest_1 = require("./web-manifest");
13
+ Object.defineProperty(exports, "checkWebManifest", { enumerable: true, get: function () { return web_manifest_1.checkWebManifest; } });
@@ -0,0 +1,4 @@
1
+ import { FetchResponse, Fetcher } from "./types";
2
+ export declare const testFetcher: (database: {
3
+ [url: string]: FetchResponse;
4
+ }) => Fetcher;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.testFetcher = void 0;
13
+ const testFetcher = (database) => {
14
+ return (url, contentType) => __awaiter(void 0, void 0, void 0, function* () {
15
+ const res = database[url];
16
+ if (!res) {
17
+ return { status: 404, contentType: contentType || 'application/octet-stream' };
18
+ }
19
+ return res;
20
+ });
21
+ };
22
+ exports.testFetcher = testFetcher;
@@ -0,0 +1,6 @@
1
+ import { Fetcher, TouchIconIconReport, TouchIconReport, TouchIconTitleReport } from "./types";
2
+ import { HTMLElement } from 'node-html-parser';
3
+ export declare const checkTouchIconTitle: (baseUrl: string, head: HTMLElement | null, fetcher?: Fetcher) => Promise<TouchIconTitleReport>;
4
+ export declare const checkTouchIconIcon: (baseUrl: string, head: HTMLElement | null, fetcher?: Fetcher) => Promise<TouchIconIconReport>;
5
+ export declare const getDuplicatedSizes: (sizes: (string | undefined)[]) => (string | undefined)[];
6
+ export declare const checkTouchIcon: (baseUrl: string, head: HTMLElement | null, fetcher?: Fetcher) => Promise<TouchIconReport>;
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.checkTouchIcon = exports.getDuplicatedSizes = exports.checkTouchIconIcon = exports.checkTouchIconTitle = void 0;
13
+ const types_1 = require("./types");
14
+ const helper_1 = require("./helper");
15
+ const checkTouchIconTitle = (baseUrl_1, head_1, ...args_1) => __awaiter(void 0, [baseUrl_1, head_1, ...args_1], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
16
+ const messages = [];
17
+ let appTitle = undefined;
18
+ if (!head) {
19
+ messages.push({
20
+ status: types_1.CheckerStatus.Error,
21
+ id: types_1.MessageId.noHead,
22
+ text: 'No <head> element'
23
+ });
24
+ return { messages };
25
+ }
26
+ const titleMarkup = head.querySelectorAll("meta[name='apple-mobile-web-app-title']");
27
+ if (titleMarkup.length === 0) {
28
+ messages.push({
29
+ status: types_1.CheckerStatus.Warning,
30
+ id: types_1.MessageId.noTouchWebAppTitle,
31
+ text: 'No touch web app title declared'
32
+ });
33
+ return { messages };
34
+ }
35
+ if (titleMarkup.length > 1) {
36
+ messages.push({
37
+ status: types_1.CheckerStatus.Error,
38
+ id: types_1.MessageId.multipleTouchWebAppTitles,
39
+ text: `The touch web app title is declared ${titleMarkup.length} times`
40
+ });
41
+ return { messages };
42
+ }
43
+ if (!titleMarkup[0].getAttribute('content')) {
44
+ messages.push({
45
+ status: types_1.CheckerStatus.Error,
46
+ id: types_1.MessageId.emptyTouchWebAppTitle,
47
+ text: 'The touch web app title has no content'
48
+ });
49
+ return { messages };
50
+ }
51
+ appTitle = titleMarkup[0].getAttribute('content');
52
+ messages.push({
53
+ status: types_1.CheckerStatus.Ok,
54
+ id: types_1.MessageId.touchWebAppTitleDeclared,
55
+ text: `The touch web app title is "${appTitle}"`
56
+ });
57
+ return { messages, appTitle };
58
+ });
59
+ exports.checkTouchIconTitle = checkTouchIconTitle;
60
+ const checkTouchIconIcon = (baseUrl_2, head_2, ...args_2) => __awaiter(void 0, [baseUrl_2, head_2, ...args_2], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
61
+ const messages = [];
62
+ let touchIcon = null;
63
+ if (!head) {
64
+ messages.push({
65
+ status: types_1.CheckerStatus.Error,
66
+ id: types_1.MessageId.noHead,
67
+ text: 'No <head> element'
68
+ });
69
+ return { messages, touchIcon };
70
+ }
71
+ const iconMarkup = head.querySelectorAll("link[rel='apple-touch-icon']");
72
+ if (iconMarkup.length === 0) {
73
+ messages.push({
74
+ status: types_1.CheckerStatus.Error,
75
+ id: types_1.MessageId.noTouchIcon,
76
+ text: 'No touch icon declared'
77
+ });
78
+ return { messages, touchIcon };
79
+ }
80
+ messages.push({
81
+ status: types_1.CheckerStatus.Ok,
82
+ id: types_1.MessageId.touchIconDeclared,
83
+ text: 'The touch icon is declared'
84
+ });
85
+ const sizes = iconMarkup.map(icon => icon.getAttribute('sizes')).filter(size => size);
86
+ if (sizes.length > 0) {
87
+ messages.push({
88
+ status: types_1.CheckerStatus.Warning,
89
+ id: types_1.MessageId.touchIconWithSize,
90
+ text: `Some Touch icon have a specific size (${sizes.join(', ')})`
91
+ });
92
+ }
93
+ const duplicatedSizes = (0, exports.getDuplicatedSizes)(iconMarkup.map(icon => icon.getAttribute('sizes')));
94
+ if (duplicatedSizes.length > 0) {
95
+ messages.push({
96
+ status: types_1.CheckerStatus.Error,
97
+ id: types_1.MessageId.duplicatedTouchIconSizes,
98
+ text: `The touch icon sizes ${duplicatedSizes.map(s => s || '(no size)').join(', ')} are declared more than once`
99
+ });
100
+ }
101
+ const iconHref = iconMarkup[0].getAttribute('href');
102
+ if (!iconHref) {
103
+ messages.push({
104
+ status: types_1.CheckerStatus.Error,
105
+ id: types_1.MessageId.noTouchIconHref,
106
+ text: 'The touch icon has no href'
107
+ });
108
+ return { messages, touchIcon };
109
+ }
110
+ const touchIconUrl = (0, helper_1.mergeUrlAndPath)(baseUrl, iconHref);
111
+ const processor = {
112
+ cannotGet: (status) => {
113
+ messages.push({
114
+ status: types_1.CheckerStatus.Error,
115
+ id: types_1.MessageId.touchIconCannotGet,
116
+ text: `The touch icon cannot be fetched (${status})`
117
+ });
118
+ },
119
+ downloadable: () => {
120
+ messages.push({
121
+ status: types_1.CheckerStatus.Ok,
122
+ id: types_1.MessageId.touchIconDownloadable,
123
+ text: 'The touch icon is downloadable'
124
+ });
125
+ },
126
+ icon404: () => {
127
+ messages.push({
128
+ status: types_1.CheckerStatus.Error,
129
+ id: types_1.MessageId.touchIcon404,
130
+ text: `The touch icon at ${touchIconUrl} is not found`
131
+ });
132
+ },
133
+ noHref: () => {
134
+ messages.push({
135
+ status: types_1.CheckerStatus.Error,
136
+ id: types_1.MessageId.noTouchIconHref,
137
+ text: 'The touch icon markup has no href'
138
+ });
139
+ },
140
+ notSquare: (width, height) => {
141
+ messages.push({
142
+ status: types_1.CheckerStatus.Error,
143
+ id: types_1.MessageId.touchIconNotSquare,
144
+ text: `The touch icon is not square (${width}x${height})`
145
+ });
146
+ },
147
+ rightSize: (width) => {
148
+ messages.push({
149
+ status: types_1.CheckerStatus.Ok,
150
+ id: types_1.MessageId.touchIconSquare,
151
+ text: `The touch icon is square (${width}x${width})`
152
+ });
153
+ },
154
+ square: (width) => {
155
+ messages.push({
156
+ status: types_1.CheckerStatus.Ok,
157
+ id: types_1.MessageId.touchIconSquare,
158
+ text: `The touch icon is square (${width}x${width})`
159
+ });
160
+ },
161
+ wrongSize: (width) => {
162
+ messages.push({
163
+ status: types_1.CheckerStatus.Error,
164
+ id: types_1.MessageId.touchIconWrongSize,
165
+ text: `The touch icon has a wrong size (${width}x${width})`
166
+ });
167
+ }
168
+ };
169
+ touchIcon = yield (0, helper_1.checkIcon)(touchIconUrl, processor, fetcher, undefined);
170
+ return { messages, touchIcon };
171
+ });
172
+ exports.checkTouchIconIcon = checkTouchIconIcon;
173
+ const getDuplicatedSizes = (sizes) => {
174
+ const duplicated = sizes.filter((size, index) => sizes.indexOf(size, index + 1) >= 0);
175
+ return duplicated.filter((size, index) => duplicated.indexOf(size) === index);
176
+ };
177
+ exports.getDuplicatedSizes = getDuplicatedSizes;
178
+ const checkTouchIcon = (baseUrl_3, head_3, ...args_3) => __awaiter(void 0, [baseUrl_3, head_3, ...args_3], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
179
+ const titleReport = yield (0, exports.checkTouchIconTitle)(baseUrl, head, fetcher);
180
+ const iconReport = yield (0, exports.checkTouchIconIcon)(baseUrl, head, fetcher);
181
+ return {
182
+ messages: [...titleReport.messages, ...iconReport.messages],
183
+ appTitle: titleReport.appTitle,
184
+ touchIcon: iconReport.touchIcon
185
+ };
186
+ });
187
+ exports.checkTouchIcon = checkTouchIcon;
@@ -0,0 +1 @@
1
+ export {};