@realfavicongenerator/check-favicon 0.1.2 → 0.2.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/README.md +1 -1
- package/dist/check.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/web-app-manifest.d.ts +4 -0
- package/dist/web-app-manifest.js +262 -0
- package/dist/web-app-manifest.test.d.ts +1 -0
- package/dist/web-app-manifest.test.js +172 -0
- package/package.json +4 -4
- package/src/check.ts +1 -1
- package/src/index.ts +2 -2
- package/src/types.ts +2 -2
- package/src/{web-manifest.test.ts → web-app-manifest.test.ts} +13 -13
- package/src/{web-manifest.ts → web-app-manifest.ts} +4 -4
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ const head = root.querySelector('head');
|
|
|
20
20
|
|
|
21
21
|
const desktopFaviconReport = await checkDesktopFavicon(pageUrl, head);
|
|
22
22
|
const touchIconFaviconReport = await checkTouchIcon(pageUrl, head);
|
|
23
|
-
const webAppManifestFaviconReport = await
|
|
23
|
+
const webAppManifestFaviconReport = await checkWebAppManifest(pageUrl, head);
|
|
24
24
|
|
|
25
25
|
console.log("Analysis and icons", desktopFaviconReport, touchIconFaviconReport, webAppManifestFaviconReport);
|
|
26
26
|
```
|
package/dist/check.js
CHANGED
|
@@ -13,11 +13,11 @@ exports.checkFavicon = void 0;
|
|
|
13
13
|
const desktop_1 = require("./desktop/desktop");
|
|
14
14
|
const helper_1 = require("./helper");
|
|
15
15
|
const touch_icon_1 = require("./touch-icon");
|
|
16
|
-
const
|
|
16
|
+
const web_app_manifest_1 = require("./web-app-manifest");
|
|
17
17
|
const checkFavicon = (baseUrl_1, head_1, ...args_1) => __awaiter(void 0, [baseUrl_1, head_1, ...args_1], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
|
|
18
18
|
const desktop = yield (0, desktop_1.checkDesktopFavicon)(baseUrl, head, fetcher);
|
|
19
19
|
const touchIcon = yield (0, touch_icon_1.checkTouchIcon)(baseUrl, head, fetcher);
|
|
20
|
-
const webAppManifest = yield (0,
|
|
20
|
+
const webAppManifest = yield (0, web_app_manifest_1.checkWebAppManifest)(baseUrl, head, fetcher);
|
|
21
21
|
return {
|
|
22
22
|
desktop,
|
|
23
23
|
touchIcon,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { CheckerStatus, MessageId, CheckerMessage, DesktopFaviconReport, TouchIconTitleReport, TouchIconIconReport,
|
|
1
|
+
export { CheckerStatus, MessageId, CheckerMessage, DesktopFaviconReport, TouchIconTitleReport, TouchIconIconReport, WebAppManifestReport, FaviconReport, TouchIconReport } from './types';
|
|
2
2
|
export { checkDesktopFavicon, checkSvgFavicon } from "./desktop/desktop";
|
|
3
3
|
export { checkTouchIcon } from "./touch-icon";
|
|
4
|
-
export { checkWebAppManifest } from "./web-manifest";
|
|
4
|
+
export { checkWebAppManifest } from "./web-app-manifest";
|
|
5
5
|
export { checkFavicon } from "./check";
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "checkDesktopFavicon", { enumerable: true, get: f
|
|
|
9
9
|
Object.defineProperty(exports, "checkSvgFavicon", { enumerable: true, get: function () { return desktop_1.checkSvgFavicon; } });
|
|
10
10
|
var touch_icon_1 = require("./touch-icon");
|
|
11
11
|
Object.defineProperty(exports, "checkTouchIcon", { enumerable: true, get: function () { return touch_icon_1.checkTouchIcon; } });
|
|
12
|
-
var
|
|
13
|
-
Object.defineProperty(exports, "checkWebAppManifest", { enumerable: true, get: function () { return
|
|
12
|
+
var web_app_manifest_1 = require("./web-app-manifest");
|
|
13
|
+
Object.defineProperty(exports, "checkWebAppManifest", { enumerable: true, get: function () { return web_app_manifest_1.checkWebAppManifest; } });
|
|
14
14
|
var check_1 = require("./check");
|
|
15
15
|
Object.defineProperty(exports, "checkFavicon", { enumerable: true, get: function () { return check_1.checkFavicon; } });
|
package/dist/types.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export type TouchIconIconReport = {
|
|
|
97
97
|
messages: CheckerMessage[];
|
|
98
98
|
touchIcon: string | null;
|
|
99
99
|
};
|
|
100
|
-
export type
|
|
100
|
+
export type WebAppManifestReport = {
|
|
101
101
|
messages: CheckerMessage[];
|
|
102
102
|
name?: string;
|
|
103
103
|
shortName?: string;
|
|
@@ -108,6 +108,6 @@ export type WebManifestReport = {
|
|
|
108
108
|
export type FaviconReport = {
|
|
109
109
|
desktop: DesktopFaviconReport;
|
|
110
110
|
touchIcon: TouchIconReport;
|
|
111
|
-
webAppManifest:
|
|
111
|
+
webAppManifest: WebAppManifestReport;
|
|
112
112
|
};
|
|
113
113
|
export type TouchIconReport = TouchIconIconReport & TouchIconTitleReport;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { HTMLElement } from "node-html-parser";
|
|
2
|
+
import { Fetcher, WebAppManifestReport } from "./types";
|
|
3
|
+
export declare const checkWebAppManifest: (baseUrl: string, head: HTMLElement | null, fetcher?: Fetcher) => Promise<WebAppManifestReport>;
|
|
4
|
+
export declare const checkWebAppManifestFile: (manifest: any, baseUrl: string, fetcher: Fetcher) => Promise<WebAppManifestReport>;
|
|
@@ -0,0 +1,262 @@
|
|
|
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 __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
+
var m = o[Symbol.asyncIterator], i;
|
|
14
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.checkWebAppManifestFile = exports.checkWebAppManifest = void 0;
|
|
20
|
+
const types_1 = require("./types");
|
|
21
|
+
const helper_1 = require("./helper");
|
|
22
|
+
const checkWebAppManifest = (baseUrl_1, head_1, ...args_1) => __awaiter(void 0, [baseUrl_1, head_1, ...args_1], void 0, function* (baseUrl, head, fetcher = helper_1.fetchFetcher) {
|
|
23
|
+
const messages = [];
|
|
24
|
+
let name = undefined;
|
|
25
|
+
let shortName = undefined;
|
|
26
|
+
let backgroundColor = undefined;
|
|
27
|
+
let themeColor = undefined;
|
|
28
|
+
let icon = null;
|
|
29
|
+
if (!head) {
|
|
30
|
+
messages.push({
|
|
31
|
+
status: types_1.CheckerStatus.Error,
|
|
32
|
+
id: types_1.MessageId.noHead,
|
|
33
|
+
text: 'No <head> element'
|
|
34
|
+
});
|
|
35
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
36
|
+
}
|
|
37
|
+
const manifestMarkup = head.querySelectorAll("link[rel='manifest']");
|
|
38
|
+
if (manifestMarkup.length === 0) {
|
|
39
|
+
messages.push({
|
|
40
|
+
status: types_1.CheckerStatus.Error,
|
|
41
|
+
id: types_1.MessageId.noManifest,
|
|
42
|
+
text: 'No web app manifest'
|
|
43
|
+
});
|
|
44
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
45
|
+
}
|
|
46
|
+
const href = manifestMarkup[0].getAttribute('href');
|
|
47
|
+
if (!href) {
|
|
48
|
+
messages.push({
|
|
49
|
+
status: types_1.CheckerStatus.Error,
|
|
50
|
+
id: types_1.MessageId.noManifestHref,
|
|
51
|
+
text: 'The web app manifest markup has no `href` attribute'
|
|
52
|
+
});
|
|
53
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
54
|
+
}
|
|
55
|
+
const manifestUrl = (0, helper_1.mergeUrlAndPath)(baseUrl, href);
|
|
56
|
+
const manifest = yield fetcher(manifestUrl, 'application/json');
|
|
57
|
+
if (manifest.status === 404) {
|
|
58
|
+
messages.push({
|
|
59
|
+
status: types_1.CheckerStatus.Error,
|
|
60
|
+
id: types_1.MessageId.manifest404,
|
|
61
|
+
text: `The web app manifest at \`${href}\` is not found`
|
|
62
|
+
});
|
|
63
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
64
|
+
}
|
|
65
|
+
else if (manifest.status >= 300 || !manifest.readableStream) {
|
|
66
|
+
messages.push({
|
|
67
|
+
status: types_1.CheckerStatus.Error,
|
|
68
|
+
id: types_1.MessageId.manifestCannotGet,
|
|
69
|
+
text: `Cannot get the web app manifest at \`${href}\` (${manifest.status} error)`
|
|
70
|
+
});
|
|
71
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
72
|
+
}
|
|
73
|
+
let parsedManifest;
|
|
74
|
+
try {
|
|
75
|
+
parsedManifest = yield readableStreamToJson(manifest.readableStream);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
messages.push({
|
|
79
|
+
status: types_1.CheckerStatus.Error,
|
|
80
|
+
id: types_1.MessageId.manifestInvalidJson,
|
|
81
|
+
text: `Cannot parse the web app manifest at \`${href}\``
|
|
82
|
+
});
|
|
83
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
84
|
+
}
|
|
85
|
+
const manifestReport = yield (0, exports.checkWebAppManifestFile)(parsedManifest, manifestUrl, fetcher);
|
|
86
|
+
return Object.assign(Object.assign({}, manifestReport), { messages: messages.concat(manifestReport.messages) });
|
|
87
|
+
});
|
|
88
|
+
exports.checkWebAppManifest = checkWebAppManifest;
|
|
89
|
+
const readableStreamToJson = (stream) => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
|
+
const reader = stream.getReader();
|
|
91
|
+
const decoder = new TextDecoder();
|
|
92
|
+
let result = '';
|
|
93
|
+
while (true) {
|
|
94
|
+
const { done, value } = yield reader.read();
|
|
95
|
+
if (done) {
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
result += decoder.decode(value);
|
|
99
|
+
}
|
|
100
|
+
return JSON.parse(result);
|
|
101
|
+
});
|
|
102
|
+
const checkWebAppManifestFile = (manifest, baseUrl, fetcher) => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
var _a, e_1, _b, _c;
|
|
104
|
+
const messages = [];
|
|
105
|
+
let icon = null;
|
|
106
|
+
const name = manifest.name || undefined;
|
|
107
|
+
if (!name) {
|
|
108
|
+
messages.push({
|
|
109
|
+
status: types_1.CheckerStatus.Error,
|
|
110
|
+
id: types_1.MessageId.noManifestName,
|
|
111
|
+
text: 'The web app manifest has no `name`'
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
messages.push({
|
|
116
|
+
status: types_1.CheckerStatus.Ok,
|
|
117
|
+
id: types_1.MessageId.manifestName,
|
|
118
|
+
text: `The web app manifest has the name "${name}"`
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const shortName = manifest.short_name || undefined;
|
|
122
|
+
if (!shortName) {
|
|
123
|
+
messages.push({
|
|
124
|
+
status: types_1.CheckerStatus.Error,
|
|
125
|
+
id: types_1.MessageId.noManifestShortName,
|
|
126
|
+
text: 'The web app manifest has no `short_name`'
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
messages.push({
|
|
131
|
+
status: types_1.CheckerStatus.Ok,
|
|
132
|
+
id: types_1.MessageId.manifestShortName,
|
|
133
|
+
text: `The web app manifest has the short name "${shortName}"`
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const backgroundColor = manifest.background_color || undefined;
|
|
137
|
+
if (!backgroundColor) {
|
|
138
|
+
messages.push({
|
|
139
|
+
status: types_1.CheckerStatus.Error,
|
|
140
|
+
id: types_1.MessageId.noManifestBackgroundColor,
|
|
141
|
+
text: 'The web app manifest has no `background_color`'
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
messages.push({
|
|
146
|
+
status: types_1.CheckerStatus.Ok,
|
|
147
|
+
id: types_1.MessageId.manifestBackgroundColor,
|
|
148
|
+
text: `The web app manifest has the background color \`${backgroundColor}\``
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const themeColor = manifest.theme_color || undefined;
|
|
152
|
+
if (!themeColor) {
|
|
153
|
+
messages.push({
|
|
154
|
+
status: types_1.CheckerStatus.Error,
|
|
155
|
+
id: types_1.MessageId.noManifestThemeColor,
|
|
156
|
+
text: 'The web app manifest has no `theme_color`'
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
messages.push({
|
|
161
|
+
status: types_1.CheckerStatus.Ok,
|
|
162
|
+
id: types_1.MessageId.manifestThemeColor,
|
|
163
|
+
text: `The web app manifest has the theme color \`${themeColor}\``
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const icons = manifest.icons;
|
|
167
|
+
if (!icons || !Array.isArray(icons) || icons.length === 0) {
|
|
168
|
+
messages.push({
|
|
169
|
+
status: types_1.CheckerStatus.Error,
|
|
170
|
+
id: types_1.MessageId.noManifestIcons,
|
|
171
|
+
text: 'The web app manifest has no `icons`'
|
|
172
|
+
});
|
|
173
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
for (var _d = true, _e = __asyncValues([192, 512]), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
177
|
+
_c = _f.value;
|
|
178
|
+
_d = false;
|
|
179
|
+
const size = _c;
|
|
180
|
+
const iconEntry = icons.find((icon) => icon.sizes === `${size}x${size}`);
|
|
181
|
+
if (!iconEntry) {
|
|
182
|
+
messages.push({
|
|
183
|
+
status: types_1.CheckerStatus.Error,
|
|
184
|
+
id: types_1.MessageId.noManifestIcon,
|
|
185
|
+
text: `The web app manifest has no ${size}x${size} icon`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
messages.push({
|
|
190
|
+
status: types_1.CheckerStatus.Ok,
|
|
191
|
+
id: types_1.MessageId.manifestIconDeclared,
|
|
192
|
+
text: `The web app manifest has a ${size}x${size} icon`
|
|
193
|
+
});
|
|
194
|
+
const iconUrl = (0, helper_1.mergeUrlAndPath)(baseUrl, iconEntry.src);
|
|
195
|
+
const processor = {
|
|
196
|
+
cannotGet: (status) => {
|
|
197
|
+
messages.push({
|
|
198
|
+
status: types_1.CheckerStatus.Error,
|
|
199
|
+
id: types_1.MessageId.manifestIconCannotGet,
|
|
200
|
+
text: `The ${size}x${size} icon cannot be fetched (${status})`
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
downloadable: () => {
|
|
204
|
+
messages.push({
|
|
205
|
+
status: types_1.CheckerStatus.Ok,
|
|
206
|
+
id: types_1.MessageId.manifestIconDownloadable,
|
|
207
|
+
text: `The ${size}x${size} icon is downloadable`
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
icon404: () => {
|
|
211
|
+
messages.push({
|
|
212
|
+
status: types_1.CheckerStatus.Error,
|
|
213
|
+
id: types_1.MessageId.manifestIcon404,
|
|
214
|
+
text: `The ${size}x${size} icon is not found`
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
noHref: () => {
|
|
218
|
+
messages.push({
|
|
219
|
+
status: types_1.CheckerStatus.Error,
|
|
220
|
+
id: types_1.MessageId.manifestIconNoHref,
|
|
221
|
+
text: `The ${size}x${size} icon has no \`href\` attribute`
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
notSquare: () => {
|
|
225
|
+
messages.push({
|
|
226
|
+
status: types_1.CheckerStatus.Error,
|
|
227
|
+
id: types_1.MessageId.manifestIconNotSquare,
|
|
228
|
+
text: `The ${size}x${size} icon is not square`
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
rightSize: () => {
|
|
232
|
+
messages.push({
|
|
233
|
+
status: types_1.CheckerStatus.Ok,
|
|
234
|
+
id: types_1.MessageId.manifestIconRightSize,
|
|
235
|
+
text: `The ${size}x${size} icon has the right size`
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
square: () => {
|
|
239
|
+
// Ignore this, just check the size
|
|
240
|
+
},
|
|
241
|
+
wrongSize: (actualSize) => {
|
|
242
|
+
messages.push({
|
|
243
|
+
status: types_1.CheckerStatus.Error,
|
|
244
|
+
id: types_1.MessageId.manifestIconWrongSize,
|
|
245
|
+
text: `The ${size}x${size} icon has the wrong size (${actualSize})`
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
icon = yield (0, helper_1.checkIcon)(iconUrl, processor, fetcher, iconEntry.type || (0, helper_1.pathToMimeType)(iconEntry.src), size);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
254
|
+
finally {
|
|
255
|
+
try {
|
|
256
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
257
|
+
}
|
|
258
|
+
finally { if (e_1) throw e_1.error; }
|
|
259
|
+
}
|
|
260
|
+
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
261
|
+
});
|
|
262
|
+
exports.checkWebAppManifestFile = checkWebAppManifestFile;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
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
|
+
const node_html_parser_1 = __importDefault(require("node-html-parser"));
|
|
16
|
+
const types_1 = require("./types");
|
|
17
|
+
const web_app_manifest_1 = require("./web-app-manifest");
|
|
18
|
+
const test_helper_1 = require("./test-helper");
|
|
19
|
+
const helper_1 = require("./helper");
|
|
20
|
+
const filterOutput = (report) => (Object.assign(Object.assign({}, report), { messages: report.messages.map(m => ({ status: m.status, id: m.id })) }));
|
|
21
|
+
const runCheckTouchIconTitleTest = (headFragment_1, output_1, ...args_1) => __awaiter(void 0, [headFragment_1, output_1, ...args_1], void 0, function* (headFragment, output, fetchDatabase = {}) {
|
|
22
|
+
const root = headFragment ? (0, node_html_parser_1.default)(headFragment) : null;
|
|
23
|
+
const result = yield (0, web_app_manifest_1.checkWebAppManifest)('https://example.com/', root, (0, test_helper_1.testFetcher)(fetchDatabase));
|
|
24
|
+
expect(filterOutput(result)).toEqual(Object.assign({ name: undefined, shortName: undefined, backgroundColor: undefined, themeColor: undefined, icon: null }, output));
|
|
25
|
+
});
|
|
26
|
+
test('checkWebAppManifest - noHead', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
yield runCheckTouchIconTitleTest(null, { messages: [{
|
|
28
|
+
status: types_1.CheckerStatus.Error,
|
|
29
|
+
id: types_1.MessageId.noHead,
|
|
30
|
+
}] });
|
|
31
|
+
}));
|
|
32
|
+
test('checkWebAppManifest - noManifest', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
|
+
yield runCheckTouchIconTitleTest('<title>Hey</title>', { messages: [{
|
|
34
|
+
status: types_1.CheckerStatus.Error,
|
|
35
|
+
id: types_1.MessageId.noManifest,
|
|
36
|
+
}] });
|
|
37
|
+
}));
|
|
38
|
+
test('checkWebAppManifest - noManifestHref', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
+
yield runCheckTouchIconTitleTest('<link rel="manifest" />', { messages: [{
|
|
40
|
+
status: types_1.CheckerStatus.Error,
|
|
41
|
+
id: types_1.MessageId.noManifestHref,
|
|
42
|
+
}] });
|
|
43
|
+
}));
|
|
44
|
+
test('checkWebAppManifest - manifest404', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
yield runCheckTouchIconTitleTest('<link rel="manifest" href="not-found.json" />', { messages: [{
|
|
46
|
+
status: types_1.CheckerStatus.Error,
|
|
47
|
+
id: types_1.MessageId.manifest404,
|
|
48
|
+
}] });
|
|
49
|
+
}));
|
|
50
|
+
test('checkWebAppManifest - manifestCannotGet', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
|
+
yield runCheckTouchIconTitleTest('<link rel="manifest" href="/error.json" />', { messages: [{
|
|
52
|
+
status: types_1.CheckerStatus.Error,
|
|
53
|
+
id: types_1.MessageId.manifestCannotGet,
|
|
54
|
+
}] }, {
|
|
55
|
+
'https://example.com/error.json': {
|
|
56
|
+
status: 500,
|
|
57
|
+
contentType: 'application/json',
|
|
58
|
+
readableStream: null
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}));
|
|
62
|
+
test('checkWebAppManifest - manifestInvalidJson', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
yield runCheckTouchIconTitleTest('<link rel="manifest" href="/bad-manifest.json" />', { messages: [{
|
|
64
|
+
status: types_1.CheckerStatus.Error,
|
|
65
|
+
id: types_1.MessageId.manifestInvalidJson,
|
|
66
|
+
}] }, {
|
|
67
|
+
'https://example.com/bad-manifest.json': {
|
|
68
|
+
status: 200,
|
|
69
|
+
contentType: 'application/json',
|
|
70
|
+
readableStream: stringToReadableStream('{ bad JSON }')
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}));
|
|
74
|
+
const stringToReadableStream = (str) => {
|
|
75
|
+
const stream = new ReadableStream({
|
|
76
|
+
start(controller) {
|
|
77
|
+
controller.enqueue(new TextEncoder().encode(str));
|
|
78
|
+
controller.close();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return stream;
|
|
82
|
+
};
|
|
83
|
+
test('checkWebAppManifestFile - Missing fields', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
+
const report = yield (0, web_app_manifest_1.checkWebAppManifestFile)({
|
|
85
|
+
name: null,
|
|
86
|
+
short_name: null,
|
|
87
|
+
background_color: null,
|
|
88
|
+
theme_color: null,
|
|
89
|
+
icons: []
|
|
90
|
+
}, 'https://example.com/', (0, test_helper_1.testFetcher)({}));
|
|
91
|
+
expect(filterOutput(report)).toEqual({
|
|
92
|
+
messages: [{
|
|
93
|
+
status: types_1.CheckerStatus.Error,
|
|
94
|
+
id: types_1.MessageId.noManifestName,
|
|
95
|
+
}, {
|
|
96
|
+
status: types_1.CheckerStatus.Error,
|
|
97
|
+
id: types_1.MessageId.noManifestShortName,
|
|
98
|
+
}, {
|
|
99
|
+
status: types_1.CheckerStatus.Error,
|
|
100
|
+
id: types_1.MessageId.noManifestBackgroundColor,
|
|
101
|
+
}, {
|
|
102
|
+
status: types_1.CheckerStatus.Error,
|
|
103
|
+
id: types_1.MessageId.noManifestThemeColor,
|
|
104
|
+
}, {
|
|
105
|
+
status: types_1.CheckerStatus.Error,
|
|
106
|
+
id: types_1.MessageId.noManifestIcons,
|
|
107
|
+
}],
|
|
108
|
+
name: undefined,
|
|
109
|
+
shortName: undefined,
|
|
110
|
+
backgroundColor: undefined,
|
|
111
|
+
themeColor: undefined,
|
|
112
|
+
icon: null
|
|
113
|
+
});
|
|
114
|
+
}));
|
|
115
|
+
const testIcon192 = './fixtures/192x192.png';
|
|
116
|
+
const testIcon512 = './fixtures/512x512.png';
|
|
117
|
+
test('checkWebAppManifestFile - Everything is fine', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
118
|
+
const report = yield (0, web_app_manifest_1.checkWebAppManifestFile)({
|
|
119
|
+
name: 'My long name',
|
|
120
|
+
short_name: 'Short!',
|
|
121
|
+
background_color: '#123456',
|
|
122
|
+
theme_color: '#abcdef',
|
|
123
|
+
icons: [
|
|
124
|
+
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
|
|
125
|
+
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' }
|
|
126
|
+
]
|
|
127
|
+
}, 'https://example.com/', (0, test_helper_1.testFetcher)({
|
|
128
|
+
'https://example.com/icon-192.png': {
|
|
129
|
+
status: 200,
|
|
130
|
+
contentType: 'image/png',
|
|
131
|
+
readableStream: yield (0, helper_1.filePathToReadableStream)(testIcon192)
|
|
132
|
+
},
|
|
133
|
+
'https://example.com/icon-512.png': {
|
|
134
|
+
status: 200,
|
|
135
|
+
contentType: 'image/png',
|
|
136
|
+
readableStream: yield (0, helper_1.filePathToReadableStream)(testIcon512)
|
|
137
|
+
}
|
|
138
|
+
}));
|
|
139
|
+
const expectedIconReport = [
|
|
140
|
+
{
|
|
141
|
+
status: types_1.CheckerStatus.Ok,
|
|
142
|
+
id: types_1.MessageId.manifestIconDeclared,
|
|
143
|
+
}, {
|
|
144
|
+
status: types_1.CheckerStatus.Ok,
|
|
145
|
+
id: types_1.MessageId.manifestIconDownloadable,
|
|
146
|
+
}, {
|
|
147
|
+
status: types_1.CheckerStatus.Ok,
|
|
148
|
+
id: types_1.MessageId.manifestIconRightSize,
|
|
149
|
+
}
|
|
150
|
+
];
|
|
151
|
+
expect(filterOutput(report)).toEqual({
|
|
152
|
+
messages: [{
|
|
153
|
+
status: types_1.CheckerStatus.Ok,
|
|
154
|
+
id: types_1.MessageId.manifestName,
|
|
155
|
+
}, {
|
|
156
|
+
status: types_1.CheckerStatus.Ok,
|
|
157
|
+
id: types_1.MessageId.manifestShortName,
|
|
158
|
+
}, {
|
|
159
|
+
status: types_1.CheckerStatus.Ok,
|
|
160
|
+
id: types_1.MessageId.manifestBackgroundColor,
|
|
161
|
+
}, {
|
|
162
|
+
status: types_1.CheckerStatus.Ok,
|
|
163
|
+
id: types_1.MessageId.manifestThemeColor,
|
|
164
|
+
},
|
|
165
|
+
...expectedIconReport, ...expectedIconReport], // Two icons
|
|
166
|
+
name: 'My long name',
|
|
167
|
+
shortName: 'Short!',
|
|
168
|
+
backgroundColor: '#123456',
|
|
169
|
+
themeColor: '#abcdef',
|
|
170
|
+
icon: (0, helper_1.bufferToDataUrl)(yield (0, helper_1.readableStreamToBuffer)(yield (0, helper_1.filePathToReadableStream)(testIcon512)), 'image/png')
|
|
171
|
+
});
|
|
172
|
+
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@realfavicongenerator/check-favicon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Check the favicon of a website",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"author": "Philippe Bernard",
|
|
24
24
|
"license": "ISC",
|
|
25
25
|
"bugs": {
|
|
26
|
-
"url": "https://github.com/RealFaviconGenerator/
|
|
26
|
+
"url": "https://github.com/RealFaviconGenerator/core/issues"
|
|
27
27
|
},
|
|
28
|
-
"homepage": "https://github.com/RealFaviconGenerator/
|
|
28
|
+
"homepage": "https://github.com/RealFaviconGenerator/core#readme",
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/jest": "^29.5.12",
|
|
31
31
|
"@types/node": "^20.11.30",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"node-html-parser": "^6.1.13",
|
|
39
39
|
"sharp": "^0.32.6"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "c6fb830f9f1aef0013f6dc013e6d2387a384d268"
|
|
42
42
|
}
|
package/src/check.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { fetchFetcher } from "./helper";
|
|
|
3
3
|
import { checkTouchIcon } from "./touch-icon";
|
|
4
4
|
import { FaviconReport, Fetcher } from "./types";
|
|
5
5
|
import { HTMLElement } from 'node-html-parser'
|
|
6
|
-
import { checkWebAppManifest } from "./web-manifest";
|
|
6
|
+
import { checkWebAppManifest } from "./web-app-manifest";
|
|
7
7
|
|
|
8
8
|
export const checkFavicon = async (baseUrl: string, head: HTMLElement | null, fetcher: Fetcher = fetchFetcher): Promise<FaviconReport> => {
|
|
9
9
|
const desktop = await checkDesktopFavicon(baseUrl, head, fetcher);
|
package/src/index.ts
CHANGED
|
@@ -6,12 +6,12 @@ export {
|
|
|
6
6
|
DesktopFaviconReport,
|
|
7
7
|
TouchIconTitleReport,
|
|
8
8
|
TouchIconIconReport,
|
|
9
|
-
|
|
9
|
+
WebAppManifestReport,
|
|
10
10
|
FaviconReport,
|
|
11
11
|
TouchIconReport
|
|
12
12
|
} from './types';
|
|
13
13
|
|
|
14
14
|
export { checkDesktopFavicon, checkSvgFavicon } from "./desktop/desktop"
|
|
15
15
|
export { checkTouchIcon } from "./touch-icon"
|
|
16
|
-
export { checkWebAppManifest } from "./web-manifest"
|
|
16
|
+
export { checkWebAppManifest } from "./web-app-manifest"
|
|
17
17
|
export { checkFavicon } from "./check"
|
package/src/types.ts
CHANGED
|
@@ -111,7 +111,7 @@ export type TouchIconIconReport = {
|
|
|
111
111
|
touchIcon: string | null,
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export type
|
|
114
|
+
export type WebAppManifestReport = {
|
|
115
115
|
messages: CheckerMessage[],
|
|
116
116
|
name?: string,
|
|
117
117
|
shortName?: string,
|
|
@@ -123,7 +123,7 @@ export type WebManifestReport = {
|
|
|
123
123
|
export type FaviconReport = {
|
|
124
124
|
desktop: DesktopFaviconReport,
|
|
125
125
|
touchIcon: TouchIconReport,
|
|
126
|
-
webAppManifest:
|
|
126
|
+
webAppManifest: WebAppManifestReport
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
export type TouchIconReport = TouchIconIconReport & TouchIconTitleReport;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import parse from "node-html-parser";
|
|
2
|
-
import { CheckerMessage, CheckerStatus, FetchResponse, MessageId,
|
|
3
|
-
import { checkWebAppManifest,
|
|
2
|
+
import { CheckerMessage, CheckerStatus, FetchResponse, MessageId, WebAppManifestReport } from "./types";
|
|
3
|
+
import { checkWebAppManifest, checkWebAppManifestFile } from "./web-app-manifest";
|
|
4
4
|
import { testFetcher } from "./test-helper";
|
|
5
5
|
import { bufferToDataUrl, filePathToReadableStream, readableStreamToBuffer } from "./helper";
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ type TestOutput = {
|
|
|
13
13
|
icon?: string | null
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const filterOutput = (report:
|
|
16
|
+
const filterOutput = (report: WebAppManifestReport): any => ({
|
|
17
17
|
...report,
|
|
18
18
|
messages: report.messages.map(m => ({ status: m.status, id: m.id }))
|
|
19
19
|
})
|
|
@@ -35,35 +35,35 @@ const runCheckTouchIconTitleTest = async (
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
test('
|
|
38
|
+
test('checkWebAppManifest - noHead', async () => {
|
|
39
39
|
await runCheckTouchIconTitleTest(null, { messages: [{
|
|
40
40
|
status: CheckerStatus.Error,
|
|
41
41
|
id: MessageId.noHead,
|
|
42
42
|
}]});
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
test('
|
|
45
|
+
test('checkWebAppManifest - noManifest', async () => {
|
|
46
46
|
await runCheckTouchIconTitleTest('<title>Hey</title>', { messages: [{
|
|
47
47
|
status: CheckerStatus.Error,
|
|
48
48
|
id: MessageId.noManifest,
|
|
49
49
|
}]});
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
test('
|
|
52
|
+
test('checkWebAppManifest - noManifestHref', async () => {
|
|
53
53
|
await runCheckTouchIconTitleTest('<link rel="manifest" />', { messages: [{
|
|
54
54
|
status: CheckerStatus.Error,
|
|
55
55
|
id: MessageId.noManifestHref,
|
|
56
56
|
}]});
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
test('
|
|
59
|
+
test('checkWebAppManifest - manifest404', async () => {
|
|
60
60
|
await runCheckTouchIconTitleTest('<link rel="manifest" href="not-found.json" />', { messages: [{
|
|
61
61
|
status: CheckerStatus.Error,
|
|
62
62
|
id: MessageId.manifest404,
|
|
63
63
|
}]});
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
test('
|
|
66
|
+
test('checkWebAppManifest - manifestCannotGet', async () => {
|
|
67
67
|
await runCheckTouchIconTitleTest('<link rel="manifest" href="/error.json" />', { messages: [{
|
|
68
68
|
status: CheckerStatus.Error,
|
|
69
69
|
id: MessageId.manifestCannotGet,
|
|
@@ -76,7 +76,7 @@ test('checkWebManifest - manifestCannotGet', async () => {
|
|
|
76
76
|
});
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
test('
|
|
79
|
+
test('checkWebAppManifest - manifestInvalidJson', async () => {
|
|
80
80
|
await runCheckTouchIconTitleTest('<link rel="manifest" href="/bad-manifest.json" />', { messages: [{
|
|
81
81
|
status: CheckerStatus.Error,
|
|
82
82
|
id: MessageId.manifestInvalidJson,
|
|
@@ -99,8 +99,8 @@ const stringToReadableStream = (str: string) => {
|
|
|
99
99
|
return stream;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
test('
|
|
103
|
-
const report = await
|
|
102
|
+
test('checkWebAppManifestFile - Missing fields', async () => {
|
|
103
|
+
const report = await checkWebAppManifestFile({
|
|
104
104
|
name: null,
|
|
105
105
|
short_name: null,
|
|
106
106
|
background_color: null,
|
|
@@ -136,8 +136,8 @@ test('checkWebManifestFile - Missing fields', async () => {
|
|
|
136
136
|
const testIcon192 = './fixtures/192x192.png';
|
|
137
137
|
const testIcon512 = './fixtures/512x512.png';
|
|
138
138
|
|
|
139
|
-
test('
|
|
140
|
-
const report = await
|
|
139
|
+
test('checkWebAppManifestFile - Everything is fine', async () => {
|
|
140
|
+
const report = await checkWebAppManifestFile({
|
|
141
141
|
name: 'My long name',
|
|
142
142
|
short_name: 'Short!',
|
|
143
143
|
background_color: '#123456',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { HTMLElement } from "node-html-parser";
|
|
2
|
-
import { CheckerMessage, CheckerStatus, Fetcher, MessageId,
|
|
2
|
+
import { CheckerMessage, CheckerStatus, Fetcher, MessageId, WebAppManifestReport } from "./types";
|
|
3
3
|
import { CheckIconProcessor, checkIcon, fetchFetcher, mergeUrlAndPath, pathToMimeType } from "./helper";
|
|
4
4
|
|
|
5
|
-
export const checkWebAppManifest = async (baseUrl: string, head: HTMLElement | null, fetcher: Fetcher = fetchFetcher): Promise<
|
|
5
|
+
export const checkWebAppManifest = async (baseUrl: string, head: HTMLElement | null, fetcher: Fetcher = fetchFetcher): Promise<WebAppManifestReport> => {
|
|
6
6
|
const messages: CheckerMessage[] = [];
|
|
7
7
|
let name = undefined;
|
|
8
8
|
let shortName = undefined;
|
|
@@ -77,7 +77,7 @@ export const checkWebAppManifest = async (baseUrl: string, head: HTMLElement | n
|
|
|
77
77
|
return { messages, name, shortName, backgroundColor, themeColor, icon };
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
const manifestReport = await
|
|
80
|
+
const manifestReport = await checkWebAppManifestFile(parsedManifest, manifestUrl, fetcher);
|
|
81
81
|
|
|
82
82
|
return {
|
|
83
83
|
...manifestReport,
|
|
@@ -99,7 +99,7 @@ const readableStreamToJson = async (stream: ReadableStream): Promise<any> => {
|
|
|
99
99
|
return JSON.parse(result);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
export const
|
|
102
|
+
export const checkWebAppManifestFile = async (manifest: any, baseUrl: string, fetcher: Fetcher): Promise<WebAppManifestReport> => {
|
|
103
103
|
const messages: CheckerMessage[] = [];
|
|
104
104
|
let icon = null;
|
|
105
105
|
|