-
-
Notifications
You must be signed in to change notification settings - Fork 33
/
get-browsers.js
119 lines (98 loc) · 3.36 KB
/
get-browsers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import browserslist from 'browserslist'
import { readFileSync } from 'fs'
import { URL } from 'url'
import { agents as caniuseAgents, region as caniuseRegion } from 'caniuse-lite'
let { version: bv } = importJSON('./node_modules/browserslist/package.json')
let { version: cv } = importJSON('./node_modules/caniuse-lite/package.json')
let wikipediaLinks = importJSON('../browsers-data/wikipedia-links.json')
const GLOBAL_REGION = 'Global'
export default async function getBrowsers(query) {
let region = parseRegionFromQuery(query)
// TODO Add support `Node > 0` query
let loadBrowsersData = async (resolve, reject) => {
let browsersByQuery = []
try {
browsersByQuery = browserslist(query)
} catch (error) {
reject(
error.browserslist
? error.message
: `Unknown browser query \`${query}\`.`
)
return
}
let browsersGroups = {}
let browsersGroupsKeys = []
for (let browser of browsersByQuery) {
if (browsersGroupsKeys.includes(browser)) {
return
}
browsersGroupsKeys.push(browser)
let [id, version] = browser.split(' ')
let versionCoverage = region === GLOBAL_REGION
? getGlobalCoverage(id, version)
: await getRegionCoverage(id, version, region)
let versionData = { version, coverage: roundNumber(versionCoverage) }
if (!browsersGroups[id]) {
browsersGroups[id] = { versions: [versionData] }
} else {
browsersGroups[id].versions.push(versionData)
}
}
let browsers = Object.entries(browsersGroups)
.map(([id, data]) => {
let { browser: name, usage_global: usageGlobal } = caniuseAgents[id]
// TODO Add regional coverage
let coverage = roundNumber(
Object.values(usageGlobal).reduce((a, b) => a + b, 0)
)
let wiki = wikipediaLinks[id]
let versions = data.versions.sort((a, b) => b.coverage - a.coverage)
return {
id,
name,
wiki,
coverage,
versions
}
})
.sort((a, b) => b.coverage - a.coverage)
resolve({
query,
region: region || GLOBAL_REGION,
coverage: browserslist.coverage(browsersByQuery, region),
versions: {
browserslist: bv,
caniuse: cv
},
browsers
})
}
return new Promise(loadBrowsersData)
}
function parseRegionFromQuery(query) {
let queryParsed = browserslist.parse(query)
// TODO Take the most frequent region in large queries?
let firstQueryRegion = queryParsed.find(x => x.place)
return firstQueryRegion ? firstQueryRegion.place : GLOBAL_REGION
}
function getGlobalCoverage(id, version) {
return getCoverage(caniuseAgents[id].usage_global, version)
}
async function getRegionCoverage(id, version, region) {
let { default: regionData } = await import(
`./node_modules/caniuse-lite/data/regions/${region}.js`
)
return getCoverage(caniuseRegion(regionData)[id], version)
}
function getCoverage(data, version) {
let [lastVersion] = Object.keys(data).sort((a, b) => Number(b) - Number(a))
// If specific version coverage is missing, fall back to 'version zero'
return data[version] !== undefined ? data[version] : data[lastVersion]
}
function roundNumber(value) {
return Math.round(value * 100) / 100
}
function importJSON(path) {
return JSON.parse(readFileSync(new URL(path, import.meta.url)))
}