ua-parser-js 1.0.35 → 2.0.0-alpha.2

Sign up to get free protection for your applications and to get access to all the features.
package/src/ua-parser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v1.0.35
3
- Copyright © 2012-2021 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.0-alpha.2
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.35',
20
+ var LIBVERSION = '2.0.0-alpha.2',
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
 
@@ -236,13 +299,13 @@
236
299
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
237
300
 
238
301
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
239
- /(flock|rockmelt|midori|epiphany|silk|skyfire|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
241
- /(heytap|ovi)browser\/([\d\.]+)/i, // Heytap/Ovi
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,
303
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
304
+ /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
242
305
  /(weibo)__([\d\.]+)/i // Weibo
243
306
  ], [NAME, VERSION], [
244
307
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
245
- ], [VERSION, [NAME, 'UC'+BROWSER]], [
308
+ ], [VERSION, [NAME, 'UCBrowser']], [
246
309
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
247
310
  /\bqbcore\/([\w\.]+).+microm/i
248
311
  ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
@@ -255,7 +318,7 @@
255
318
  /ya(?:search)?browser\/([\w\.]+)/i // Yandex
256
319
  ], [VERSION, [NAME, 'Yandex']], [
257
320
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
258
- ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [
321
+ ], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
259
322
  /\bfocus\/([\w\.]+)/i // Firefox Focus
260
323
  ], [VERSION, [NAME, FIREFOX+' Focus']], [
261
324
  /\bopt\/([\w\.]+)/i // Opera Touch
@@ -267,13 +330,13 @@
267
330
  /coast\/([\w\.]+)/i // Opera Coast
268
331
  ], [VERSION, [NAME, OPERA+' Coast']], [
269
332
  /miuibrowser\/([\w\.]+)/i // MIUI Browser
270
- ], [VERSION, [NAME, 'MIUI '+BROWSER]], [
271
- /fxios\/([-\w\.]+)/i // Firefox for iOS
272
- ], [VERSION, [NAME, FIREFOX]], [
333
+ ], [VERSION, [NAME, 'MIUI' + SUFFIX_BROWSER]], [
334
+ /fxios\/([\w\.-]+)/i // Firefox for iOS
335
+ ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
273
336
  /\bqihu|(qi?ho?o?|360)browser/i // 360
274
- ], [[NAME, '360 '+BROWSER]], [
337
+ ], [[NAME, '360' + SUFFIX_BROWSER]], [
275
338
  /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i
276
- ], [[NAME, /(.+)/, '$1 '+BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
339
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
277
340
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
278
341
  ], [[NAME, /_/g, ' '], VERSION], [
279
342
  /(electron)\/([\w\.]+) safari/i, // Electron-based App
@@ -306,14 +369,19 @@
306
369
  ], [[NAME, CHROME+' WebView'], VERSION], [
307
370
 
308
371
  /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser
309
- ], [VERSION, [NAME, 'Android '+BROWSER]], [
372
+ ], [VERSION, [NAME, 'Android' + SUFFIX_BROWSER]], [
373
+
374
+ /chrome\/([\w\.]+) mobile/i // Chrome Mobile
375
+ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
310
376
 
311
377
  /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
312
378
  ], [NAME, VERSION], [
313
379
 
314
- /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i // Mobile Safari
315
- ], [VERSION, [NAME, 'Mobile Safari']], [
316
- /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
317
385
  ], [VERSION, NAME], [
318
386
  /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
319
387
  ], [NAME, [VERSION, strMapper, oldSafariMap]], [
@@ -322,6 +390,8 @@
322
390
  ], [NAME, VERSION], [
323
391
 
324
392
  // Gecko based
393
+ /(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i // Firefox Mobile
394
+ ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
325
395
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
326
396
  ], [[NAME, 'Netscape'], VERSION], [
327
397
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
@@ -343,17 +413,15 @@
343
413
  ], [NAME, VERSION], [
344
414
 
345
415
  /(cobalt)\/([\w\.]+)/i // Cobalt
346
- ], [NAME, [VERSION, /master.|lts./, ""]]
416
+ ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
347
417
  ],
348
418
 
349
419
  cpu : [[
350
420
 
351
- /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64)
421
+ /\b(?:(amd|x|x86[-_]?|wow|win)64)\b/i // AMD64 (x64)
352
422
  ], [[ARCHITECTURE, 'amd64']], [
353
423
 
354
- /(ia32(?=;))/i // IA32 (quicktime)
355
- ], [[ARCHITECTURE, lowerize]], [
356
-
424
+ /(ia32(?=;))/i, // IA32 (quicktime)
357
425
  /((?:i[346]|x)86)[;\)]/i // IA32 (x86)
358
426
  ], [[ARCHITECTURE, 'ia32']], [
359
427
 
@@ -535,69 +603,20 @@
535
603
  /(kobo)\s(ereader|touch)/i, // Kobo
536
604
  /(archos) (gamepad2?)/i, // Archos
537
605
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
538
- /(kindle)\/([\w\.]+)/i, // Kindle
539
- /(nook)[\w ]+build\/(\w+)/i, // Nook
540
- /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak
541
- /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets
542
- /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets
543
- /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets
544
- /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone
606
+ /(kindle)\/([\w\.]+)/i // Kindle
545
607
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
546
608
 
547
609
  /(surface duo)/i // Surface Duo
548
610
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [
549
611
  /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone
550
612
  ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [
551
- /(u304aa)/i // AT&T
552
- ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [
553
- /\bsie-(\w*)/i // Siemens
554
- ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [
555
- /\b(rct\w+) b/i // RCA Tablets
556
- ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [
557
- /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets
558
- ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [
559
- /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet
560
- ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [
561
- /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet
562
- ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [
563
- /\b(tm\d{3}\w+) b/i
564
- ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [
565
- /\b(k88) b/i // ZTE K Series Tablet
566
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [
567
- /\b(nx\d{3}j) b/i // ZTE Nubia
568
- ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [
569
- /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile
570
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [
571
- /\b(zur\d{3}) b/i // Swiss ZUR Tablet
572
- ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [
573
- /\b((zeki)?tb.*\b) b/i // Zeki Tablets
574
- ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [
575
- /\b([yr]\d{2}) b/i,
576
- /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet
577
- ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [
578
- /\b(ns-?\w{0,9}) b/i // Insignia Tablets
579
- ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [
580
- /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets
581
- ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [
582
- /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones
583
- ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [
584
- /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones
585
- ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [
586
- /\b(ph-1) /i // Essential PH-1
587
- ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [
588
- /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets
589
- ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [
590
- /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets
591
- ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [
592
- /\btu_(1491) b/i // Rotor Tablets
593
- ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [
594
613
  /(shield[\w ]+) b/i // Nvidia Shield Tablets
595
614
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [
596
615
  /(sprint) (\w+)/i // Sprint Phones
597
616
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
598
617
  /(kin\.[onetw]{3})/i // Microsoft Kin
599
618
  ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [
600
- /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
601
620
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [
602
621
  /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i
603
622
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [
@@ -621,7 +640,7 @@
621
640
  /\(dtv[\);].+(aquos)/i,
622
641
  /(aquos-tv[\w ]+)\)/i // Sharp
623
642
  ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[
624
- /(bravia[\w ]+)( bui|\))/i // Sony
643
+ /(bravia[\w ]+)( bui|\))/i // Sony
625
644
  ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [
626
645
  /(mitv-\w{5}) bui/i // Xiaomi
627
646
  ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [
@@ -638,11 +657,11 @@
638
657
  ///////////////////
639
658
 
640
659
  /(ouya)/i, // Ouya
641
- /(nintendo) ([wids3utch]+)/i // Nintendo
660
+ /(nintendo) (\w+)/i // Nintendo
642
661
  ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
643
662
  /droid.+; (shield) bui/i // Nvidia
644
663
  ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
645
- /(playstation [345portablevi]+)/i // Playstation
664
+ /(playstation \w+)/i // Playstation
646
665
  ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
647
666
  /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
648
667
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
@@ -717,7 +736,7 @@
717
736
  /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
718
737
  ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
719
738
  /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i
720
- ], [[NAME, 'Windows'], [VERSION, strMapper, windowsVersionMap]], [
739
+ ], [[NAME, WINDOWS], [VERSION, strMapper, windowsVersionMap]], [
721
740
 
722
741
  // iOS/macOS
723
742
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
@@ -726,7 +745,7 @@
726
745
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
727
746
  /(mac os x) ?([\w\. ]*)/i,
728
747
  /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
729
- ], [[NAME, MAC_OS], [VERSION, /_/g, '.']], [
748
+ ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
730
749
 
731
750
  // Mobile OSes
732
751
  /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
@@ -752,7 +771,7 @@
752
771
  /crkey\/([\d\.]+)/i // Google Chromecast
753
772
  ], [VERSION, [NAME, CHROME+'cast']], [
754
773
  /(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
755
- ], [[NAME, CHROMIUM_OS], VERSION],[
774
+ ], [[NAME, "Chrome OS"], VERSION],[
756
775
 
757
776
  // Smart TVs
758
777
  /panasonic;(viera)/i, // Panasonic Viera
@@ -760,7 +779,7 @@
760
779
  /(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
761
780
 
762
781
  // Console
763
- /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation
782
+ /(nintendo|playstation) (\w+)/i, // Nintendo/Playstation
764
783
  /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
765
784
 
766
785
  // Other
@@ -784,100 +803,315 @@
784
803
  ]
785
804
  };
786
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
+ var that = this;
892
+ var UAParserDataResolve = function () {
893
+ for (var prop in that) {
894
+ if (that.hasOwnProperty(prop)) {
895
+ this[prop] = that[prop];
896
+ }
897
+ }
898
+ };
899
+ UAParserDataResolve.prototype = {
900
+ is : UAParserData.prototype.is,
901
+ toString : UAParserData.prototype.toString
902
+ };
903
+ var resolveData = new UAParserDataResolve();
904
+ cb(resolveData);
905
+ return resolveData;
906
+ };
907
+ }
908
+
909
+ return new UAParserData();
910
+ };
911
+
787
912
  /////////////////
788
913
  // Constructor
789
914
  ////////////////
790
915
 
791
- var UAParser = function (ua, extensions) {
916
+ function UAParserDataCH (uach, isHTTP_UACH) {
917
+ uach = uach || {};
918
+ assignFromEntries.call(this, CH_ALL_VALUES);
919
+ if (isHTTP_UACH) {
920
+ assignFromEntries.call(this, [
921
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
922
+ [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
923
+ [BRANDS, itemListToArray(uach[CH_HEADER])],
924
+ [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
925
+ [MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
926
+ [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
927
+ [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
928
+ [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
929
+ [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
930
+ ]);
931
+ } else {
932
+ for (var prop in uach) {
933
+ if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
934
+ }
935
+ }
936
+ return this;
937
+ }
938
+
939
+ function UAParserItem (itemType, ua, rgxMap, uaCH) {
940
+ assignFromEntries.call(this, [
941
+ ['itemType', itemType],
942
+ ['ua', ua],
943
+ ['uaCH', uaCH],
944
+ ['rgxMap', rgxMap],
945
+ ['data', createUAParserData(itemType, ua, rgxMap, uaCH)]
946
+ ]);
947
+ this.parse();
948
+ var isSelfNav = NAVIGATOR && NAVIGATOR.userAgent == ua;
949
+ switch(this.itemType) {
950
+ case UA_BROWSER:
951
+ // Brave-specific detection
952
+ if (isSelfNav && NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
953
+ this.set(NAME, 'Brave');
954
+ }
955
+ this.set(MAJOR, majorize(this.get(VERSION)));
956
+ break;
957
+ case UA_DEVICE:
958
+ if (isSelfNav && !this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
959
+ this.set(TYPE, MOBILE);
960
+ }
961
+ // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
962
+ if (isSelfNav && this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
963
+ this.set(MODEL, 'iPad')
964
+ .set(TYPE, TABLET);
965
+ }
966
+ break;
967
+ case UA_OS:
968
+ if (isSelfNav && !this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
969
+ this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
970
+ }
971
+ break;
972
+ case UA_RESULT:
973
+ var createUAParserItem = function (itemType) {
974
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get();
975
+ };
976
+ this.set('ua', ua)
977
+ .set(UA_BROWSER, createUAParserItem(UA_BROWSER))
978
+ .set(UA_CPU, createUAParserItem(UA_CPU))
979
+ .set(UA_DEVICE, createUAParserItem(UA_DEVICE))
980
+ .set(UA_ENGINE, createUAParserItem(UA_ENGINE))
981
+ .set(UA_OS, createUAParserItem(UA_OS))
982
+ .get();
983
+ }
984
+ return this;
985
+ }
986
+ UAParserItem.prototype.get = function (prop) {
987
+ if (!prop) return this.data;
988
+ return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
989
+ };
990
+ UAParserItem.prototype.parse = function () {
991
+ if (this.itemType != UA_RESULT) {
992
+ rgxMapper.call(this.data, this.ua, this.rgxMap);
993
+ }
994
+ return this;
995
+ };
996
+ UAParserItem.prototype.parseCH = function () {
997
+ var ua = this.ua,
998
+ uaCH = this.uaCH,
999
+ rgxMap = this.rgxMap;
1000
+
1001
+ switch (this.itemType) {
1002
+ case UA_BROWSER:
1003
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
1004
+ if (brands) {
1005
+ for (var i in brands) {
1006
+ var brandName = brands[i].brand,
1007
+ brandVersion = brands[i].version;
1008
+ if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
1009
+ this.set(NAME, strip(GOOGLE+' ', brandName))
1010
+ .set(VERSION, brandVersion)
1011
+ .set(MAJOR, majorize(brandVersion));
1012
+ }
1013
+ }
1014
+ }
1015
+ break;
1016
+ case UA_CPU:
1017
+ var archName = uaCH[ARCHITECTURE];
1018
+ if (archName) {
1019
+ if (archName && uaCH[BITNESS] == '64') archName += '64';
1020
+ rgxMapper.call(this.data, archName + ';', rgxMap);
1021
+ }
1022
+ break;
1023
+ case UA_DEVICE:
1024
+ if (uaCH[MOBILE]) {
1025
+ this.set(TYPE, MOBILE);
1026
+ }
1027
+ if (uaCH[MODEL]) {
1028
+ this.set(MODEL, uaCH[MODEL]);
1029
+ }
1030
+ break;
1031
+ case UA_OS:
1032
+ var osName = uaCH[PLATFORM];
1033
+ if(osName) {
1034
+ var osVersion = uaCH[PLATFORMVER];
1035
+ if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
1036
+ this.set(NAME, osName)
1037
+ .set(VERSION, osVersion);
1038
+ }
1039
+ break;
1040
+ case UA_RESULT:
1041
+ var createUAParserItemWithCH = function (itemType) {
1042
+ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get();
1043
+ };
1044
+ this.set('ua', ua)
1045
+ .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER))
1046
+ .set(UA_CPU, createUAParserItemWithCH(UA_CPU))
1047
+ .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE))
1048
+ .set(UA_ENGINE, createUAParserItemWithCH(UA_ENGINE))
1049
+ .set(UA_OS, createUAParserItemWithCH(UA_OS));
1050
+ }
1051
+ return this;
1052
+ };
1053
+ UAParserItem.prototype.set = function (prop, val) {
1054
+ this.data[prop] = val;
1055
+ return this;
1056
+ };
1057
+
1058
+ function UAParser (ua, extensions, headers) {
792
1059
 
793
1060
  if (typeof ua === OBJ_TYPE) {
794
- extensions = ua;
1061
+ if (isExtensions(ua)) {
1062
+ if (typeof extensions === OBJ_TYPE) {
1063
+ headers = extensions; // case UAParser(extensions, headers)
1064
+ }
1065
+ extensions = ua; // case UAParser(extensions)
1066
+ } else {
1067
+ headers = ua; // case UAParser(headers)
1068
+ extensions = undefined;
1069
+ }
795
1070
  ua = undefined;
1071
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1072
+ headers = extensions; // case UAParser(ua, headers)
1073
+ extensions = undefined;
796
1074
  }
797
-
1075
+
798
1076
  if (!(this instanceof UAParser)) {
799
- return new UAParser(ua, extensions).getResult();
1077
+ return new UAParser(ua, extensions, headers).getResult();
800
1078
  }
801
1079
 
802
- var _navigator = (typeof window !== UNDEF_TYPE && window.navigator) ? window.navigator : undefined;
803
- var _ua = ua || ((_navigator && _navigator.userAgent) ? _navigator.userAgent : EMPTY);
804
- var _uach = (_navigator && _navigator.userAgentData) ? _navigator.userAgentData : undefined;
805
- var _rgxmap = extensions ? extend(regexes, extensions) : regexes;
806
- var _isSelfNav = _navigator && _navigator.userAgent == _ua;
807
-
808
- this.getBrowser = function () {
809
- var _browser = {};
810
- _browser[NAME] = undefined;
811
- _browser[VERSION] = undefined;
812
- rgxMapper.call(_browser, _ua, _rgxmap.browser);
813
- _browser[MAJOR] = majorize(_browser[VERSION]);
814
- // Brave-specific detection
815
- if (_isSelfNav && _navigator && _navigator.brave && typeof _navigator.brave.isBrave == FUNC_TYPE) {
816
- _browser[NAME] = 'Brave';
817
- }
818
- return _browser;
819
- };
820
- this.getCPU = function () {
821
- var _cpu = {};
822
- _cpu[ARCHITECTURE] = undefined;
823
- rgxMapper.call(_cpu, _ua, _rgxmap.cpu);
824
- return _cpu;
825
- };
826
- this.getDevice = function () {
827
- var _device = {};
828
- _device[VENDOR] = undefined;
829
- _device[MODEL] = undefined;
830
- _device[TYPE] = undefined;
831
- rgxMapper.call(_device, _ua, _rgxmap.device);
832
- if (_isSelfNav && !_device[TYPE] && _uach && _uach.mobile) {
833
- _device[TYPE] = MOBILE;
834
- }
835
- // iPadOS-specific detection: identified as Mac, but has some iOS-only properties
836
- if (_isSelfNav && _device[MODEL] == 'Macintosh' && _navigator && typeof _navigator.standalone !== UNDEF_TYPE && _navigator.maxTouchPoints && _navigator.maxTouchPoints > 2) {
837
- _device[MODEL] = 'iPad';
838
- _device[TYPE] = TABLET;
839
- }
840
- return _device;
841
- };
842
- this.getEngine = function () {
843
- var _engine = {};
844
- _engine[NAME] = undefined;
845
- _engine[VERSION] = undefined;
846
- rgxMapper.call(_engine, _ua, _rgxmap.engine);
847
- return _engine;
848
- };
849
- this.getOS = function () {
850
- var _os = {};
851
- _os[NAME] = undefined;
852
- _os[VERSION] = undefined;
853
- rgxMapper.call(_os, _ua, _rgxmap.os);
854
- if (_isSelfNav && !_os[NAME] && _uach && _uach.platform != 'Unknown') {
855
- _os[NAME] = _uach.platform
856
- .replace(/chrome os/i, CHROMIUM_OS)
857
- .replace(/macos/i, MAC_OS); // backward compatibility
858
- }
859
- return _os;
860
- };
861
- this.getResult = function () {
862
- return {
863
- ua : this.getUA(),
864
- browser : this.getBrowser(),
865
- engine : this.getEngine(),
866
- os : this.getOS(),
867
- device : this.getDevice(),
868
- cpu : this.getCPU()
1080
+ var userAgent = ua ||
1081
+ ((NAVIGATOR && NAVIGATOR.userAgent) ?
1082
+ NAVIGATOR.userAgent :
1083
+ (headers && headers[USER_AGENT] ?
1084
+ headers[USER_AGENT] :
1085
+ EMPTY)),
1086
+
1087
+ HTTP_UACH = new UAParserDataCH(headers, true),
1088
+
1089
+ regexMap = extensions ?
1090
+ extend(defaultRegexes, extensions) :
1091
+ defaultRegexes,
1092
+
1093
+ createUAParserItemFunc = function (itemType) {
1094
+ return function () {
1095
+ return new UAParserItem(itemType, userAgent, itemType == UA_RESULT ? regexMap : regexMap[itemType], HTTP_UACH).get();
1096
+ };
869
1097
  };
870
- };
871
- this.getUA = function () {
872
- return _ua;
873
- };
874
- this.setUA = function (ua) {
875
- _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
876
- return this;
877
- };
878
- this.setUA(_ua);
1098
+
1099
+ // public methods
1100
+ assignFromEntries.call(this, [
1101
+ ['getBrowser', createUAParserItemFunc(UA_BROWSER)],
1102
+ ['getCPU', createUAParserItemFunc(UA_CPU)],
1103
+ ['getDevice', createUAParserItemFunc(UA_DEVICE)],
1104
+ ['getEngine', createUAParserItemFunc(UA_ENGINE)],
1105
+ ['getOS', createUAParserItemFunc(UA_OS)],
1106
+ ['getResult', createUAParserItemFunc(UA_RESULT)],
1107
+ ['getUA', function () { return userAgent; }],
1108
+ ['setUA', function (ua) {
1109
+ userAgent = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;
1110
+ return this;
1111
+ }]
1112
+ ]).setUA(userAgent);
879
1113
  return this;
880
- };
1114
+ }
881
1115
 
882
1116
  UAParser.VERSION = LIBVERSION;
883
1117
  UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);