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

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.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]);