baseline-browser-mapping 2.4.4 → 2.5.0

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.
@@ -1,465 +0,0 @@
1
- import { createRequire } from "node:module";
2
- const require = createRequire(import.meta.url);
3
- const bcdBrowsers = require("@mdn/browser-compat-data");
4
- const otherBrowsers = require("../data/downstream-browsers.json");
5
- import { features } from "web-features";
6
- const bcdCoreBrowserNames = [
7
- "chrome",
8
- "chrome_android",
9
- "edge",
10
- "firefox",
11
- "firefox_android",
12
- "safari",
13
- "safari_ios",
14
- ];
15
- const coreBrowserData = Object.entries(bcdBrowsers.browsers).filter(([browserName]) => bcdCoreBrowserNames.includes(browserName));
16
- const bcdDownstreamBrowserNames = [
17
- "webview_android",
18
- "samsunginternet_android",
19
- "opera_android",
20
- "opera",
21
- ];
22
- const downstreamBrowserData = [
23
- ...Object.entries(bcdBrowsers.browsers).filter(([browserName]) => bcdDownstreamBrowserNames.includes(browserName)),
24
- ...Object.entries(otherBrowsers.browsers),
25
- ];
26
- const acceptableStatuses = [
27
- "current",
28
- "esr",
29
- "retired",
30
- "unknown",
31
- "beta",
32
- "nightly",
33
- ];
34
- let suppressPre2015Warning = false;
35
- const stripLTEPrefix = (str) => {
36
- if (!str) {
37
- return str;
38
- }
39
- if (!str.startsWith("≤")) {
40
- return str;
41
- }
42
- return str.slice(1);
43
- };
44
- const compareVersions = (incomingVersionString, previousVersionString) => {
45
- if (incomingVersionString === previousVersionString) {
46
- return 0;
47
- }
48
- let [incomingVersionStringMajor, incomingVersionStringMinor] = incomingVersionString.split(".");
49
- let [previousVersionStringMajor, previousVersionStringMinor] = previousVersionString.split(".");
50
- if (!incomingVersionStringMajor || !previousVersionStringMajor) {
51
- throw new Error("One of these version strings is broken: " +
52
- incomingVersionString +
53
- " or " +
54
- previousVersionString +
55
- "");
56
- }
57
- if (parseInt(incomingVersionStringMajor) > parseInt(previousVersionStringMajor)) {
58
- return 1;
59
- }
60
- if (incomingVersionStringMinor) {
61
- if (parseInt(incomingVersionStringMajor) ==
62
- parseInt(previousVersionStringMajor) &&
63
- (!previousVersionStringMinor ||
64
- parseInt(incomingVersionStringMinor) >
65
- parseInt(previousVersionStringMinor))) {
66
- return 1;
67
- }
68
- }
69
- return -1;
70
- };
71
- const getCompatibleFeaturesByDate = (date) => {
72
- return Object.entries(features)
73
- .filter(([feature_id, feature]) => feature.status.baseline_low_date &&
74
- new Date(feature.status.baseline_low_date) <= date)
75
- .map(([feature_id, feature]) => {
76
- return {
77
- id: feature_id,
78
- name: feature.name,
79
- baseline_low_date: feature.status.baseline_low_date,
80
- support: feature.status.support,
81
- };
82
- });
83
- };
84
- const getMinimumVersionsFromFeatures = (features) => {
85
- let minimumVersions = {};
86
- Object.entries(coreBrowserData).forEach(([, browserData]) => {
87
- minimumVersions[browserData[0]] = {
88
- browser: browserData[0],
89
- version: "0",
90
- release_date: "",
91
- };
92
- });
93
- features.forEach((feature) => {
94
- Object.entries(feature.support).forEach((browser) => {
95
- const browserName = browser[0];
96
- const version = stripLTEPrefix(browser[1]);
97
- if (minimumVersions[browserName] &&
98
- compareVersions(version, stripLTEPrefix(minimumVersions[browserName].version)) === 1) {
99
- minimumVersions[browserName] = {
100
- browser: browserName,
101
- version: version,
102
- release_date: feature.baseline_low_date,
103
- };
104
- }
105
- });
106
- });
107
- return Object.values(minimumVersions);
108
- };
109
- const getSubsequentVersions = (minimumVersions) => {
110
- let subsequentVersions = [];
111
- minimumVersions.forEach((minimumVersion) => {
112
- let bcdBrowser = coreBrowserData.find((bcdBrowser) => bcdBrowser[0] === minimumVersion.browser);
113
- if (bcdBrowser) {
114
- let sortedVersions = Object.entries(bcdBrowser[1].releases)
115
- .filter(([, versionData]) => {
116
- if (!acceptableStatuses.includes(versionData.status)) {
117
- return false;
118
- }
119
- return true;
120
- })
121
- .sort((a, b) => {
122
- return compareVersions(a[0], b[0]);
123
- });
124
- sortedVersions.forEach(([version, versionData]) => {
125
- if (!acceptableStatuses.includes(versionData.status)) {
126
- return false;
127
- }
128
- if (compareVersions(version, minimumVersion.version) === 1) {
129
- subsequentVersions.push({
130
- browser: minimumVersion.browser,
131
- version: version,
132
- release_date: versionData.release_date
133
- ? versionData.release_date
134
- : "unknown",
135
- });
136
- return true;
137
- }
138
- return false;
139
- });
140
- }
141
- });
142
- return subsequentVersions;
143
- };
144
- const getCoreVersionsByDate = (date, listAllCompatibleVersions = false) => {
145
- if (date.getFullYear() < 2015 && !suppressPre2015Warning) {
146
- console.warn(new Error("There are no browser versions compatible with Baseline before 2015. You may receive unexpected results."));
147
- }
148
- if (date.getFullYear() < 2002) {
149
- throw new Error("None of the browsers in the core set were released before 2002. Please use a date after 2002.");
150
- }
151
- if (date.getFullYear() > new Date().getFullYear()) {
152
- throw new Error("There are no browser versions compatible with Baseline in the future");
153
- }
154
- const compatibleFeatures = getCompatibleFeaturesByDate(date);
155
- const minimumVersions = getMinimumVersionsFromFeatures(compatibleFeatures);
156
- if (!listAllCompatibleVersions) {
157
- return minimumVersions;
158
- }
159
- else {
160
- return [...minimumVersions, ...getSubsequentVersions(minimumVersions)].sort((a, b) => {
161
- if (a.browser < b.browser) {
162
- return -1;
163
- }
164
- else if (a.browser > b.browser) {
165
- return 1;
166
- }
167
- else {
168
- return compareVersions(a.version, b.version);
169
- }
170
- });
171
- }
172
- };
173
- const getDownstreamBrowsers = (inputArray = [], listAllCompatibleVersions = true) => {
174
- let minimumChromeVersion = undefined;
175
- if (inputArray && inputArray.length > 0) {
176
- minimumChromeVersion = inputArray
177
- .filter((browser) => browser.browser === "chrome")
178
- .sort((a, b) => {
179
- return compareVersions(a.version, b.version);
180
- })[0]?.version;
181
- }
182
- if (!minimumChromeVersion) {
183
- throw new Error("There are no browser versions compatible with Baseline before Chrome");
184
- }
185
- let downstreamArray = new Array();
186
- downstreamBrowserData.forEach(([browserName, browserData]) => {
187
- if (!browserData.releases)
188
- return;
189
- let sortedAndFilteredVersions = Object.entries(browserData.releases)
190
- .filter(([, versionData]) => {
191
- if (!versionData.engine) {
192
- return false;
193
- }
194
- if (versionData.engine != "Blink") {
195
- return false;
196
- }
197
- if (versionData.engine_version &&
198
- parseInt(versionData.engine_version) < parseInt(minimumChromeVersion)) {
199
- return false;
200
- }
201
- return true;
202
- })
203
- .sort((a, b) => {
204
- return compareVersions(a[0], b[0]);
205
- });
206
- for (let i = 0; i < sortedAndFilteredVersions.length; i++) {
207
- const versionEntry = sortedAndFilteredVersions[i];
208
- if (versionEntry) {
209
- const [versionNumber, versionData] = versionEntry;
210
- let outputArray = {
211
- browser: browserName,
212
- version: versionNumber,
213
- release_date: versionData.release_date ?? "unknown",
214
- };
215
- if (versionData.engine && versionData.engine_version) {
216
- outputArray.engine = versionData.engine;
217
- outputArray.engine_version = versionData.engine_version;
218
- }
219
- downstreamArray.push(outputArray);
220
- if (!listAllCompatibleVersions) {
221
- break;
222
- }
223
- }
224
- }
225
- });
226
- return downstreamArray;
227
- };
228
- /**
229
- * Returns browser versions compatible with specified Baseline targets.
230
- * Defaults to returning the minimum versions of the core browser set that support Baseline Widely available.
231
- * Takes an optional configuraation object `Object` with four optional properties:
232
- * - `listAllCompatibleVersions`: `false` (default) or `false`
233
- * - `includeDownstreamBrowsers`: `false` (default) or `false`
234
- * - `widelyAvailableOnDate`: date in format `YYYY-MM-DD`
235
- * - `targetYear`: year in format `YYYY`
236
- */
237
- export function getCompatibleVersions(userOptions) {
238
- let incomingOptions = userOptions ?? {};
239
- let options = {
240
- listAllCompatibleVersions: incomingOptions.listAllCompatibleVersions ?? false,
241
- includeDownstreamBrowsers: incomingOptions.includeDownstreamBrowsers ?? false,
242
- widelyAvailableOnDate: incomingOptions.widelyAvailableOnDate ?? undefined,
243
- targetYear: incomingOptions.targetYear ?? undefined,
244
- };
245
- let targetDate = new Date();
246
- if (!options.widelyAvailableOnDate && !options.targetYear) {
247
- targetDate = new Date();
248
- }
249
- else if (options.targetYear && options.widelyAvailableOnDate) {
250
- console.log(new Error("You cannot use targetYear and widelyAvailableOnDate at the same time. Please remove one of these options and try again."));
251
- process.exit(1);
252
- }
253
- else if (options.widelyAvailableOnDate) {
254
- targetDate = new Date(options.widelyAvailableOnDate);
255
- }
256
- else if (options.targetYear) {
257
- targetDate = new Date(`${options.targetYear}-12-31`);
258
- }
259
- // Sets a cutoff date for feature interoperability 30 months before the stated date
260
- if (options.widelyAvailableOnDate || options.targetYear === undefined) {
261
- targetDate.setMonth(targetDate.getMonth() - 30);
262
- }
263
- let coreBrowserArray = getCoreVersionsByDate(targetDate, options.listAllCompatibleVersions);
264
- if (options.includeDownstreamBrowsers === false) {
265
- return coreBrowserArray;
266
- }
267
- else {
268
- return [
269
- ...coreBrowserArray,
270
- ...getDownstreamBrowsers(coreBrowserArray, options.listAllCompatibleVersions),
271
- ];
272
- }
273
- }
274
- /**
275
- * Returns all browser versions known to this module with their level of Baseline support either as an `Array` or a `String` CSV.
276
- * Takes an object as an argument with two optional properties:
277
- * - `includeDownstreamBrowsers`: `true` (default) or `false`
278
- * - `outputFormat`: `array` (default), `object` or `csv`
279
- */
280
- export function getAllVersions(userOptions) {
281
- suppressPre2015Warning = true;
282
- let incomingOptions = userOptions ?? {};
283
- let options = {
284
- outputFormat: incomingOptions.outputFormat ?? "array",
285
- includeDownstreamBrowsers: incomingOptions.includeDownstreamBrowsers ?? false,
286
- useSupports: incomingOptions.useSupports ?? false,
287
- };
288
- let nextYear = new Date().getFullYear() + 1;
289
- const yearArray = [...Array(nextYear).keys()].slice(2002);
290
- const yearMinimumVersions = {};
291
- yearArray.forEach((year) => {
292
- yearMinimumVersions[year] = {};
293
- getCompatibleVersions({ targetYear: year }).forEach((version) => {
294
- if (yearMinimumVersions[year])
295
- yearMinimumVersions[year][version.browser] = version;
296
- });
297
- });
298
- const waMinimumVersions = getCompatibleVersions({});
299
- const waObject = {};
300
- waMinimumVersions.forEach((version) => {
301
- waObject[version.browser] = version;
302
- });
303
- const thirtyMonthsFromToday = new Date();
304
- thirtyMonthsFromToday.setMonth(thirtyMonthsFromToday.getMonth() + 30);
305
- const naMinimumVersions = getCompatibleVersions({
306
- widelyAvailableOnDate: thirtyMonthsFromToday.toISOString().slice(0, 10),
307
- });
308
- const naObject = {};
309
- naMinimumVersions.forEach((version) => {
310
- naObject[version.browser] = version;
311
- });
312
- const allVersions = getCompatibleVersions({
313
- targetYear: 2002,
314
- listAllCompatibleVersions: true,
315
- });
316
- const outputArray = new Array();
317
- bcdCoreBrowserNames.forEach((browserName) => {
318
- let thisBrowserAllVersions = allVersions
319
- .filter((version) => version.browser == browserName)
320
- .sort((a, b) => {
321
- return compareVersions(a.version, b.version);
322
- });
323
- let waVersion = waObject[browserName]?.version ?? "0";
324
- let naVersion = naObject[browserName]?.version ?? "0";
325
- yearArray.forEach((year) => {
326
- if (yearMinimumVersions[year]) {
327
- let minBrowserVersionInfo = yearMinimumVersions[year][browserName] ?? {
328
- version: "0",
329
- };
330
- let minBrowserVersion = minBrowserVersionInfo.version;
331
- let sliceIndex = thisBrowserAllVersions.findIndex((element) => compareVersions(element.version, minBrowserVersion) === 0);
332
- let subArray = year === nextYear - 1
333
- ? thisBrowserAllVersions
334
- : thisBrowserAllVersions.slice(0, sliceIndex);
335
- subArray.forEach((version) => {
336
- let isWaCcompatible = compareVersions(version.version, waVersion) >= 0 ? true : false;
337
- let isNaCompatible = compareVersions(version.version, naVersion) >= 0 ? true : false;
338
- let versionToPush = {
339
- ...version,
340
- year: year <= 2015 ? "pre_baseline" : year - 1,
341
- };
342
- if (options.useSupports) {
343
- if (isWaCcompatible)
344
- versionToPush.supports = "widely";
345
- if (isNaCompatible)
346
- versionToPush.supports = "newly";
347
- }
348
- else {
349
- versionToPush = {
350
- ...versionToPush,
351
- wa_compatible: isWaCcompatible,
352
- };
353
- }
354
- outputArray.push(versionToPush);
355
- });
356
- thisBrowserAllVersions = thisBrowserAllVersions.slice(sliceIndex, thisBrowserAllVersions.length);
357
- }
358
- });
359
- });
360
- if (options.includeDownstreamBrowsers) {
361
- let downstreamBrowsers = getDownstreamBrowsers(outputArray);
362
- downstreamBrowsers.forEach((version) => {
363
- let correspondingChromiumVersion = outputArray.find((upstreamVersion) => upstreamVersion.browser === "chrome" &&
364
- upstreamVersion.version === version.engine_version);
365
- if (correspondingChromiumVersion) {
366
- if (options.useSupports) {
367
- outputArray.push({
368
- ...version,
369
- year: correspondingChromiumVersion.year,
370
- supports: correspondingChromiumVersion.supports,
371
- });
372
- }
373
- else {
374
- outputArray.push({
375
- ...version,
376
- year: correspondingChromiumVersion.year,
377
- wa_compatible: correspondingChromiumVersion.wa_compatible,
378
- });
379
- }
380
- }
381
- });
382
- }
383
- outputArray.sort((a, b) => {
384
- // Sort by year: "pre_baseline" first, then numerical year in ascending order
385
- if (a.year === "pre_baseline" && b.year !== "pre_baseline") {
386
- return -1;
387
- }
388
- if (b.year === "pre_baseline" && a.year !== "pre_baseline") {
389
- return 1;
390
- }
391
- if (a.year !== "pre_baseline" && b.year !== "pre_baseline") {
392
- if (a.year < b.year) {
393
- return -1;
394
- }
395
- if (a.year > b.year) {
396
- return 1;
397
- }
398
- }
399
- // Sort by browser alphabetically
400
- if (a.browser < b.browser) {
401
- return -1;
402
- }
403
- if (a.browser > b.browser) {
404
- return 1;
405
- }
406
- // Sort by version using compareVersions
407
- return compareVersions(a.version, b.version);
408
- });
409
- if (options.outputFormat === "object") {
410
- const outputObject = {};
411
- outputArray.forEach((version) => {
412
- if (!outputObject[version.browser]) {
413
- outputObject[version.browser] = {};
414
- }
415
- let versionToAdd = {
416
- year: version.year,
417
- release_date: version.release_date,
418
- engine: version.engine,
419
- engine_version: version.engine_version,
420
- };
421
- if (options.useSupports) {
422
- //@ts-ignore
423
- outputObject[version.browser][version.version] = version.supports
424
- ? { ...versionToAdd, supports: version.supports }
425
- : versionToAdd;
426
- }
427
- else {
428
- //@ts-ignores
429
- outputObject[version.browser][version.version] = {
430
- ...versionToAdd,
431
- wa_compatible: version.wa_compatible,
432
- };
433
- }
434
- });
435
- return outputObject ?? {};
436
- }
437
- if (options.outputFormat === "csv") {
438
- let outputString = `"browser","version","year",` +
439
- `"${options.useSupports ? "supports" : "wa_compatible"}",` +
440
- `"release_date","engine","engine_version"`;
441
- outputArray.forEach((version) => {
442
- let outputs = {
443
- browser: version.browser,
444
- version: version.version,
445
- year: version.year,
446
- release_date: version.release_date ?? "NULL",
447
- engine: version.engine ?? "NULL",
448
- engine_version: version.engine_version ?? "NULL",
449
- };
450
- outputs = options.useSupports
451
- ? { ...outputs, supports: version.supports ?? "" }
452
- : { ...outputs, wa_compatible: version.wa_compatible };
453
- outputString +=
454
- `\n"${outputs.browser}","` +
455
- `${outputs.version}","` +
456
- `${outputs.year}","` +
457
- `${options.useSupports ? outputs.supports : outputs.wa_compatible}","` +
458
- `${outputs.release_date}","` +
459
- `${outputs.engine}","` +
460
- `${outputs.engine_version}"`;
461
- });
462
- return outputString;
463
- }
464
- return outputArray;
465
- }