ua-parser-js 1.0.34 → 2.0.0-alpha.1

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/src/ua-parser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v1.0.34
3
- Copyright © 2012-2021 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.0-alpha.1
3
+ Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
4
4
  MIT License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
6
  Supports browser & node.js environment.
@@ -17,7 +17,7 @@
17
17
  /////////////
18
18
 
19
19
 
20
- var LIBVERSION = '1.0.34',
20
+ var LIBVERSION = '2.0.0-alpha.1',
21
21
  EMPTY = '',
22
22
  UNKNOWN = '?',
23
23
  FUNC_TYPE = 'function',
@@ -37,45 +37,78 @@
37
37
  SMARTTV = 'smarttv',
38
38
  WEARABLE = 'wearable',
39
39
  EMBEDDED = 'embedded',
40
- UA_MAX_LENGTH = 350;
41
-
42
- var AMAZON = 'Amazon',
43
- APPLE = 'Apple',
44
- ASUS = 'ASUS',
45
- BLACKBERRY = 'BlackBerry',
46
- BROWSER = 'Browser',
47
- CHROME = 'Chrome',
48
- EDGE = 'Edge',
49
- FIREFOX = 'Firefox',
50
- GOOGLE = 'Google',
51
- HUAWEI = 'Huawei',
52
- LG = 'LG',
53
- MICROSOFT = 'Microsoft',
54
- MOTOROLA = 'Motorola',
55
- OPERA = 'Opera',
56
- SAMSUNG = 'Samsung',
57
- SHARP = 'Sharp',
58
- SONY = 'Sony',
59
- VIERA = 'Viera',
60
- XIAOMI = 'Xiaomi',
61
- ZEBRA = 'Zebra',
40
+ USER_AGENT = 'user-agent',
41
+ UA_MAX_LENGTH = 350,
42
+ BRANDS = 'brands',
43
+ FULLVERLIST = 'fullVersionList',
44
+ PLATFORM = 'platform',
45
+ PLATFORMVER = 'platformVersion',
46
+ BITNESS = 'bitness',
47
+ CH_HEADER = 'sec-ch-ua',
48
+ CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
49
+ CH_HEADER_ARCH = CH_HEADER + '-arch',
50
+ CH_HEADER_BITNESS = CH_HEADER + '-bitness',
51
+ CH_HEADER_MOBILE = CH_HEADER + '-mobile',
52
+ CH_HEADER_MODEL = CH_HEADER + '-model',
53
+ CH_HEADER_PLATFORM = CH_HEADER + '-platform',
54
+ CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
55
+ CH_ALL_VALUES = ['brands', 'fullVersionList', MOBILE, MODEL, 'platform', 'platformVersion', ARCHITECTURE, 'bitness'],
56
+ UA_BROWSER = 'browser',
57
+ UA_CPU = 'cpu',
58
+ UA_DEVICE = 'device',
59
+ UA_ENGINE = 'engine',
60
+ UA_OS = 'os',
61
+ UA_RESULT = 'result',
62
+ AMAZON = 'Amazon',
63
+ APPLE = 'Apple',
64
+ ASUS = 'ASUS',
65
+ BLACKBERRY = 'BlackBerry',
66
+ GOOGLE = 'Google',
67
+ HUAWEI = 'Huawei',
68
+ LG = 'LG',
69
+ MICROSOFT = 'Microsoft',
70
+ MOTOROLA = 'Motorola',
71
+ SAMSUNG = 'Samsung',
72
+ SHARP = 'Sharp',
73
+ SONY = 'Sony',
74
+ XIAOMI = 'Xiaomi',
75
+ ZEBRA = 'Zebra',
76
+ PREFIX_MOBILE = 'Mobile ',
77
+ SUFFIX_BROWSER = ' Browser',
78
+ CHROME = 'Chrome',
79
+ EDGE = 'Edge',
80
+ FIREFOX = 'Firefox',
81
+ OPERA = 'Opera',
62
82
  FACEBOOK = 'Facebook',
63
- CHROMIUM_OS = 'Chromium OS',
64
- MAC_OS = 'Mac OS';
83
+ WINDOWS = 'Windows';
84
+
85
+ var NAVIGATOR = (typeof window !== UNDEF_TYPE && window.navigator) ?
86
+ window.navigator :
87
+ undefined,
88
+ NAVIGATOR_UADATA = (NAVIGATOR && NAVIGATOR.userAgentData) ?
89
+ NAVIGATOR.userAgentData :
90
+ undefined;
65
91
 
