ua-parser-js 2.0.0-beta.2 → 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.
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.0-beta.2
3
- Copyright © 2012-2023 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.0-beta.3
3
+ Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
4
4
  AGPLv3 License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
6
  Supports browser & node.js environment.
@@ -19,7 +19,7 @@
19
19
  // Constants
20
20
  /////////////
21
21
 
22
- var LIBVERSION = '2.0.0-beta.2',
22
+ var LIBVERSION = '2.0.0-beta.3',
23
23
  EMPTY = '',
24
24
  UNKNOWN = '?',
25
25
  FUNC_TYPE = 'function',
@@ -38,11 +38,12 @@
38
38
  TABLET = 'tablet',
39
39
  SMARTTV = 'smarttv',
40
40
  WEARABLE = 'wearable',
41
+ XR = 'xr',
41
42
  EMBEDDED = 'embedded',
42
43
  USER_AGENT = 'user-agent',
43
44
  UA_MAX_LENGTH = 500,
44
45
  BRANDS = 'brands',
45
- FORMFACTOR = 'formFactor',
46
+ FORMFACTORS = 'formFactors',
46
47
  FULLVERLIST = 'fullVersionList',
47
48
  PLATFORM = 'platform',
48
49
  PLATFORMVER = 'platformVersion',
@@ -51,12 +52,12 @@
51
52
  CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
52
53
  CH_HEADER_ARCH = CH_HEADER + '-arch',
53
54
  CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
54
- CH_HEADER_FORM_FACTOR = CH_HEADER + '-form-factor',
55
+ CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
55
56
  CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
56
57
  CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
57
58
  CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
58
59
  CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
59
- CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTOR, BITNESS],
60
+ CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
60
61
  UA_BROWSER = 'browser',
61
62
  UA_CPU = 'cpu',
62
63
  UA_DEVICE = 'device',
@@ -100,12 +101,21 @@
100
101
  // Helper
101
102
  //////////
102
103
 
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];
104
+ var extend = function (defaultRgx, extensions) {
105
+ var mergedRgx = {};
106
+ var extraRgx = extensions;
107
+ if (!isExtensions(extensions)) {
108
+ extraRgx = {};
109
+ for (var i in extensions) {
110
+ for (var j in extensions[i]) {
111
+ extraRgx[j] = extensions[i][j].concat(extraRgx[j] ? extraRgx[j] : []);
112
+ }
113
+ }
114
+ }
115
+ for (var k in defaultRgx) {
116
+ mergedRgx[k] = extraRgx[k] && extraRgx[k].length % 2 === 0 ? extraRgx[k].concat(defaultRgx[k]) : defaultRgx[k];
107
117
  }
108
- return mergedRegexes;
118
+ return mergedRgx;
109
119
  },
110
120
  enumerize = function (arr) {
111
121
  var enums = {};
@@ -123,9 +133,9 @@
123
133
  }
124
134
  return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
125
135
  },
126
- isExtensions = function (obj) {
136
+ isExtensions = function (obj, deep) {
127
137
  for (var prop in obj) {
128
- return /^(browser|cpu|device|engine|os)$/.test(prop);
138
+ return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false);
129
139
  }
130
140
  },
131
141
  isString = function (val) {
@@ -269,12 +279,13 @@
269
279
  'RT' : 'ARM'
270
280
  },
271
281
 
