ua-parser-js 2.0.0-beta.1 → 2.0.0-beta.3

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.
@@ -3,8 +3,8 @@
3
3
  // Source: /src/main/ua-parser.js
4
4
 
5
5
  /////////////////////////////////////////////////////////////////////////////////
6
- /* UAParser.js v2.0.0-beta.1
7
- Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
6
+ /* UAParser.js v2.0.0-beta.3
7
+ Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
8
8
  AGPLv3 License *//*
9
9
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
10
10
  Supports browser & node.js environment.
@@ -21,8 +21,7 @@
21
21
  // Constants
22
22
  /////////////
23
23
 
24
-
25
- var LIBVERSION = '2.0.0-beta.1',
24
+ var LIBVERSION = '2.0.0-beta.3',
26
25
  EMPTY = '',
27
26
  UNKNOWN = '?',
28
27
  FUNC_TYPE = 'function',
@@ -41,11 +40,12 @@
41
40
  TABLET = 'tablet',
42
41
  SMARTTV = 'smarttv',
43
42
  WEARABLE = 'wearable',
43
+ XR = 'xr',
44
44
  EMBEDDED = 'embedded',
45
45
  USER_AGENT = 'user-agent',
46
- UA_MAX_LENGTH = 350,
46
+ UA_MAX_LENGTH = 500,
47
47
  BRANDS = 'brands',
48
- FORMFACTOR = 'formFactor',
48
+ FORMFACTORS = 'formFactors',
49
49
  FULLVERLIST = 'fullVersionList',
50
50
  PLATFORM = 'platform',
51
51
  PLATFORMVER = 'platformVersion',
@@ -54,12 +54,12 @@
54
54
  CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
55
55
  CH_HEADER_ARCH = CH_HEADER + '-arch',
56
56
  CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
57
- CH_HEADER_FORM_FACTOR = CH_HEADER + '-form-factor',
57
+ CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
58
58
  CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
59
59
  CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
60
60
  CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
61
61
  CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
62
- CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTOR, BITNESS],
62
+ CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
63
63
  UA_BROWSER = 'browser',
64
64
  UA_CPU = 'cpu',
65
65
  UA_DEVICE = 'device',
@@ -72,6 +72,7 @@
72
72
  BLACKBERRY = 'BlackBerry',
73
73
  GOOGLE = 'Google',
74
74
  HUAWEI = 'Huawei',
75
+ LENOVO = 'Lenovo',
75
76
  LG = 'LG',
76
77
  MICROSOFT = 'Microsoft',
77
78
  MOTOROLA = 'Motorola',
@@ -87,9 +88,11 @@
87
88
  FIREFOX = 'Firefox',
88
89
  OPERA = 'Opera',
89
90
  FACEBOOK = 'Facebook',
91
+ SOGOU = 'Sogou',
90
92
  WINDOWS = 'Windows';
91
93
 
92
- var NAVIGATOR = (typeof window !== UNDEF_TYPE && window.navigator) ?
94
+ var isWindow = typeof window !== UNDEF_TYPE,
95
+ NAVIGATOR = (isWindow && window.navigator) ?
93
96
  window.navigator :
94
97
  undefined,
95
98
  NAVIGATOR_UADATA = (NAVIGATOR && NAVIGATOR.userAgentData) ?
@@ -100,12 +103,21 @@
100
103
  // Helper
101
104
  //////////
102
105
 
103
- var extend = function (regexes, extensions) {
104
- var mergedRegexes = {};
105
- for (var i in regexes) {
106
- mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i];
106
+ var extend = function (defaultRgx, extensions) {
107
+ var mergedRgx = {};
108
+ var extraRgx = extensions;
109
+ if (!isExtensions(extensions)) {
110
+ extraRgx = {};
111
+ for (var i in extensions) {
112
+ for (var j in extensions[i]) {
113
+ extraRgx[j] = extensions[i][j].concat(extraRgx[j] ? extraRgx[j] : []);
114
+ }
115
+ }
116
+ }
117
+ for (var k in defaultRgx) {
118
+ mergedRgx[k] = extraRgx[k] && extraRgx[k].length % 2 === 0 ? extraRgx[k].concat(defaultRgx[k]) : defaultRgx[k];
107
119
  }
108
- return mergedRegexes;
120
+ return mergedRgx;
109
121
  },
110
122
  enumerize = function (arr) {
111
123
  var enums = {};
@@ -121,13 +133,16 @@
121
133
  }
122
134
  return false;
123
135
  }
124
- return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
136
+ return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
125
137
  },
126
- isExtensions = function (obj) {
138
+ isExtensions = function (obj, deep) {
127
139
  for (var prop in obj) {
128
- return /^(browser|cpu|device|engine|os)$/.test(prop);
140
+ return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false);
129
141
  }
130
142
  },
143
+ isString = function (val) {
144
+ return typeof val === STR_TYPE;
145
+ },
131
146
  itemListToArray = function (header) {
132
147
  if (!header) return undefined;
133
148
  var arr = [];
@@ -137,16 +152,16 @@
137
152
  var token = trim(tokens[i]).split(';v=');
138
153
  arr[i] = { brand : token[0], version : token[1] };
139
154
  } else {
140
- arr[i] = tokens[i];
155
+ arr[i] = trim(tokens[i]);
141
156
  }
142
157
  }
143
158
  return arr;
144
159
  },
145
160
  lowerize = function (str) {
146
- return typeof(str) === STR_TYPE ? str.toLowerCase() : str;
161
+ return isString(str) ? str.toLowerCase() : str;
147
162
  },
148
163
  majorize = function (version) {
149
- return typeof(version) === STR_TYPE ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
164
+ return isString(version) ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
150
165
  },
151
166
  setProps = function (arr) {
152
167
  for (var i in arr) {
@@ -160,15 +175,15 @@
160
175
  return this;
161
176
  },
162
177
  strip = function (pattern, str) {
163
- return str.replace(pattern, EMPTY);
178
+ return isString(str) ? str.replace(pattern, EMPTY) : str;
164
179
  },
165
- stripQuotes = function (val) {
166
- return typeof val === STR_TYPE ? strip(/\\?\"/g, val) : val;
180
+ stripQuotes = function (str) {
181
+ return strip(/\\?\"/g, str);
167
182
  },
168
183
  trim = function (str, len) {
169
- if (typeof(str) === STR_TYPE) {
184
+ if (isString(str)) {
170
185
  str = strip(/^\s\s*/, str);
