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
120
121
122
123
124
125
126
127
128
129
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const BROWSERS = [
{
name: "Firefox",
mustContain: new RegExp(`(?:Firefox|FxiOS)\/(${getVersionRegex(1, 1)})`),
},
{
name: "Opera",
mustContain: new RegExp(`(?:OPR|Opera)\/(${getVersionRegex(1, 1)})`),
},
{
name: "Safari",
mustContain: new RegExp(`Version\/(${getVersionRegex(1, 1)}).+Safari`),
mustNotContain: new RegExp("Chrome|Chromium"),
},
{
name: "Edge",
mustContain: new RegExp(`Edge\/(${getVersionRegex(0, 1)})`),
},
{
name: "Chrome",
mustContain: new RegExp(`(?:Chrome|CriOS)\/(${getVersionRegex(1, 1)})`),
},
{
name: "IE",
mustContain: new RegExp(`MSIE (${getVersionRegex(1, 1)})`),
},
];
const OSES = [
{
name: "iOS",
minMinorVersionCount: 0,
mustContain: new RegExp(`CPU iPhone OS (${getVersionRegex(0, 2)})`),
},
{
name: "iPadOS",
minMinorVersionCount: 0,
mustContain: new RegExp(`CPU OS (${getVersionRegex(0, 2)})`),
},
{
name: "Windows Phone",
minMinorVersionCount: 1,
mustContain: new RegExp(`Windows Phone (${getVersionRegex(1, 2)})`),
},
{
name: "Chrome OS",
minMinorVersionCount: 1,
mustContain: new RegExp(`CrOS .+ (${getVersionRegex(1, 2)})`),
},
{
name: "Android",
minMinorVersionCount: 0,
mustContain: new RegExp(`Android (${getVersionRegex(0, 2)})`),
},
{
name: "Windows NT",
minMinorVersionCount: 1,
mustContain: new RegExp(`Windows NT (${getVersionRegex(1, 2)})`),
},
{
name: "Mac OSX",
minMinorVersionCount: 1,
mustContain: new RegExp(`Intel Mac OS X (${getVersionRegex(1, 2)})`),
},
{
name: "Linux",
mustContain: new RegExp("Linux"),
},
];
function getVersionRegex(minMinorVersionCount, maxMinorVersionCount) {
return `\\d+(?:[._][0-9a-z]+){${minMinorVersionCount},${maxMinorVersionCount}}`;
}
function detect(ua, dataset) {
for (const {
name,
mustContain,
mustNotContain,
minMinorVersionCount,
} of dataset) {
const result = mustContain.exec(ua);
if (!result) {
continue;
}
if (mustNotContain && mustNotContain.test(ua)) {
continue;
}
let version = null;
if (result && result.length === 2) {
// Remove most minor version if that expresses 0.
let parts = result[1].match(/([0-9a-z]+)/g);
parts = parts.reverse();
const validVersionIndex = parts.findIndex(
part => parseInt(part, 10) !== 0
);
if (validVersionIndex !== -1) {
parts = parts.splice(validVersionIndex);
for (let i = 0; i < minMinorVersionCount + 1 - parts.length; i++) {
parts.unshift(0);
}
}
version = parts.reverse().join(".");
}
return { name, version };
}
return null;
}
function parseUserAgent(ua) {
return {
browser: detect(ua, BROWSERS),
os: detect(ua, OSES),
};
}
module.exports = { parseUserAgent };
|