272
- formFactorMap = {
282
+ formFactorsMap = {
273
283
  'embedded' : 'Automotive',
274
284
  'mobile' : 'Mobile',
275
285
  'tablet' : ['Tablet', 'EInk'],
276
286
  'smarttv' : 'TV',
277
- 'wearable' : ['VR', 'XR', 'Watch'],
287
+ 'wearable' : 'Watch',
288
+ 'xr' : ['VR', 'XR'],
278
289
  '?' : ['Desktop', 'Unknown'],
279
290
  '*' : undefined
280
291
  };
@@ -309,17 +320,20 @@
309
320
  /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
310
321
  ], [VERSION, [NAME, 'Baidu']], [
311
322
  /(kindle)\/([\w\.]+)/i, // Kindle
312
- /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer
323
+ /(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i,
324
+ // Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir
313
325
  // Trident based
314
326
  /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
315
327
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
316
328
 
317
329
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
318
- /(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,
319
- // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo
330
+ /(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,
331
+ // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar
320
332
  /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
321
333
  /(weibo)__([\d\.]+)/i // Weibo
322
334
  ], [NAME, VERSION], [
335
+ /\bddg\/([\w\.]+)/i // DuckDuckGo
336
+ ], [VERSION, [NAME, 'DuckDuckGo']], [
323
337
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
324
338
  ], [VERSION, [NAME, 'UCBrowser']], [
325
339
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
@@ -352,8 +366,10 @@
352
366
  ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
353
367
  /\bqihu|(qi?ho?o?|360)browser/i // 360
354
368
  ], [[NAME, '360' + SUFFIX_BROWSER]], [
355
- /(oculus|sailfish|huawei|vivo)browser\/([\w\.]+)/i
356
- ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser
369
+ /\b(qq)\/([\w\.]+)/i // QQ
370
+ ], [[NAME, /(.+)/, '$1Browser'], VERSION], [
371
+ /(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i
372
+ ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser
357
373
  /samsungbrowser\/([\w\.]+)/i // Samsung Internet
358
374
  ], [VERSION, [NAME, SAMSUNG + ' Internet']], [
359
375
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
@@ -366,7 +382,7 @@
366
382
  /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
367
383
  /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser
368
384
  ], [NAME, VERSION], [
369
- /(lbbrowser)/i, // LieBao Browser
385
+ /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq
370
386
  /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
371
387
  ], [NAME], [
372
388
 
@@ -379,6 +395,7 @@
379
395
  /safari (line)\/([\w\.]+)/i, // Line App for iOS
380
396
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
381
397
  /(alipay)client\/([\w\.]+)/i, // Alipay
398
+ /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
382
399
  /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
383
400
  ], [NAME, VERSION], [
384
401
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
@@ -418,23 +435,24 @@
418
435
  ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
419
436
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
420
437
  ], [[NAME, 'Netscape'], VERSION], [
438
+ /(wolvic)\/([\w\.]+)/i // Wolvic
439
+ ], [NAME, VERSION], [
421
440
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
422
441
  ], [VERSION, [NAME, FIREFOX+' Reality']], [
423
442
  /ekiohf.+(flow)\/([\w\.]+)/i, // Flow
424
443
  /(swiftfox)/i, // Swiftfox
425
- /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i,
426
- // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar
444
+ /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
445
+ // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
427
446
  /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
428
447
  // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
429
448
  /(firefox)\/([\w\.]+)/i, // Other Firefox-based
430
449
  /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
431
450
 
432
451
  // Other
433
- /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
434
- // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser
435
- /(links) \(([\w\.]+)/i, // Links
436
- /panasonic;(viera)/i // Panasonic Viera
437
- ], [NAME, VERSION], [
452
+ /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
453
+ // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser
454
+ /(links) \(([\w\.]+)/i // Links
455
+ ], [NAME, [VERSION, /_/g, '.']], [
438
456
 
439
457
  /(cobalt)\/([\w\.]+)/i // Cobalt
440
458
  ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
@@ -521,6 +539,8 @@
521
539
  /; (\w+) bui.+ oppo/i,
522
540
  /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
523
541
  ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
542
+ /\b(opd2\d{3}a?) bui/i
543
+ ], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [
524
544
 
525
545
  // Vivo
526
546
  /vivo (\w+)(?: bui|\))/i,
@@ -704,12 +724,17 @@
704
724
  ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
705
725
  /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
706
726
  ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
707
- /droid.+; (glass) \d/i // Google Glass
708
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
709
727
  /droid.+; (wt63?0{2,3})\)/i
710
728
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
711
- /(quest( 2| pro)?)/i // Oculus Quest
712
- ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [
729
+
730
+ ///////////////////
731
+ // XR
732
+ ///////////////////
733
+
734
+ /droid.+; (glass) \d/i // Google Glass
735
+ ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
736
+ /(quest( \d| pro)?)/i // Oculus Quest
737
+ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
713
738
 
714
739
  ///////////////////
715
740
  // EMBEDDED
@@ -840,7 +865,7 @@
840
865
  var defaultProps = (function () {
841
866
  var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
842
867
  setProps.call(props.init, [
843
- [UA_BROWSER, [NAME, VERSION, MAJOR]],
868
+ [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
844
869
  [UA_CPU, [ARCHITECTURE]],
845
870
  [UA_DEVICE, [TYPE, MODEL, VENDOR]],
846
871
  [UA_ENGINE, [NAME, VERSION]],
@@ -968,7 +993,7 @@
968
993
  [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
969
994
  [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
970
995
  [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
971
- [FORMFACTOR, itemListToArray(uach[CH_HEADER_FORM_FACTOR])],
996
+ [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
972
997
  [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
973
998
  ]);
974
999
  } else {
@@ -1088,15 +1113,15 @@
1088
1113
  this.set(TYPE, CONSOLE)
1089
1114
  .set(VENDOR, MICROSOFT);
1090
1115
  }
1091
- if (uaCH[FORMFACTOR]) {
1116
+ if (uaCH[FORMFACTORS]) {
1092
1117
  var ff;
1093
- if (typeof uaCH[FORMFACTOR] !== 'string') {
1118
+ if (typeof uaCH[FORMFACTORS] !== 'string') {
1094
1119
  var idx = 0;
1095
- while (!ff && idx < uaCH[FORMFACTOR].length) {
1096
- ff = strMapper(uaCH[FORMFACTOR][idx++], formFactorMap);
1120
+ while (!ff && idx < uaCH[FORMFACTORS].length) {
1121
+ ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
1097
1122
  }
1098
1123
  } else {
1099
- ff = strMapper(uaCH[FORMFACTOR], formFactorMap);
1124
+ ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
1100
1125
  }
1101
1126
  this.set(TYPE, ff);
1102
1127
  }
@@ -1147,7 +1172,7 @@
1147
1172
  function UAParser (ua, extensions, headers) {
1148
1173
 
1149
1174
  if (typeof ua === OBJ_TYPE) {
1150
- if (isExtensions(ua)) {
1175
+ if (isExtensions(ua, true)) {
1151
1176
  if (typeof extensions === OBJ_TYPE) {
1152
1177
  headers = extensions; // case UAParser(extensions, headers)
1153
1178
  }
@@ -1157,7 +1182,7 @@
1157
1182
  extensions = undefined;
1158
1183
  }
1159
1184
  ua = undefined;
1160
- } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1185
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
1161
1186
  headers = extensions; // case UAParser(ua, headers)
1162
1187
  extensions = undefined;
1163
1188
  }
@@ -1218,7 +1243,7 @@
1218
1243
  }
1219
1244
 
1220
1245
  UAParser.VERSION = LIBVERSION;
1221
- UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);
1246
+ UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]);
1222
1247
  UAParser.CPU = enumerize([ARCHITECTURE]);
1223
1248
  UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
1224
1249
  UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);
@@ -3,8 +3,8 @@
3
3
  // Source: /src/main/ua-parser.js
4
4
 
5
5
  /////////////////////////////////////////////////////////////////////////////////
6
- /* UAParser.js v2.0.0-beta.2
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,7 +21,7 @@
21
21
  // Constants
22
22
  /////////////
23
23
 
24
- var LIBVERSION = '2.0.0-beta.2',
24
+ var LIBVERSION = '2.0.0-beta.3',
25
25
  EMPTY = '',
26
26
  UNKNOWN = '?',
27
27
  FUNC_TYPE = 'function',
@@ -40,11 +40,12 @@
40
40
  TABLET = 'tablet',
41
41
  SMARTTV = 'smarttv',
42
42
  WEARABLE = 'wearable',
43
+ XR = 'xr',
43
44
  EMBEDDED = 'embedded',
44
45
  USER_AGENT = 'user-agent',
45
46
  UA_MAX_LENGTH = 500,
46
47
  BRANDS = 'brands',
47
- FORMFACTOR = 'formFactor',
48
+ FORMFACTORS = 'formFactors',
48
49
  FULLVERLIST = 'fullVersionList',
49
50
  PLATFORM = 'platform',
50
51
  PLATFORMVER = 'platformVersion',
@@ -53,12 +54,12 @@
53
54
  CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
54
55
  CH_HEADER_ARCH = CH_HEADER + '-arch',
55
56
  CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
56
- CH_HEADER_FORM_FACTOR = CH_HEADER + '-form-factor',
57
+ CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
57
58
  CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
58
59
  CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
59
60
  CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
60
61
  CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
61
- 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],
62
63
  UA_BROWSER = 'browser',
63
64
  UA_CPU = 'cpu',
64
65
  UA_DEVICE = 'device',
@@ -102,12 +103,21 @@
102
103
  // Helper
103
104
  //////////
104
105
 
105
- var extend = function (regexes, extensions) {
106
- var mergedRegexes = {};
107
- for (var i in regexes) {
108
- 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];
109
119
  }
110
- return mergedRegexes;
120
+ return mergedRgx;
111
121
  },
112
122
  enumerize = function (arr) {
113
123
  var enums = {};
@@ -125,9 +135,9 @@
125
135
  }
126
136
  return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
127
137
  },
128
- isExtensions = function (obj) {
138
+ isExtensions = function (obj, deep) {
129
139
  for (var prop in obj) {
130
- return /^(browser|cpu|device|engine|os)$/.test(prop);
140
+ return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false);
131
141
  }
132
142
  },
133
143
  isString = function (val) {
@@ -271,12 +281,13 @@
271
281
  'RT' : 'ARM'
272
282
  },
273
283
 
274
- formFactorMap = {
284
+ formFactorsMap = {
275
285
  'embedded' : 'Automotive',
276
286
  'mobile' : 'Mobile',
277
287
  'tablet' : ['Tablet', 'EInk'],
278
288
  'smarttv' : 'TV',
279
- 'wearable' : ['VR', 'XR', 'Watch'],
289
+ 'wearable' : 'Watch',
290
+ 'xr' : ['VR', 'XR'],
280
291
  '?' : ['Desktop', 'Unknown'],
281
292
  '*' : undefined
282
293
  };
@@ -311,17 +322,20 @@
311
322
  /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
312
323
  ], [VERSION, [NAME, 'Baidu']], [
313
324
  /(kindle)\/([\w\.]+)/i, // Kindle
314
- /(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
315
327
  // Trident based
316
328
  /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
317
329
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
318
330
 
319
331
  // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
320
- /(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,
321
- // 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
322
334
  /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
323
335
  /(weibo)__([\d\.]+)/i // Weibo
324
336
  ], [NAME, VERSION], [
337
+ /\bddg\/([\w\.]+)/i // DuckDuckGo
338
+ ], [VERSION, [NAME, 'DuckDuckGo']], [
325
339
  /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
326
340
  ], [VERSION, [NAME, 'UCBrowser']], [
327
341
  /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
@@ -354,8 +368,10 @@
354
368
  ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
355
369
  /\bqihu|(qi?ho?o?|360)browser/i // 360
356
370
  ], [[NAME, '360' + SUFFIX_BROWSER]], [
357
- /(oculus|sailfish|huawei|vivo)browser\/([\w\.]+)/i
358
- ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser
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
359
375
  /samsungbrowser\/([\w\.]+)/i // Samsung Internet
360
376
  ], [VERSION, [NAME, SAMSUNG + ' Internet']], [
361
377
  /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
@@ -368,7 +384,7 @@
368
384
  /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
369
385
  /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser
370
386
  ], [NAME, VERSION], [
371
- /(lbbrowser)/i, // LieBao Browser
387
+ /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq
372
388
  /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
373
389
  ], [NAME], [
374
390
 
@@ -381,6 +397,7 @@
381
397
  /safari (line)\/([\w\.]+)/i, // Line App for iOS
382
398
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
383
399
  /(alipay)client\/([\w\.]+)/i, // Alipay
400
+ /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
384
401
  /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
385
402
  ], [NAME, VERSION], [
386
403
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
@@ -420,23 +437,24 @@
420
437
  ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
421
438
  /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
422
439
  ], [[NAME, 'Netscape'], VERSION], [
440
+ /(wolvic)\/([\w\.]+)/i // Wolvic
441
+ ], [NAME, VERSION], [
423
442
  /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
424
443
  ], [VERSION, [NAME, FIREFOX+' Reality']], [
425
444
  /ekiohf.+(flow)\/([\w\.]+)/i, // Flow
426
445
  /(swiftfox)/i, // Swiftfox
427
- /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i,
428
- // 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
429
448
  /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
430
449
  // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
431
450
  /(firefox)\/([\w\.]+)/i, // Other Firefox-based
432
451
  /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
433
452
 
434
453
  // Other
435
- /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
436
- // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser
437
- /(links) \(([\w\.]+)/i, // Links
438
- /panasonic;(viera)/i // Panasonic Viera
439
- ], [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, '.']], [
440
458
 
441
459
  /(cobalt)\/([\w\.]+)/i // Cobalt
442
460
  ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
@@ -523,6 +541,8 @@
523
541
  /; (\w+) bui.+ oppo/i,
524
542
  /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
525
543
  ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
544
+ /\b(opd2\d{3}a?) bui/i
545
+ ], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [
526
546
 
527
547
  // Vivo
528
548
  /vivo (\w+)(?: bui|\))/i,
@@ -706,12 +726,17 @@
706
726
  ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
707
727
  /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
708
728
  ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
709
- /droid.+; (glass) \d/i // Google Glass
710
- ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
711
729
  /droid.+; (wt63?0{2,3})\)/i
712
730
  ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
713
- /(quest( 2| pro)?)/i // Oculus Quest
714
- ], [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]], [
715
740
 
716
741
  ///////////////////
717
742
  // EMBEDDED
@@ -842,7 +867,7 @@
842
867
  var defaultProps = (function () {
843
868
  var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
844
869
  setProps.call(props.init, [
845
- [UA_BROWSER, [NAME, VERSION, MAJOR]],
870
+ [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
846
871
  [UA_CPU, [ARCHITECTURE]],
847
872
  [UA_DEVICE, [TYPE, MODEL, VENDOR]],
848
873
  [UA_ENGINE, [NAME, VERSION]],
@@ -970,7 +995,7 @@
970
995
  [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
971
996
  [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
972
997
  [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
973
- [FORMFACTOR, itemListToArray(uach[CH_HEADER_FORM_FACTOR])],
998
+ [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
974
999
  [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
975
1000
  ]);
976
1001
  } else {
@@ -1090,15 +1115,15 @@
1090
1115
  this.set(TYPE, CONSOLE)
1091
1116
  .set(VENDOR, MICROSOFT);
1092
1117
  }
1093
- if (uaCH[FORMFACTOR]) {
1118
+ if (uaCH[FORMFACTORS]) {
1094
1119
  var ff;
1095
- if (typeof uaCH[FORMFACTOR] !== 'string') {
1120
+ if (typeof uaCH[FORMFACTORS] !== 'string') {
1096
1121
  var idx = 0;
1097
- while (!ff && idx < uaCH[FORMFACTOR].length) {
1098
- ff = strMapper(uaCH[FORMFACTOR][idx++], formFactorMap);
1122
+ while (!ff && idx < uaCH[FORMFACTORS].length) {
1123
+ ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
1099
1124
  }
1100
1125
  } else {
1101
- ff = strMapper(uaCH[FORMFACTOR], formFactorMap);
1126
+ ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
1102
1127
  }
1103
1128
  this.set(TYPE, ff);
1104
1129
  }
@@ -1149,7 +1174,7 @@
1149
1174
  function UAParser (ua, extensions, headers) {
1150
1175
 
1151
1176
  if (typeof ua === OBJ_TYPE) {
1152
- if (isExtensions(ua)) {
1177
+ if (isExtensions(ua, true)) {
1153
1178
  if (typeof extensions === OBJ_TYPE) {
1154
1179
  headers = extensions; // case UAParser(extensions, headers)
1155
1180
  }
@@ -1159,7 +1184,7 @@
1159
1184
  extensions = undefined;
1160
1185
  }
1161
1186
  ua = undefined;
1162
- } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) {
1187
+ } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
1163
1188
  headers = extensions; // case UAParser(ua, headers)
1164
1189
  extensions = undefined;
1165
1190
  }
@@ -1220,7 +1245,7 @@
1220
1245
  }
1221
1246
 
1222
1247
  UAParser.VERSION = LIBVERSION;
1223
- UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);
1248
+ UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]);
1224
1249
  UAParser.CPU = enumerize([ARCHITECTURE]);
1225
1250
  UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
1226
1251
  UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);