171
- return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
186
+ return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
172
187
  }
173
188
  };
174
189
 
@@ -266,12 +281,13 @@
266
281
  'RT' : 'ARM'
267
282
  },
268
283
 
269
- formFactorMap = {
284
+ formFactorsMap = {
270
285
  'embedded' : 'Automotive',
271
286
  'mobile' : 'Mobile',
272
287
  'tablet' : ['Tablet', 'EInk'],
273
288
  'smarttv' : 'TV',
274
- 'wearable' : ['VR', 'XR', 'Watch'],
289
+ 'wearable' : 'Watch',
290
+ 'xr' : ['VR', 'XR'],
275
291
  '?' : ['Desktop', 'Unknown'],
276
292
  '*' : undefined
277
293
  };
@@ -297,28 +313,33 @@
297
313
  ], [NAME, VERSION], [
298
314
  /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0
299
315
  ], [VERSION, [NAME, OPERA+' Mini']], [
316
+ /\bop(?:rg)?x\/([\w\.]+)/i // Opera GX
317
+ ], [VERSION, [NAME, OPERA+' GX']], [
300
318
  /\bopr\/([\w\.]+)/i // Opera Webkit
301
319
  ], [VERSION, [NAME, OPERA]], [
302
320
 
303
321
  // Mixed
322
+ /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
323
+ ], [VERSION, [NAME, 'Baidu']], [
304
324
  /(kindle)\/([\w\.]+)/i, // Kindle
305
- /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer
325
+ /(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i,
326
+ // Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir
306
327
  // Trident based
307
- /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
308
- /(ba?idubrowser)[\/ ]?([\w\.]+)/i, // Baidu Browser
328
+ /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
309
329
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
310
330
 
311
331
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
312
- /(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,
313
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
332
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar)\/([-\w\.]+)/i,
333
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar
314
334
  /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
315
335
  /(weibo)__([\d\.]+)/i // Weibo
316
336
  ], [NAME, VERSION], [
337
+ /\bddg\/([\w\.]+)/i // DuckDuckGo
338
+ ], [VERSION, [NAME, 'DuckDuckGo']], [
317
339
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
318
340
  ], [VERSION, [NAME, 'UCBrowser']], [
319
341
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
320
- /\bqbcore\/([\w\.]+).+microm/i
321
- ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [
342
+ /\bqbcore\/([\w\.]+).+microm/i,
322
343
  /micromessenger\/([\w\.]+)/i // WeChat
323
344
  ], [VERSION, [NAME, 'WeChat']], [
324
345
  /konqueror\/([\w\.]+)/i // Konqueror
@@ -327,6 +348,8 @@
327
348
  ], [VERSION, [NAME, 'IE']], [
328
349
  /ya(?:search)?browser\/([\w\.]+)/i // Yandex
329
350
  ], [VERSION, [NAME, 'Yandex']], [
351
+ /slbrowser\/([\w\.]+)/i // Smart Lenovo Browser
352
+ ], [VERSION, [NAME, 'Smart ' + LENOVO + SUFFIX_BROWSER]], [
330
353
  /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
331
354
  ], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
332
355
  /\bfocus\/([\w\.]+)/i // Firefox Focus
@@ -345,26 +368,36 @@
345
368
  ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
346
369
  /\bqihu|(qi?ho?o?|360)browser/i // 360
347
370
  ], [[NAME, '360' + SUFFIX_BROWSER]], [
348
- /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i
349
- ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser
371
+ /\b(qq)\/([\w\.]+)/i // QQ
372
+ ], [[NAME, /(.+)/, '$1Browser'], VERSION], [
373
+ /(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i
374
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser
375
+ /samsungbrowser\/([\w\.]+)/i // Samsung Internet
376
+ ], [VERSION, [NAME, SAMSUNG + ' Internet']], [
350
377
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
351
378
  ], [[NAME, /_/g, ' '], VERSION], [
379
+ /metasr[\/ ]?([\d\.]+)/i // Sogou Explorer
380
+ ], [VERSION, [NAME, SOGOU + ' Explorer']], [
381
+ /(sogou)mo\w+\/([\d\.]+)/i // Sogou Mobile
382
+ ], [[NAME, SOGOU + ' Mobile'], VERSION], [
352
383
  /(electron)\/([\w\.]+) safari/i, // Electron-based App
353
384
  /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
354
- /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/Baidu App/2345 Browser
385
+ /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser
355
386
  ], [NAME, VERSION], [
356
- /(metasr)[\/ ]?([\w\.]+)/i, // SouGouBrowser
357
- /(lbbrowser)/i, // LieBao Browser
387
+ /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq
358
388
  /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
359
389
  ], [NAME], [
360
390
 
361
391
  // WebView
362
392
  /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
363
393
  ], [[NAME, FACEBOOK], VERSION], [
394
+ /(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android
364
395
  /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
365
396
  /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
366
397
  /safari (line)\/([\w\.]+)/i, // Line App for iOS
367
398
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
399
+ /(alipay)client\/([\w\.]+)/i, // Alipay
400
+ /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
368
401
  /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
369
402
  ], [NAME, VERSION], [
370
403
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
@@ -404,23 +437,24 @@
404
437
  ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
405
438
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
406
439
  ], [[NAME, 'Netscape'], VERSION], [
440
+ /(wolvic)\/([\w\.]+)/i // Wolvic
441
+ ], [NAME, VERSION], [
407
442
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
408
443
  ], [VERSION, [NAME, FIREFOX+' Reality']], [
409
444
  /ekiohf.+(flow)\/([\w\.]+)/i, // Flow
410
445
  /(swiftfox)/i, // Swiftfox
411
- /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i,
412
- // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar
446
+ /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
447
+ // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
413
448
  /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
414
449
  // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
415
450
  /(firefox)\/([\w\.]+)/i, // Other Firefox-based
416
451
  /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
417
452
 
418
453
  // Other
419
- /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
420
- // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser
421
- /(links) \(([\w\.]+)/i, // Links
422
- /panasonic;(viera)/i // Panasonic Viera
423
- ], [NAME, VERSION], [
454
+ /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
455
+ // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser
456
+ /(links) \(([\w\.]+)/i // Links
457
+ ], [NAME, [VERSION, /_/g, '.']], [
424
458
 
425
459
  /(cobalt)\/([\w\.]+)/i // Cobalt
426
460
  ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
@@ -496,7 +530,7 @@
496
530
  /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
497
531
  /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
498
532
  /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
499
- /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|\))/i, // Xiaomi Redmi 'numeric' models
533
+ /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
500
534
  /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi
501
535
  ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
502
536
  /oid[^\)]+; (2\d{4}(283|rpbf)[cgl])( bui|\))/i, // Redmi Pad
@@ -507,6 +541,8 @@
507
541
  /; (\w+) bui.+ oppo/i,
508
542
  /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
509
543
  ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
544
+ /\b(opd2\d{3}a?) bui/i
545
+ ], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [
510
546
 
511
547
  // Vivo
512
548
  /vivo (\w+)(?: bui|\))/i,
@@ -536,7 +572,7 @@
536
572
  // Lenovo
537
573
  /(ideatab[-\w ]+)/i,
538
574
  /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i
539
- ], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [
575
+ ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
540
576
 
541
577
  // Nokia
542
578
  /(?:maemo|nokia).*(n900|lumia \d+)/i,
@@ -690,12 +726,17 @@
690
726
  ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
691
727
  /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
692
728
  ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
693
- /droid.+; (glass) \d/i // Google Glass
694
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
695
729
  /droid.+; (wt63?0{2,3})\)/i