66
92
  ///////////
67
93
  // Helper
68
94
  //////////
69
95
 
70
- var extend = function (regexes, extensions) {
71
- var mergedRegexes = {};
72
- for (var i in regexes) {
73
- if (extensions[i] && extensions[i].length % 2 === 0) {
74
- mergedRegexes[i] = extensions[i].concat(regexes[i]);
96
+ var assignFromEntries = function (arr) {
97
+ for (var i in arr) {
98
+ var propName = arr[i];
99
+ if (typeof propName == OBJ_TYPE && propName.length == 2) {
100
+ this[propName[0]] = propName[1];
75
101
  } else {
76
- mergedRegexes[i] = regexes[i];
102
+ this[propName] = undefined;
77
103
  }
78
104
  }
105
+ return this;
106
+ },
107
+ extend = function (regexes, extensions) {
108
+ var mergedRegexes = {};
109
+ for (var i in regexes) {
110
+ mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
111
+ }
79
112
  return mergedRegexes;
80
113
  },
81
114
  enumerize = function (arr) {
@@ -86,17 +119,44 @@
86
119
  return enums;
87
120
  },
88
121
  has = function (str1, str2) {
122
+ if (typeof str1 === OBJ_TYPE && str1.length > 0) {
123
+ for (var i in str1) {
124
+ if (lowerize(str1[i]) == lowerize(str2)) return true;
125
+ }
126
+ return false;
127
+ }
89
128
  return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
90
129
  },
130
+ isExtensions = function (obj) {
131
+ for (var prop in obj) {
132
+ return /^(browser|cpu|device|engine|os)$/.test(prop);
133
+ }
134
+ },
135
+ itemListToArray = function (header) {
136
+ if (!header) return undefined;
137
+ var arr = [];
138
+ var tokens = strip(/\\?\"/g, header).split(', ');
139
+ for (var i = 0; i < tokens.length; i++) {
140
+ var token = tokens[i].split(';v=');
141
+ arr[i] = { brand : token[0], version : token[1] };
142
+ }
143
+ return arr;
144
+ },
91
145
  lowerize = function (str) {
92
- return str.toLowerCase();
146
+ return typeof(str) === STR_TYPE ? str.toLowerCase() : str;
93
147
  },
94
148
  majorize = function (version) {
95
- return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined;
149
+ return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
150
+ },
151
+ strip = function (pattern, str) {
152
+ return str.replace(pattern, EMPTY);
153
+ },
154
+ stripQuotes = function (val) {
155
+ return typeof val === STR_TYPE ? strip(/\"/g, val) : val;
96
156
  },
97
157
  trim = function (str, len) {
98
158
  if (typeof(str) === STR_TYPE) {
99
- str = str.replace(/^\s\s*/, EMPTY);
159
+ str = strip(/^\s\s*/, str);
100
160
  return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
101
161
  }
102
162
  };
@@ -107,6 +167,8 @@
107
167
 
108
168
  var rgxMapper = function (ua, arrays) {
109
169
 
170
+ if(!ua || !arrays) return;
171
+
110
172
  var i = 0, j, k, p, q, matches, match;
111
173
 
112
174
  // loop through all regexes maps
@@ -208,12 +270,13 @@
208
270
  // Regex map
209
271
  /////////////
210
272
 
211
- var regexes = {
273
+ var defaultRegexes = {
212
274
 
213
275
  browser : [[
214
276
 
277
+ // Most common regardless engine
215
278
  /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
216
- ], [VERSION, [NAME, 'Chrome']], [
279
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
217
280
  /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge
218
281
  ], [VERSION, [NAME, 'Edge']], [
219
282
 
@@ -237,11 +300,12 @@
237
300
 
238
301
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
239
302
  /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i,
240
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ
303
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
304
+ /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
241
305
  /(weibo)__([\d\.]+)/i // Weibo
242
306
  ], [NAME, VERSION], [
243
307
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
244
- ], [VERSION, [NAME, 'UC'+BROWSER]], [
308
+ ], [VERSION, [NAME, 'UCBrowser']], [
245
309
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
246
310
  /\bqbcore\/([\w\.]+).+microm/i
247
311
  ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
@@ -251,10 +315,10 @@
251
315
  ], [VERSION, [NAME, 'Konqueror']], [
252
316
  /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11
253
317
  ], [VERSION, [NAME, 'IE']], [
254
- /yabrowser\/([\w\.]+)/i // Yandex
318
+ /ya(?:search)?browser\/([\w\.]+)/i // Yandex
255
319
  ], [VERSION, [NAME, 'Yandex']], [
256
320
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
257
- ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [
321
+ ], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
258
322
  /\bfocus\/([\w\.]+)/i // Firefox Focus
259
323
  ], [VERSION, [NAME, FIREFOX+' Focus']], [
260
324
  /\bopt\/([\w\.]+)/i // Opera Touch
@@ -266,13 +330,13 @@
266
330
  /coast\/([\w\.]+)/i // Opera Coast
267
331
  ], [VERSION, [NAME, OPERA+' Coast']], [
268
332
  /miuibrowser\/([\w\.]+)/i // MIUI Browser
269
- ], [VERSION, [NAME, 'MIUI '+BROWSER]], [
270
- /fxios\/([-\w\.]+)/i // Firefox for iOS
271
- ], [VERSION, [NAME, FIREFOX]], [
333
+ ], [VERSION, [NAME, 'MIUI' + SUFFIX_BROWSER]], [
334
+ /fxios\/([\w\.-]+)/i // Firefox for iOS
335
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Firefox']], [
272
336
  /\bqihu|(qi?ho?o?|360)browser/i // 360
273
- ], [[NAME, '360 '+BROWSER]], [
337
+ ], [[NAME, '360' + SUFFIX_BROWSER]], [
274
338
  /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i
275
- ], [[NAME, /(.+)/, '$1 '+BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
339
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
276
340
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
277
341
  ], [[NAME, /_/g, ' '], VERSION], [
278
342
  /(electron)\/([\w\.]+) safari/i, // Electron-based App
@@ -295,6 +359,8 @@
295
359
  ], [NAME, VERSION], [
296
360
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
297
361
  ], [VERSION, [NAME, 'GSA']], [
362
+ /musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok
363
+ ], [VERSION, [NAME, 'TikTok']], [
298
364
 
299
365
  /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
300
366
  ], [VERSION, [NAME, CHROME+' Headless']], [
@@ -303,14 +369,19 @@
303
369
  ], [[NAME, CHROME+' WebView'], VERSION], [
304
370
 
305
371
  /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser
306
- ], [VERSION, [NAME, 'Android '+BROWSER]], [
372
+ ], [VERSION, [NAME, 'Android' + SUFFIX_BROWSER]], [
373
+
374
+ /chrome\/([\w\.]+) mobile/i // Chrome Mobile
375
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
307
376
 
308
377
  /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
309
378
  ], [NAME, VERSION], [
310
379
 
311
- /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i // Mobile Safari
312
- ], [VERSION, [NAME, 'Mobile Safari']], [
313
- /version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile
380
+ /version\/([\w\.\,]+) .*mobile(?:\/\w+ | ?)safari/i // Safari Mobile
381
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Safari']], [
382
+ /iphone .*mobile(?:\/\w+ | ?)safari/i
383
+ ], [[NAME, PREFIX_MOBILE + 'Safari']], [
384
+ /version\/([\w\.\,]+) .*(safari)/i // Safari
314
385
  ], [VERSION, NAME], [
315
386
  /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
316
387
  ], [NAME, [VERSION, strMapper, oldSafariMap]], [
@@ -319,6 +390,8 @@
319
390
  ], [NAME, VERSION], [
320
391
 
321
392
  // Gecko based
393
+ /(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i // Firefox Mobile
394
+ ], [[NAME, PREFIX_MOBILE + 'Firefox'], VERSION], [
322
395
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
323
396
  ], [[NAME, 'Netscape'], VERSION], [
324
397
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
@@ -340,17 +413,15 @@
340
413
  ], [NAME, VERSION], [
341
414
 
342
415
  /(cobalt)\/([\w\.]+)/i // Cobalt
343
- ], [NAME, [VERSION, /master.|lts./, ""]]
416
+ ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
344
417
  ],
345
418
 
346
419
  cpu : [[
347
420
 
348
- /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64)
421
+ /\b(?:(amd|x|x86[-_]?|wow|win)64)\b/i // AMD64 (x64)
349
422
  ], [[ARCHITECTURE, 'amd64']], [
350
423
 
351
- /(ia32(?=;))/i // IA32 (quicktime)
352
- ], [[ARCHITECTURE, lowerize]], [
353
-
424
+ /(ia32(?=;))/i, // IA32 (quicktime)
354
425
  /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
355
426
  ], [[ARCHITECTURE, 'ia32']], [
356
427
 
@@ -390,7 +461,7 @@
390
461
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
391
462
 
392
463
  // Apple
393
- /\((ip(?:hone|od)[\w ]*);/i // iPod/iPhone
464
+ /(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
394
465
  ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
395
466
  /\((ipad);[-\w\),; ]+apple/i, // iPad
396
467
  /applecoremedia\/[\w\.]+ \((ipad)/i,
@@ -480,7 +551,7 @@
480
551
 
481
552
  // Amazon
482
553
  /(alexa)webm/i,
483
- /(kf[a-z]{2}wi)( bui|\))/i, // Kindle Fire without Silk
554
+ /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i, // Kindle Fire without Silk / Echo Show
484
555
  /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD
485
556
  ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [
486
557
  /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone
@@ -532,69 +603,20 @@
532
603
  /(kobo)\s(ereader|touch)/i, // Kobo
533
604
  /(archos) (gamepad2?)/i, // Archos
534
605
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
535
- /(kindle)\/([\w\.]+)/i, // Kindle
536
- /(nook)[\w ]+build\/(\w+)/i, // Nook
537
- /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak
538
- /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets
539
- /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets
540
- /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets
541
- /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone
606
+ /(kindle)\/([\w\.]+)/i // Kindle
542
607
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
543
608
 
544
609
  /(surface duo)/i // Surface Duo
545
610
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [
546
611
  /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone
547
612
  ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [
548
- /(u304aa)/i // AT&T
549
- ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [
550
- /\bsie-(\w*)/i // Siemens
551
- ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [
552
- /\b(rct\w+) b/i // RCA Tablets
553
- ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [
554
- /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets
555
- ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [
556
- /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet
557
- ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [
558
- /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet
559
- ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [
560
- /\b(tm\d{3}\w+) b/i
561
- ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [
562
- /\b(k88) b/i // ZTE K Series Tablet
563
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [
564
- /\b(nx\d{3}j) b/i // ZTE Nubia
565
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [
566
- /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile
567
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [
568
- /\b(zur\d{3}) b/i // Swiss ZUR Tablet
569
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [
570
- /\b((zeki)?tb.*\b) b/i // Zeki Tablets
571
- ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [
572
- /\b([yr]\d{2}) b/i,
573
- /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet
574
- ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [
575
- /\b(ns-?\w{0,9}) b/i // Insignia Tablets
576
- ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [
577
- /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets
578
- ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [
579
- /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones
580
- ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [
581
- /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones
582
- ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [
583
- /\b(ph-1) /i // Essential PH-1
584
- ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [
585
- /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets
586
- ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [
587
- /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets
588
- ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [
589
- /\btu_(1491) b/i // Rotor Tablets
590
- ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [
591
613
  /(shield[\w ]+) b/i // Nvidia Shield Tablets
592
614
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [
593
615
  /(sprint) (\w+)/i // Sprint Phones
594
616
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
595
617
  /(kin\.[onetw]{3})/i // Microsoft Kin
596
618
  ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [
597
- /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
619
+ /droid.+; ([c6]+|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
598
620
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [
599
621
  /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i
600
622
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [
@@ -618,7 +640,7 @@
618
640
  /\(dtv[\);].+(aquos)/i,
619
641
  /(aquos-tv[\w ]+)\)/i // Sharp
620
642
  ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[
621
- /(bravia[\w ]+)( bui|\))/i // Sony
643
+ /(bravia[\w ]+)( bui|\))/i // Sony
622
644
  ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [
623
645
  /(mitv-\w{5}) bui/i // Xiaomi
624
646
  ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [
@@ -635,11 +657,11 @@
635
657
  ///////////////////
636
658
 
637
659
  /(ouya)/i, // Ouya
638
- /(nintendo) ([wids3utch]+)/i // Nintendo
660
+ /(nintendo) (\w+)/i // Nintendo
639
661
  ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
640
662
  /droid.+; (shield) bui/i // Nvidia
641
663
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
642
- /(playstation [345portablevi]+)/i // Playstation
664
+ /(playstation \w+)/i // Playstation
643
665
  ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
644
666
  /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
645
667
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
@@ -665,6 +687,8 @@
665
687
 
666
688
  /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla
667
689
  ], [VENDOR, [TYPE, EMBEDDED]], [
690
+ /(aeobc)\b/i // Echo Dot
691
+ ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
668
692
 
669
693
  ////////////////////
670
694
  // MIXED (GENERIC)
@@ -694,7 +718,8 @@
694
718
  /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna
695
719
  /ekioh(flow)\/([\w\.]+)/i, // Flow
696
720
  /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
697
- /(icab)[\/ ]([23]\.[\d\.]+)/i // iCab
721
+ /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
722
+ /\b(libweb)/i
698
723
  ], [NAME, VERSION], [
699
724
 
700
725
  /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko
@@ -711,15 +736,16 @@
711
736
  /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
712
737
  ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
713
738
  /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i
714
- ], [[NAME, 'Windows'], [VERSION, strMapper, windowsVersionMap]], [
739
+ ], [[NAME, WINDOWS], [VERSION, strMapper, windowsVersionMap]], [
715
740
 
716
741
  // iOS/macOS
717
742
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
743
+ /ios;fbsv\/([\d\.]+)/i,
718
744
  /cfnetwork\/.+darwin/i
719
745
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
720
746
  /(mac os x) ?([\w\. ]*)/i,
721
747
  /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
722
- ], [[NAME, MAC_OS], [VERSION, /_/g, '.']], [
748
+ ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
723
749
 
724
750
  // Mobile OSes
725
751
  /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
@@ -745,7 +771,7 @@
745
771
  /crkey\/([\d\.]+)/i // Google Chromecast
746
772
  ], [VERSION, [NAME, CHROME+'cast']], [
747
773
  /(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
748
- ], [[NAME, CHROMIUM_OS], VERSION],[
774
+ ], [[NAME, "Chrome OS"], VERSION],[
749
775
 
750
776
  // Smart TVs
751
777
  /panasonic;(viera)/i, // Panasonic Viera
@@ -753,7 +779,7 @@
753
779
  /(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
754
780
 
755
781
  // Console
756
- /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation
782
+ /(nintendo|playstation) (\w+)/i, // Nintendo/Playstation
757
783
  /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
758
784
 
759
785
  // Other
@@ -771,105 +797,307 @@
771
797
  ], [[NAME, 'Solaris'], VERSION], [
772
798
  /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
773
799
  /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
774
- /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX
800
+ /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
775
801
  /(unix) ?([\w\.]*)/i // UNIX
776
802
  ], [NAME, VERSION]
777
803
  ]
778
804
  };
779
805
 
806
+ /////////////////
807
+ // Factories
808
+ ////////////////
809
+
810
+ var defaultProps = (function () {
811
+ var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
812
+ assignFromEntries.call(props.init, [
813
+ [UA_BROWSER, [NAME, VERSION, MAJOR]],
814
+ [UA_CPU, [ARCHITECTURE]],
815
+ [UA_DEVICE, [TYPE, MODEL, VENDOR]],
816
+ [UA_ENGINE, [NAME, VERSION]],
817
+ [UA_OS, [NAME, VERSION]]
818
+ ]);
819
+ assignFromEntries.call(props.isIgnore, [
820
+ [UA_BROWSER, [VERSION, MAJOR]],
821
+ [UA_ENGINE, [VERSION]],
822
+ [UA_OS, [VERSION]]
823
+ ]);
824
+ assignFromEntries.call(props.isIgnoreRgx, [
825
+ [UA_BROWSER, / ?browser$/i],
826
+ [UA_OS, / ?os$/i]
827
+ ]);
828
+ assignFromEntries.call(props.toString, [
829
+ [UA_BROWSER, [NAME, VERSION]],
830
+ [UA_CPU, [ARCHITECTURE]],
831
+ [UA_DEVICE, [VENDOR, MODEL]],
832
+ [UA_ENGINE, [NAME, VERSION]],
833
+ [UA_OS, [NAME, VERSION]]
834
+ ]);
835
+ return props;
836
+ })();
837
+
838
+ var createUAParserData = function (itemType, ua, rgxMap, uaCH) {
839
+
840
+ var init_props = defaultProps.init[itemType],
841
+ is_ignoreProps = defaultProps.isIgnore[itemType] || 0,
842
+ is_ignoreRgx = defaultProps.isIgnoreRgx[itemType] || 0,
843
+ toString_props = defaultProps.toString[itemType] || 0;
844
+
845
+ function UAParserData () {
846
+ assignFromEntries.call(this, init_props);
847
+ }
848
+ UAParserData.prototype.withClientHints = function () {
849
+
850
+ // nodejs / non-client-hints browsers
851
+ if (!NAVIGATOR_UADATA) {
852
+ return new UAParserItem(itemType, ua, rgxMap, uaCH).parseCH().get();
853
+ }
854
+
855
+ // browsers based on chromium 85+
856
+ return NAVIGATOR_UADATA
857
+ .getHighEntropyValues(CH_ALL_VALUES)
858
+ .then(function (res) {
859
+ var JS_UACH = new UAParserDataCH(res, false);
860
+ return new UAParserItem(itemType, ua, rgxMap, JS_UACH).parseCH().get();
861
+ });
862
+ };
863
+
864
+ if (itemType != UA_RESULT) {
865
+ UAParserData.prototype.is = function (strToCheck) {
866
+ var is = false;
867
+ for (var i in this) {
868
+ if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
869
+ is = true;
870
+ if (strToCheck != UNDEF_TYPE) break;
871
+ } else if (strToCheck == UNDEF_TYPE && is) {
872
+ is = !is;
873
+ break;
874
+ }
875
+ }
876
+ return is;
877
+ };
878
+ UAParserData.prototype.toString = function () {
879
+ var str = EMPTY;
880
+ for (var i in toString_props) {
881
+ if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
882
+ str += (str ? ' ' : EMPTY) + this[toString_props[i]];
883
+ }
884
+ }
885
+ return str || UNDEF_TYPE;
886
+ };
887
+ }
888
+
889
+ if (!NAVIGATOR_UADATA) {
890
+ UAParserData.prototype.then = function (cb) {
891
+ cb(this);
892
+ return this;
893
+ };
894
+ }
895
+
896
+ return new UAParserData();
897
+ };
898
+
780
899
  /////////////////
781
900
  // Constructor
782
901
  ////////////////
783
902
 
784
- var UAParser = function (ua, extensions) {
903
+ function UAParserDataCH (uach, isHTTP_UACH) {
904
+ uach = uach || {};
905
+ assignFromEntries.call(this, CH_ALL_VALUES);
906
+ if (isHTTP_UACH) {
907
+ assignFromEntries.call(this, [
908
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
909
+ [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
910
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
911
+ [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
912
+ [MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
913
+ [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
914
+ [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
915
+ [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
916
+ [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
917
+ ]);
918
+ } else {
919
+ for (var prop in uach) {
920
+ if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
921
+ }
922
+ }
923
+ return this;
924
+ }
925
+
926
+ function UAParserItem (itemType, ua, rgxMap, uaCH) {
927
+ assignFromEntries.call(this, [
928
+ ['itemType', itemType],
929
+ ['ua', ua],
930
+ ['uaCH', uaCH],
931
+ ['rgxMap', rgxMap],
932
+ ['data', createUAParserData(itemType, ua, rgxMap, uaCH)]
933
+ ]);
934
+ this.parse();
935
+ switch(this.itemType) {
936
+ case UA_BROWSER:
937
+ // Brave-specific detection
938
+ if (NAVIGATOR && NAVIGATOR.userAgent == ua && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
939
+ this.set(NAME, 'Brave');
940
+ }
941
+ this.set(MAJOR, majorize(this.get(VERSION)));
942
+ break;
943
+ case UA_DEVICE:
944
+ if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
945
+ this.set(TYPE, MOBILE);
946
+ }
947
+ // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
948
+ if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
949
+ this.set(MODEL, 'iPad')
950
+ .set(TYPE, TABLET);
951
+ }
952
+ break;
953
+ case UA_OS:
954
+ if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM] && NAVIGATOR_UADATA[PLATFORM] != 'Unknown') {
955
+ this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
956
+ }
957
+ break;
958
+ case UA_RESULT:
959
+ var createUAParserItem = function (itemType) {
960
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get();
961
+ };
962
+ this.set('ua', ua)
963
+ .set(UA_BROWSER, createUAParserItem(UA_BROWSER))
964
+ .set(UA_CPU, createUAParserItem(UA_CPU))
965
+ .set(UA_DEVICE, createUAParserItem(UA_DEVICE))
966
+ .set(UA_ENGINE, createUAParserItem(UA_ENGINE))
967
+ .set(UA_OS, createUAParserItem(UA_OS))
968
+ .get();
969
+ }
970
+ return this;
971
+ }
972
+ UAParserItem.prototype.get = function (prop) {
973
+ if (!prop) return this.data;
974
+ return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
975
+ };
976
+ UAParserItem.prototype.parse = function () {
977
+ if (this.itemType != UA_RESULT) {
978
+ rgxMapper.call(this.data, this.ua, this.rgxMap);
979
+ }
980
+ return this;
981
+ };
982
+ UAParserItem.prototype.parseCH = function () {
983
+ var ua = this.ua,
984
+ uaCH = this.uaCH,
985
+ rgxMap = this.rgxMap;
986
+
987
+ switch (this.itemType) {
988
+ case UA_BROWSER:
989
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
990
+ if (brands) {
991
+ for (var i in brands) {
992
+ var brandName = brands[i].brand,
993
+ brandVersion = brands[i].version;
994
+ if (!/not.a.brand/i.test(brandName) || /chromi/i.test(this.get(NAME))) {
995
+ this.set(NAME, strip(GOOGLE+' ', brandName))
996
+ .set(VERSION, brandVersion)
997
+ .set(MAJOR, majorize(brandVersion));
998
+ }
999
+ }
1000
+ }
1001
+ break;
1002
+ case UA_CPU:
1003
+ var archName = uaCH[ARCHITECTURE];
1004
+ if (archName) {
1005
+ if (archName && uaCH[BITNESS] == '64') archName += '64';
1006
+ rgxMapper.call(this.data, archName + ';', rgxMap);
1007
+ }
1008
+ break;
1009
+ case UA_DEVICE:
1010
+ if (uaCH[MOBILE]) {
1011
+ this.set(TYPE, MOBILE);
1012
+ }
1013
+ if (uaCH[MODEL]) {
1014
+ this.set(MODEL, uaCH[MODEL]);
1015
+ }
1016
+ break;
1017
+ case UA_OS:
1018
+ var osName = uaCH[PLATFORM];
1019
+ if(osName) {
1020
+ var osVersion = uaCH[PLATFORMVER];
1021
+ if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
1022
+ this.set(NAME, osName)
1023
+ .set(VERSION, osVersion);
1024
+ }
1025
+ break;
1026
+ case UA_RESULT:
1027
+ var createUAParserItemWithCH = function (itemType) {
1028
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get();
1029
+ };
1030
+ this.set('ua', ua)
1031
+ .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER))
1032
+ .set(UA_CPU, createUAParserItemWithCH(UA_CPU))
1033
+ .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE))
1034
+ .set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE))
1035
+ .set(UA_OS, createUAParserItemWithCH(UA_OS));
1036
+ }
1037
+ return this;
1038
+ };
1039
+ UAParserItem.prototype.set = function (prop, val) {
1040
+ this.data[prop] = val;
1041
+ return this;
1042
+ };
1043
+
1044
+ function UAParser (ua, extensions, headers) {
785
1045
 
786
1046
  if (typeof ua === OBJ_TYPE) {
787
- extensions = ua;
1047
+ if (isExtensions(ua)) {
1048
+ if (typeof extensions === OBJ_TYPE) {
1049
+ headers = extensions; // case UAParser(extensions, headers)
1050
+ }
1051
+ extensions = ua; // case UAParser(extensions)
1052
+ } else {
1053
+ headers = ua; // case UAParser(headers)
1054
+ extensions = undefined;
1055
+ }
788
1056
  ua = undefined;
1057
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1058
+ headers = extensions; // case UAParser(ua, headers)
1059
+ extensions = undefined;
789
1060
  }
790
-
1061
+
791
1062
  if (!(this instanceof UAParser)) {
792
- return new UAParser(ua, extensions).getResult();
1063
+ return new UAParser(ua, extensions, headers).getResult();
793
1064
  }
794
1065
 
795
- var _navigator = (typeof window !== UNDEF_TYPE && window.navigator) ? window.navigator : undefined;
796
- var _ua = ua || ((_navigator && _navigator.userAgent) ? _navigator.userAgent : EMPTY);
797
- var _uach = (_navigator && _navigator.userAgentData) ? _navigator.userAgentData : undefined;
798
- var _rgxmap = extensions ? extend(regexes, extensions) : regexes;
799
-
800
- this.getBrowser = function () {
801
- var _browser = {};
802
- _browser[NAME] = undefined;
803
- _browser[VERSION] = undefined;
804
- rgxMapper.call(_browser, _ua, _rgxmap.browser);
805
- _browser[MAJOR] = majorize(_browser[VERSION]);
806
- // Brave-specific detection
807
- if (_navigator && _navigator.brave && typeof _navigator.brave.isBrave == FUNC_TYPE) {
808
- _browser[NAME] = 'Brave';
809
- }
810
- return _browser;
811
- };
812
- this.getCPU = function () {
813
- var _cpu = {};
814
- _cpu[ARCHITECTURE] = undefined;
815
- rgxMapper.call(_cpu, _ua, _rgxmap.cpu);
816
- return _cpu;
817
- };
818
- this.getDevice = function () {
819
- var _device = {};
820
- _device[VENDOR] = undefined;
821
- _device[MODEL] = undefined;
822
- _device[TYPE] = undefined;
823
- rgxMapper.call(_device, _ua, _rgxmap.device);
824
- if (!_device[TYPE] && _uach && _uach.mobile) {
825
- _device[TYPE] = MOBILE;
826
- }
827
- // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
828
- if (_device[MODEL] == 'Macintosh' && _navigator && typeof _navigator.standalone !== UNDEF_TYPE && _navigator.maxTouchPoints && _navigator.maxTouchPoints > 2) {
829
- _device[MODEL] = 'iPad';
830
- _device[TYPE] = TABLET;
831
- }
832
- return _device;
833
- };
834
- this.getEngine = function () {
835
- var _engine = {};
836
- _engine[NAME] = undefined;
837
- _engine[VERSION] = undefined;
838
- rgxMapper.call(_engine, _ua, _rgxmap.engine);
839
- return _engine;
840
- };
841
- this.getOS = function () {
842
- var _os = {};
843
- _os[NAME] = undefined;
844
- _os[VERSION] = undefined;
845
- rgxMapper.call(_os, _ua, _rgxmap.os);
846
- if (!_os[NAME] && _uach && _uach.platform != 'Unknown') {
847
- _os[NAME] = _uach.platform
848
- .replace(/chrome os/i, CHROMIUM_OS)
849
- .replace(/macos/i, MAC_OS); // backward compatibility
850
- }
851
- return _os;
852
- };
853
- this.getResult = function () {
854
- return {
855
- ua : this.getUA(),
856
- browser : this.getBrowser(),
857
- engine : this.getEngine(),
858
- os : this.getOS(),
859
- device : this.getDevice(),
860
- cpu : this.getCPU()
1066
+ var userAgent = ua ||
1067
+ ((NAVIGATOR && NAVIGATOR.userAgent) ?
1068
+ NAVIGATOR.userAgent :
1069
+ (headers && headers[USER_AGENT] ?
1070
+ headers[USER_AGENT] :
1071
+ EMPTY)),
1072
+
1073
+ HTTP_UACH = new UAParserDataCH(headers, true),
1074
+
1075
+ regexMap = extensions ?
1076
+ extend(defaultRegexes, extensions) :
1077
+ defaultRegexes,
1078
+
1079
+ createUAParserItemFunc = function (itemType) {
1080
+ return function () {
1081
+ return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).get();
1082
+ };
861
1083
  };
862
- };
863
- this.getUA = function () {
864
- return _ua;
865
- };
866
- this.setUA = function (ua) {
867
- _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
868
- return this;
869
- };
870
- this.setUA(_ua);
1084
+
1085
+ // public methods
1086
+ assignFromEntries.call(this, [
1087
+ ['getBrowser', createUAParserItemFunc(UA_BROWSER)],
1088
+ ['getCPU', createUAParserItemFunc(UA_CPU)],
1089
+ ['getDevice', createUAParserItemFunc(UA_DEVICE)],
1090
+ ['getEngine', createUAParserItemFunc(UA_ENGINE)],
1091
+ ['getOS', createUAParserItemFunc(UA_OS)],
1092
+ ['getResult', createUAParserItemFunc(UA_RESULT)],
1093
+ ['getUA', function () { return userAgent; }],
1094
+ ['setUA', function (ua) {
1095
+ userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
1096
+ return this;
1097
+ }]
1098
+ ]).setUA(userAgent);
871
1099
  return this;
872
- };
1100
+ }
873
1101
 
874
1102
  UAParser.VERSION = LIBVERSION;
875
1103
  UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);