696
730
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
697
- /(quest( 2| pro)?)/i // Oculus Quest
698
- ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [
731
+
732
+ ///////////////////
733
+ // XR
734
+ ///////////////////
735
+
736
+ /droid.+; (glass) \d/i // Google Glass
737
+ ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
738
+ /(quest( \d| pro)?)/i // Oculus Quest
739
+ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
699
740
 
700
741
  ///////////////////
701
742
  // EMBEDDED
@@ -710,7 +751,7 @@
710
751
  // MIXED (GENERIC)
711
752
  ///////////////////
712
753
 
713
- /droid .+?; ([^;]+?)(?: bui|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors
754
+ /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors
714
755
  ], [MODEL, [TYPE, MOBILE]], [
715
756
  /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors
716
757
  ], [MODEL, [TYPE, TABLET]], [
@@ -747,12 +788,12 @@
747
788
  // Windows
748
789
  /microsoft (windows) (vista|xp)/i // Windows (iTunes)
749
790
  ], [NAME, VERSION], [
750
- /(windows) nt 6\.2; (arm)/i, // Windows RT
751
- /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, // Windows Phone
752
- /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i
791
+ /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i // Windows Phone
753
792
  ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
754
- /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i
755
- ], [[NAME, WINDOWS], [VERSION, strMapper, windowsVersionMap]], [
793
+ /windows nt 6\.2; (arm)/i, // Windows RT
794
+ /windows[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i,
795
+ /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
796
+ ], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [
756
797
 
757
798
  // iOS/macOS
758
799
  /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
@@ -826,7 +867,7 @@
826
867
  var defaultProps = (function () {
827
868
  var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
828
869
  setProps.call(props.init, [
829
- [UA_BROWSER, [NAME, VERSION, MAJOR]],
870
+ [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
830
871
  [UA_CPU, [ARCHITECTURE]],
831
872
  [UA_DEVICE, [TYPE, MODEL, VENDOR]],
832
873
  [UA_ENGINE, [NAME, VERSION]],
@@ -954,7 +995,7 @@
954
995
  [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
955
996
  [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
956
997
  [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
957
- [FORMFACTOR, itemListToArray(uach[CH_HEADER_FORM_FACTOR])],
998
+ [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
958
999
  [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
959
1000
  ]);
960
1001
  } else {
@@ -1041,15 +1082,16 @@
1041
1082
 
1042
1083
  switch (this.itemType) {
1043
1084
  case UA_BROWSER:
1044
- var brands = uaCH[FULLVERLIST] || uaCH[BRANDS];
1085
+ var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
1045
1086
  if (brands) {
1046
1087
  for (var i in brands) {
1047
- var brandName = brands[i].brand,
1088
+ var brandName = strip(/(Google|Microsoft) /, brands[i].brand || brands[i]),
1048
1089
  brandVersion = brands[i].version;
1049
- if (!/not.a.brand/i.test(brandName) && (i < 1 || /chromi/i.test(this.get(NAME)))) {
1050
- this.set(NAME, strip(GOOGLE+' ', brandName))
1090
+ if (!/not.a.brand/i.test(brandName) && (!prevName || (/chrom/i.test(prevName) && !/chromi/i.test(brandName)))) {
1091
+ this.set(NAME, brandName)
1051
1092
  .set(VERSION, brandVersion)
1052
1093
  .set(MAJOR, majorize(brandVersion));
1094
+ prevName = brandName;
1053
1095
  }
1054
1096
  }
1055
1097
  }
@@ -1068,15 +1110,20 @@
1068
1110
  if (uaCH[MODEL]) {
1069
1111
  this.set(MODEL, uaCH[MODEL]);
1070
1112
  }
1071
- if (uaCH[FORMFACTOR]) {
1113
+ // Xbox-Specific Detection
1114
+ if (uaCH[MODEL] == 'Xbox') {
1115
+ this.set(TYPE, CONSOLE)
1116
+ .set(VENDOR, MICROSOFT);
1117
+ }
1118
+ if (uaCH[FORMFACTORS]) {
1072
1119
  var ff;
1073
- if (typeof uaCH[FORMFACTOR] !== 'string') {
1120
+ if (typeof uaCH[FORMFACTORS] !== 'string') {
1074
1121
  var idx = 0;
1075
- while (!ff && idx < uaCH[FORMFACTOR].length) {
1076
- ff = strMapper(uaCH[FORMFACTOR][idx++], formFactorMap);
1122
+ while (!ff && idx < uaCH[FORMFACTORS].length) {
1123
+ ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
1077
1124
  }
1078
1125
  } else {
1079
- ff = strMapper(uaCH[FORMFACTOR], formFactorMap);
1126
+ ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
1080
1127
  }
1081
1128
  this.set(TYPE, ff);
1082
1129
  }
@@ -1089,6 +1136,11 @@
1089
1136
  this.set(NAME, osName)
1090
1137
  .set(VERSION, osVersion);
1091
1138
  }
1139
+ // Xbox-Specific Detection
1140
+ if (this.get(NAME) == WINDOWS && uaCH[MODEL] == 'Xbox') {
1141
+ this.set(NAME, 'Xbox')
1142
+ .set(VERSION, undefined);
1143
+ }
1092
1144
  break;
1093
1145
  case UA_RESULT:
1094
1146
  var data = this.data;
@@ -1122,7 +1174,7 @@
1122
1174
  function UAParser (ua, extensions, headers) {
1123
1175
 
1124
1176
  if (typeof ua === OBJ_TYPE) {
1125
- if (isExtensions(ua)) {
1177
+ if (isExtensions(ua, true)) {
1126
1178
  if (typeof extensions === OBJ_TYPE) {
1127
1179
  headers = extensions; // case UAParser(extensions, headers)
1128
1180
  }
@@ -1132,7 +1184,7 @@
1132
1184
  extensions = undefined;
1133
1185
  }
1134
1186
  ua = undefined;
1135
- } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1187
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
1136
1188
  headers = extensions; // case UAParser(ua, headers)
1137
1189
  extensions = undefined;
1138
1190
  }
@@ -1182,7 +1234,7 @@
1182
1234
  ['getResult', createItemFunc(UA_RESULT)],
1183
1235
  ['getUA', function () { return userAgent; }],
1184
1236
  ['setUA', function (ua) {
1185
- if (typeof ua === STR_TYPE)
1237
+ if (isString(ua))
1186
1238
  userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
1187
1239
  return this;
1188
1240
  }]
@@ -1193,7 +1245,7 @@
1193
1245
  }
1194
1246
 
1195
1247
  UAParser.VERSION = LIBVERSION;
1196
- UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);
1248
+ UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]);
1197
1249
  UAParser.CPU = enumerize([ARCHITECTURE]);
1198
1250
  UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
1199
1251
  UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);