diff --git a/bower.json b/bower.json index 6539b1b..618bac5 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "ua-parser-js", - "version": "0.7.28", + "version": "0.7.31", "authors": [ "Faisal Salman " ], diff --git a/dist/ua-parser.min.js b/dist/ua-parser.min.js index 1a3eed4..d2bdd17 100644 --- a/dist/ua-parser.min.js +++ b/dist/ua-parser.min.js @@ -1,4 +1,4 @@ -/* UAParser.js v0.7.28 +/* UAParser.js v0.7.31 Copyright © 2012-2021 Faisal Salman MIT License */ -(function(window,undefined){"use strict";var LIBVERSION="0.7.28",EMPTY="",UNKNOWN="?",FUNC_TYPE="function",UNDEF_TYPE="undefined",OBJ_TYPE="object",STR_TYPE="string",MAJOR="major",MODEL="model",NAME="name",TYPE="type",VENDOR="vendor",VERSION="version",ARCHITECTURE="architecture",CONSOLE="console",MOBILE="mobile",TABLET="tablet",SMARTTV="smarttv",WEARABLE="wearable",EMBEDDED="embedded",UA_MAX_LENGTH=255;var AMAZON="Amazon",APPLE="Apple",ASUS="ASUS",BLACKBERRY="BlackBerry",BROWSER="Browser",CHROME="Chrome",EDGE="Edge",FIREFOX="Firefox",GOOGLE="Google",HUAWEI="Huawei",LG="LG",MICROSOFT="Microsoft",MOTOROLA="Motorola",OPERA="Opera",SAMSUNG="Samsung",SONY="Sony",XIAOMI="Xiaomi",ZEBRA="Zebra";var extend=function(regexes,extensions){var mergedRegexes={};for(var i in regexes){if(extensions[i]&&extensions[i].length%2===0){mergedRegexes[i]=extensions[i].concat(regexes[i])}else{mergedRegexes[i]=regexes[i]}}return mergedRegexes},enumerize=function(arr){var enums={};for(var i=0;i0){if(q.length==2){if(typeof q[1]==FUNC_TYPE){this[q[0]]=q[1].call(this,match)}else{this[q[0]]=q[1]}}else if(q.length==3){if(typeof q[1]===FUNC_TYPE&&!(q[1].exec&&q[1].test)){this[q[0]]=match?q[1].call(this,match,q[2]):undefined}else{this[q[0]]=match?match.replace(q[1],q[2]):undefined}}else if(q.length==4){this[q[0]]=match?q[3].call(this,match.replace(q[1],q[2])):undefined}}else{this[q]=match?match:undefined}}}}i+=2}},strMapper=function(str,map){for(var i in map){if(typeof map[i]===OBJ_TYPE&&map[i].length>0){for(var j=0;jUA_MAX_LENGTH?trim(ua,UA_MAX_LENGTH):ua;return this};this.setUA(_ua);return this};UAParser.VERSION=LIBVERSION;UAParser.BROWSER=enumerize([NAME,VERSION,MAJOR]);UAParser.CPU=enumerize([ARCHITECTURE]);UAParser.DEVICE=enumerize([MODEL,VENDOR,TYPE,CONSOLE,MOBILE,SMARTTV,TABLET,WEARABLE,EMBEDDED]);UAParser.ENGINE=UAParser.OS=enumerize([NAME,VERSION]);if(typeof exports!==UNDEF_TYPE){if(typeof module!==UNDEF_TYPE&&module.exports){exports=module.exports=UAParser}exports.UAParser=UAParser}else{if(typeof define===FUNC_TYPE&&define.amd){define(function(){return UAParser})}else if(typeof window!==UNDEF_TYPE){window.UAParser=UAParser}}var $=typeof window!==UNDEF_TYPE&&(window.jQuery||window.Zepto);if($&&!$.ua){var parser=new UAParser;$.ua=parser.getResult();$.ua.get=function(){return parser.getUA()};$.ua.set=function(ua){parser.setUA(ua);var result=parser.getResult();for(var prop in result){$.ua[prop]=result[prop]}}}})(typeof window==="object"?window:this); \ No newline at end of file +(function(window,undefined){"use strict";var LIBVERSION="0.7.31",EMPTY="",UNKNOWN="?",FUNC_TYPE="function",UNDEF_TYPE="undefined",OBJ_TYPE="object",STR_TYPE="string",MAJOR="major",MODEL="model",NAME="name",TYPE="type",VENDOR="vendor",VERSION="version",ARCHITECTURE="architecture",CONSOLE="console",MOBILE="mobile",TABLET="tablet",SMARTTV="smarttv",WEARABLE="wearable",EMBEDDED="embedded",UA_MAX_LENGTH=275;var AMAZON="Amazon",APPLE="Apple",ASUS="ASUS",BLACKBERRY="BlackBerry",BROWSER="Browser",CHROME="Chrome",EDGE="Edge",FIREFOX="Firefox",GOOGLE="Google",HUAWEI="Huawei",LG="LG",MICROSOFT="Microsoft",MOTOROLA="Motorola",OPERA="Opera",SAMSUNG="Samsung",SONY="Sony",XIAOMI="Xiaomi",ZEBRA="Zebra",FACEBOOK="Facebook";var extend=function(regexes,extensions){var mergedRegexes={};for(var i in regexes){if(extensions[i]&&extensions[i].length%2===0){mergedRegexes[i]=extensions[i].concat(regexes[i])}else{mergedRegexes[i]=regexes[i]}}return mergedRegexes},enumerize=function(arr){var enums={};for(var i=0;i0){if(q.length===2){if(typeof q[1]==FUNC_TYPE){this[q[0]]=q[1].call(this,match)}else{this[q[0]]=q[1]}}else if(q.length===3){if(typeof q[1]===FUNC_TYPE&&!(q[1].exec&&q[1].test)){this[q[0]]=match?q[1].call(this,match,q[2]):undefined}else{this[q[0]]=match?match.replace(q[1],q[2]):undefined}}else if(q.length===4){this[q[0]]=match?q[3].call(this,match.replace(q[1],q[2])):undefined}}else{this[q]=match?match:undefined}}}}i+=2}},strMapper=function(str,map){for(var i in map){if(typeof map[i]===OBJ_TYPE&&map[i].length>0){for(var j=0;jUA_MAX_LENGTH?trim(ua,UA_MAX_LENGTH):ua;return this};this.setUA(_ua);return this};UAParser.VERSION=LIBVERSION;UAParser.BROWSER=enumerize([NAME,VERSION,MAJOR]);UAParser.CPU=enumerize([ARCHITECTURE]);UAParser.DEVICE=enumerize([MODEL,VENDOR,TYPE,CONSOLE,MOBILE,SMARTTV,TABLET,WEARABLE,EMBEDDED]);UAParser.ENGINE=UAParser.OS=enumerize([NAME,VERSION]);if(typeof exports!==UNDEF_TYPE){if(typeof module!==UNDEF_TYPE&&module.exports){exports=module.exports=UAParser}exports.UAParser=UAParser}else{if(typeof define===FUNC_TYPE&&define.amd){define(function(){return UAParser})}else if(typeof window!==UNDEF_TYPE){window.UAParser=UAParser}}var $=typeof window!==UNDEF_TYPE&&(window.jQuery||window.Zepto);if($&&!$.ua){var parser=new UAParser;$.ua=parser.getResult();$.ua.get=function(){return parser.getUA()};$.ua.set=function(ua){parser.setUA(ua);var result=parser.getResult();for(var prop in result){$.ua[prop]=result[prop]}}}})(typeof window==="object"?window:this); \ No newline at end of file diff --git a/dist/ua-parser.pack.js b/dist/ua-parser.pack.js index bde4d2e..c6a6616 100644 --- a/dist/ua-parser.pack.js +++ b/dist/ua-parser.pack.js @@ -1,4 +1,4 @@ -/* UAParser.js v0.7.28 +/* UAParser.js v0.7.31 Copyright © 2012-2021 Faisal Salman MIT License */ -!function(r,d){"use strict";function i(i){for(var e={},o=0;o (http://faisalman.com)", "description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Supports browser & node.js environment", "keywords": [ @@ -156,10 +156,12 @@ ], "regs": [ "^((?:\\$|(\\s*\\*\\s*@)|(\\s*(?:var|,)?\\s+))(?:LIBVERSION|version)[\\s\\:='\"]+)([0-9]+(?:\\.[0-9]+){2,2})", - "^(\\s?\\*.*v)([0-9]+(?:\\.[0-9]+){2,2})" + "^(\\/?\\s?\\*.*v)([0-9]+(?:\\.[0-9]+){2,2})" ] }, "devDependencies": { + "@babel/parser": "7.15.8", + "@babel/traverse": "7.15.4", "jshint": "~2.12.0", "mocha": "~8.2.0", "requirejs": "^2.3.2", diff --git a/src/ua-parser.js b/src/ua-parser.js index ae050f3..09294c2 100755 --- a/src/ua-parser.js +++ b/src/ua-parser.js @@ -1,875 +1,1176 @@ ///////////////////////////////////////////////////////////////////////////////// -/* UAParser.js v0.7.28 +/* UAParser.js v0.7.31 Copyright © 2012-2021 Faisal Salman - MIT License *//* + MIT License */ /* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. - Supports browser & node.js environment. + Supports browser & node.js environment. Demo : https://faisalman.github.io/ua-parser-js Source : https://github.com/faisalman/ua-parser-js */ ///////////////////////////////////////////////////////////////////////////////// (function (window, undefined) { + "use strict"; - 'use strict'; + ////////////// + // Constants + ///////////// - ////////////// - // Constants - ///////////// + var LIBVERSION = "0.7.31", + EMPTY = "", + UNKNOWN = "?", + FUNC_TYPE = "function", + UNDEF_TYPE = "undefined", + OBJ_TYPE = "object", + STR_TYPE = "string", + MAJOR = "major", + MODEL = "model", + NAME = "name", + TYPE = "type", + VENDOR = "vendor", + VERSION = "version", + ARCHITECTURE = "architecture", + CONSOLE = "console", + MOBILE = "mobile", + TABLET = "tablet", + SMARTTV = "smarttv", + WEARABLE = "wearable", + EMBEDDED = "embedded", + UA_MAX_LENGTH = 275; + var AMAZON = "Amazon", + APPLE = "Apple", + ASUS = "ASUS", + BLACKBERRY = "BlackBerry", + BROWSER = "Browser", + CHROME = "Chrome", + EDGE = "Edge", + FIREFOX = "Firefox", + GOOGLE = "Google", + HUAWEI = "Huawei", + LG = "LG", + MICROSOFT = "Microsoft", + MOTOROLA = "Motorola", + OPERA = "Opera", + SAMSUNG = "Samsung", + SONY = "Sony", + XIAOMI = "Xiaomi", + ZEBRA = "Zebra", + FACEBOOK = "Facebook"; - var LIBVERSION = '0.7.28', - EMPTY = '', - UNKNOWN = '?', - FUNC_TYPE = 'function', - UNDEF_TYPE = 'undefined', - OBJ_TYPE = 'object', - STR_TYPE = 'string', - MAJOR = 'major', - MODEL = 'model', - NAME = 'name', - TYPE = 'type', - VENDOR = 'vendor', - VERSION = 'version', - ARCHITECTURE= 'architecture', - CONSOLE = 'console', - MOBILE = 'mobile', - TABLET = 'tablet', - SMARTTV = 'smarttv', - WEARABLE = 'wearable', - EMBEDDED = 'embedded', - UA_MAX_LENGTH = 255; + /////////// + // Helper + ////////// - var AMAZON = 'Amazon', - APPLE = 'Apple', - ASUS = 'ASUS', - BLACKBERRY = 'BlackBerry', - BROWSER = 'Browser', - CHROME = 'Chrome', - EDGE = 'Edge', - FIREFOX = 'Firefox', - GOOGLE = 'Google', - HUAWEI = 'Huawei', - LG = 'LG', - MICROSOFT = 'Microsoft', - MOTOROLA = 'Motorola', - OPERA = 'Opera', - SAMSUNG = 'Samsung', - SONY = 'Sony', - XIAOMI = 'Xiaomi', - ZEBRA = 'Zebra'; + var extend = function (regexes, extensions) { + var mergedRegexes = {}; + for (var i in regexes) { + if (extensions[i] && extensions[i].length % 2 === 0) { + mergedRegexes[i] = extensions[i].concat(regexes[i]); + } else { + mergedRegexes[i] = regexes[i]; + } + } + return mergedRegexes; + }, + enumerize = function (arr) { + var enums = {}; + for (var i = 0; i < arr.length; i++) { + enums[arr[i].toUpperCase()] = arr[i]; + } + return enums; + }, + has = function (str1, str2) { + return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; + }, + lowerize = function (str) { + return str.toLowerCase(); + }, + majorize = function (version) { + return typeof version === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split(".")[0] : undefined; + }, + trim = function (str, len) { + if (typeof str === STR_TYPE) { + str = str.replace(/^\s\s*/, EMPTY).replace(/\s\s*$/, EMPTY); + return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH); + } + }; - /////////// - // Helper - ////////// + /////////////// + // Map helper + ////////////// - var extend = function (regexes, extensions) { - var mergedRegexes = {}; - for (var i in regexes) { - if (extensions[i] && extensions[i].length % 2 === 0) { - mergedRegexes[i] = extensions[i].concat(regexes[i]); - } else { - mergedRegexes[i] = regexes[i]; + var rgxMapper = function (ua, arrays) { + var i = 0, + j, + k, + p, + q, + matches, + match; + + // loop through all regexes maps + while (i < arrays.length && !matches) { + var regex = arrays[i], // even sequence (0,2,4,..) + props = arrays[i + 1]; // odd sequence (1,3,5,..) + j = k = 0; + + // try matching uastring with regexes + while (j < regex.length && !matches) { + matches = regex[j++].exec(ua); + + if (!!matches) { + for (p = 0; p < props.length; p++) { + match = matches[++k]; + q = props[p]; + // check if given property is actually array + if (typeof q === OBJ_TYPE && q.length > 0) { + if (q.length === 2) { + if (typeof q[1] == FUNC_TYPE) { + // assign modified match + this[q[0]] = q[1].call(this, match); + } else { + // assign given value, ignore regex match + this[q[0]] = q[1]; + } + } else if (q.length === 3) { + // check whether function or regex + if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) { + // call function (usually string mapper) + this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; + } else { + // sanitize match using given regex + this[q[0]] = match ? match.replace(q[1], q[2]) : undefined; + } + } else if (q.length === 4) { + this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; } + } else { + this[q] = match ? match : undefined; + } } - return mergedRegexes; - }, - enumerize = function (arr) { - var enums = {}; - for (var i = 0; i < arr.length; i++) { - enums[arr[i].toUpperCase()] = arr[i]; - } - return enums; - }, - has = function (str1, str2) { - return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; - }, - lowerize = function (str) { - return str.toLowerCase(); - }, - majorize = function (version) { - return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined; - }, - trim = function (str, len) { - if (typeof(str) === STR_TYPE) { - str = str.replace(/^\s+|\s+$/g, EMPTY); - return typeof(len) === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH); - } - }; - - /////////////// - // Map helper - ////////////// - - var rgxMapper = function (ua, arrays) { - - var i = 0, j, k, p, q, matches, match; - - // loop through all regexes maps - while (i < arrays.length && !matches) { - - var regex = arrays[i], // even sequence (0,2,4,..) - props = arrays[i + 1]; // odd sequence (1,3,5,..) - j = k = 0; - - // try matching uastring with regexes - while (j < regex.length && !matches) { - - matches = regex[j++].exec(ua); - - if (!!matches) { - for (p = 0; p < props.length; p++) { - match = matches[++k]; - q = props[p]; - // check if given property is actually array - if (typeof q === OBJ_TYPE && q.length > 0) { - if (q.length == 2) { - if (typeof q[1] == FUNC_TYPE) { - // assign modified match - this[q[0]] = q[1].call(this, match); - } else { - // assign given value, ignore regex match - this[q[0]] = q[1]; - } - } else if (q.length == 3) { - // check whether function or regex - if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) { - // call function (usually string mapper) - this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; - } else { - // sanitize match using given regex - this[q[0]] = match ? match.replace(q[1], q[2]) : undefined; - } - } else if (q.length == 4) { - this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; - } - } else { - this[q] = match ? match : undefined; - } - } - } - } - i += 2; - } - }, - - strMapper = function (str, map) { - - for (var i in map) { - // check if current value is array - if (typeof map[i] === OBJ_TYPE && map[i].length > 0) { - for (var j = 0; j < map[i].length; j++) { - if (has(map[i][j], str)) { - return (i === UNKNOWN) ? undefined : i; - } - } - } else if (has(map[i], str)) { - return (i === UNKNOWN) ? undefined : i; - } - } - return str; - }; - - /////////////// - // String map - ////////////// - - // Safari < 3.0 - var oldSafariMap = { - '1.0' : '/8', - '1.2' : '/1', - '1.3' : '/3', - '2.0' : '/412', - '2.0.2' : '/416', - '2.0.3' : '/417', - '2.0.4' : '/419', - '?' : '/' - }, - windowsVersionMap = { - 'ME' : '4.90', - 'NT 3.11' : 'NT3.51', - 'NT 4.0' : 'NT4.0', - '2000' : 'NT 5.0', - 'XP' : ['NT 5.1', 'NT 5.2'], - 'Vista' : 'NT 6.0', - '7' : 'NT 6.1', - '8' : 'NT 6.2', - '8.1' : 'NT 6.3', - '10' : ['NT 6.4', 'NT 10.0'], - 'RT' : 'ARM' - }; - - ////////////// - // Regex map - ///////////// - - var regexes = { - - browser : [[ - - /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS - ], [VERSION, [NAME, 'Chrome']], [ - /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge - ], [VERSION, [NAME, 'Edge']], [ - - // Presto based - /(opera mini)\/([-\w\.]+)/i, // Opera Mini - /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, // Opera Mobi/Tablet - /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i // Opera - ], [NAME, VERSION], [ - /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0 - ], [VERSION, [NAME, OPERA+' Mini']], [ - /\bopr\/([\w\.]+)/i // Opera Webkit - ], [VERSION, [NAME, OPERA]], [ - - // Mixed - /(kindle)\/([\w\.]+)/i, // Kindle - /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer - // Trident based - /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser - /(ba?idubrowser)[\/ ]?([\w\.]+)/i, // Baidu Browser - /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer - - // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon - /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq)\/([-\w\.]+)/i, - // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ - /(weibo)__([\d\.]+)/i // Weibo - ], [NAME, VERSION], [ - /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser - ], [VERSION, [NAME, 'UC'+BROWSER]], [ - /\bqbcore\/([\w\.]+)/i // WeChat Desktop for Windows Built-in Browser - ], [VERSION, [NAME, 'WeChat(Win) Desktop']], [ - /micromessenger\/([\w\.]+)/i // WeChat - ], [VERSION, [NAME, 'WeChat']], [ - /konqueror\/([\w\.]+)/i // Konqueror - ], [VERSION, [NAME, 'Konqueror']], [ - /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11 - ], [VERSION, [NAME, 'IE']], [ - /yabrowser\/([\w\.]+)/i // Yandex - ], [VERSION, [NAME, 'Yandex']], [ - /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser - ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [ - /\bfocus\/([\w\.]+)/i // Firefox Focus - ], [VERSION, [NAME, FIREFOX+' Focus']], [ - /\bopt\/([\w\.]+)/i // Opera Touch - ], [VERSION, [NAME, OPERA+' Touch']], [ - /coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser - ], [VERSION, [NAME, 'Coc Coc']], [ - /dolfin\/([\w\.]+)/i // Dolphin - ], [VERSION, [NAME, 'Dolphin']], [ - /coast\/([\w\.]+)/i // Opera Coast - ], [VERSION, [NAME, OPERA+' Coast']], [ - /miuibrowser\/([\w\.]+)/i // MIUI Browser - ], [VERSION, [NAME, 'MIUI '+BROWSER]], [ - /fxios\/([-\w\.]+)/i // Firefox for iOS - ], [VERSION, [NAME, FIREFOX]], [ - /\bqihu|(qi?ho?o?|360)browser/i // 360 - ], [[NAME, '360 '+BROWSER]], [ - /(oculus|samsung|sailfish)browser\/([\w\.]+)/i - ], [[NAME, /(.+)/, '$1 '+BROWSER], VERSION], [ // Oculus/Samsung/Sailfish Browser - /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon - ], [[NAME, /_/g, ' '], VERSION], [ - /(electron)\/([\w\.]+) safari/i, // Electron-based App - /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla - /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/Baidu App/2345 Browser - ], [NAME, VERSION], [ - /(metasr)[\/ ]?([\w\.]+)/i, // SouGouBrowser - /(lbbrowser)/i // LieBao Browser - ], [NAME], [ - - // WebView - /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android - ], [[NAME, 'Facebook'], VERSION], [ - /safari (line)\/([\w\.]+)/i, // Line App for iOS - /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android - /(chromium|instagram)[\/ ]([-\w\.]+)/i // Chromium/Instagram - ], [NAME, VERSION], [ - /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS - ], [VERSION, [NAME, 'GSA']], [ - - /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless - ], [VERSION, [NAME, CHROME+' Headless']], [ - - / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView - ], [[NAME, CHROME+' WebView'], VERSION], [ - - /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser - ], [VERSION, [NAME, 'Android '+BROWSER]], [ - - /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia - ], [NAME, VERSION], [ - - /version\/([\w\.]+) .*mobile\/\w+ (safari)/i // Mobile Safari - ], [VERSION, [NAME, 'Mobile Safari']], [ - /version\/([\w\.]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile - ], [VERSION, NAME], [ - /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 - ], [NAME, [VERSION, strMapper, oldSafariMap]], [ - - /(webkit|khtml)\/([\w\.]+)/i - ], [NAME, VERSION], [ - - // Gecko based - /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape - ], [[NAME, 'Netscape'], VERSION], [ - /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality - ], [VERSION, [NAME, FIREFOX+' Reality']], [ - /ekiohf.+(flow)\/([\w\.]+)/i, // Flow - /(swiftfox)/i, // Swiftfox - /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, - // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar - /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, - // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix - /(firefox)\/([\w\.]+)/i, // Other Firefox-based - /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla - - // Other - /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, - // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser - /(links) \(([\w\.]+)/i // Links - ], [NAME, VERSION] - ], - - cpu : [[ - - /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64) - ], [[ARCHITECTURE, 'amd64']], [ - - /(ia32(?=;))/i // IA32 (quicktime) - ], [[ARCHITECTURE, lowerize]], [ - - /((?:i[346]|x)86)[;\)]/i // IA32 (x86) - ], [[ARCHITECTURE, 'ia32']], [ - - /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64 - ], [[ARCHITECTURE, 'arm64']], [ - - /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF - ], [[ARCHITECTURE, 'armhf']], [ - - // PocketPC mistakenly identified as PowerPC - /windows (ce|mobile); ppc;/i - ], [[ARCHITECTURE, 'arm']], [ - - /((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i // PowerPC - ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [ - - /(sun4\w)[;\)]/i // SPARC - ], [[ARCHITECTURE, 'sparc']], [ - - /((?:avr32|ia64(?=;))|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i - // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC - ], [[ARCHITECTURE, lowerize]] - ], - - device : [[ - - ////////////////////////// - // MOBILES & TABLETS - // Ordered by popularity - ///////////////////////// - - // Samsung - /\b(sch-i[89]0\d|shw-m380s|sm-[pt]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i - ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [ - /\b((?:s[cgp]h|gt|sm)-\w+|galaxy nexus)/i, - /samsung[- ]([-\w]+)/i, - /sec-(sgh\w+)/i - ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [ - - // Apple - /((ipod|iphone)\d+,\d+)/i // iPod/iPhone model - ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [ - /(ipad\d+,\d+)/i // iPad model - ], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [ - /\((ip(?:hone|od)[\w ]*);/i // iPod/iPhone - ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [ - /\((ipad);[-\w\),; ]+apple/i, // iPad - /applecoremedia\/[\w\.]+ \((ipad)/i, - /\b(ipad)\d\d?,\d\d?[;\]].+ios/i - ], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [ - - // Huawei - /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i - ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [ - /(?:huawei|honor)([-\w ]+)[;\)]/i, - /\b(nexus 6p|\w{2,4}-[atu]?[ln][01259x][012359][an]?)\b(?!.+d\/s)/i - ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [ - - // Xiaomi - /\b(poco[\w ]+)(?: bui|\))/i, // Xiaomi POCO - /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models - /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi - /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi - /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi - ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [ - /\b(mi[-_ ]?(?:pad)(?:[\w_ ]+))(?: bui|\))/i // Mi Pad tablets - ],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [ - - // OPPO - /; (\w+) bui.+ oppo/i, - /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007)\b/i - ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [ - - // Vivo - /vivo (\w+)(?: bui|\))/i, - /\b(v[12]\d{3}\w?[at])(?: bui|;)/i - ], [MODEL, [VENDOR, 'Vivo'], [TYPE, MOBILE]], [ - - // Realme - /\b(rmx[12]\d{3})(?: bui|;|\))/i - ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [ - - // Motorola - /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i, - /\bmot(?:orola)?[- ](\w*)/i, - /((?:moto[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i - ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [ - /\b(mz60\d|xoom[2 ]{0,2}) build\//i - ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [ - - // LG - /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i - ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [ - /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i, - /\blg[-e;\/ ]+((?!browser|netcast|android tv)\w+)/i, - /\blg-?([\d\w]+) bui/i - ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [ - - // Lenovo - /(ideatab[-\w ]+)/i, - /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i - ], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [ - - // Nokia - /(?:maemo|nokia).*(n900|lumia \d+)/i, - /nokia[-_ ]?([-\w\.]*)/i - ], [[MODEL, /_/g, ' '], [VENDOR, 'Nokia'], [TYPE, MOBILE]], [ - - // Google - /(pixel c)\b/i // Google Pixel C - ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [ - /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel - ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [ - - // Sony - /droid.+ ([c-g]\d{4}|so[-l]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i - ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [ - /sony tablet [ps]/i, - /\b(?:sony)?sgp\w+(?: bui|\))/i - ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [ - - // OnePlus - / (kb2005|in20[12]5|be20[12][59])\b/i, - /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i - ], [MODEL, [VENDOR, 'OnePlus'], [TYPE, MOBILE]], [ - - // Amazon - /(alexa)webm/i, - /(kf[a-z]{2}wi)( bui|\))/i, // Kindle Fire without Silk - /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD - ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [ - /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone - ], [[MODEL, /(.+)/g, 'Fire Phone $1'], [VENDOR, AMAZON], [TYPE, MOBILE]], [ - - // BlackBerry - /(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook - ], [MODEL, VENDOR, [TYPE, TABLET]], [ - /\b((?:bb[a-f]|st[hv])100-\d)/i, - /\(bb10; (\w+)/i // BlackBerry 10 - ], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [ - - // Asus - /(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i - ], [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], [ - / (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i - ], [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], [ - - // HTC - /(nexus 9)/i // HTC Nexus 9 - ], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [ - /(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, // HTC - - // ZTE - /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i, - /(alcatel|geeksphone|nexian|panasonic|sony)[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony - ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [ - - // Acer - /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i - ], [MODEL, [VENDOR, 'Acer'], [TYPE, TABLET]], [ - - // Meizu - /droid.+; (m[1-5] note) bui/i, - /\bmz-([-\w]{2,})/i - ], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [ - - // Sharp - /\b(sh-?[altvz]?\d\d[a-ekm]?)/i - ], [MODEL, [VENDOR, 'Sharp'], [TYPE, MOBILE]], [ - - // MIXED - /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\w]*)/i, - // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron - /(hp) ([\w ]+\w)/i, // HP iPAQ - /(asus)-?(\w+)/i, // Asus - /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia - /(lenovo)[-_ ]?([-\w]+)/i, // Lenovo - /(jolla)/i, // Jolla - /(oppo) ?([\w ]+) bui/i // OPPO - ], [VENDOR, MODEL, [TYPE, MOBILE]], [ - - /(archos) (gamepad2?)/i, // Archos - /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad - /(kindle)\/([\w\.]+)/i, // Kindle - /(nook)[\w ]+build\/(\w+)/i, // Nook - /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak - /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets - /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets - /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets - /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone - ], [VENDOR, MODEL, [TYPE, TABLET]], [ - - /(surface duo)/i // Surface Duo - ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [ - /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone - ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [ - /(u304aa)/i // AT&T - ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [ - /\bsie-(\w*)/i // Siemens - ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [ - /\b(rct\w+) b/i // RCA Tablets - ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [ - /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets - ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [ - /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet - ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [ - /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet - ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [ - /\b(tm\d{3}\w+) b/i - ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [ - /\b(k88) b/i // ZTE K Series Tablet - ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [ - /\b(nx\d{3}j) b/i // ZTE Nubia - ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [ - /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile - ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [ - /\b(zur\d{3}) b/i // Swiss ZUR Tablet - ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [ - /\b((zeki)?tb.*\b) b/i // Zeki Tablets - ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [ - /\b([yr]\d{2}) b/i, - /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet - ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [ - /\b(ns-?\w{0,9}) b/i // Insignia Tablets - ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [ - /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets - ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [ - /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones - ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [ - /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones - ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [ - /\b(ph-1) /i // Essential PH-1 - ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [ - /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets - ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [ - /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets - ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [ - /\btu_(1491) b/i // Rotor Tablets - ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [ - /(shield[\w ]+) b/i // Nvidia Shield Tablets - ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [ - /(sprint) (\w+)/i // Sprint Phones - ], [VENDOR, MODEL, [TYPE, MOBILE]], [ - /(kin\.[onetw]{3})/i // Microsoft Kin - ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [ - /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra - ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [ - /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i - ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [ - - /////////////////// - // CONSOLES - /////////////////// - - /(ouya)/i, // Ouya - /(nintendo) ([wids3utch]+)/i // Nintendo - ], [VENDOR, MODEL, [TYPE, CONSOLE]], [ - /droid.+; (shield) bui/i // Nvidia - ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [ - /(playstation [345portablevi]+)/i // Playstation - ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [ - /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox - ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [ - - /////////////////// - // SMARTTVS - /////////////////// - - /smart-tv.+(samsung)/i // Samsung - ], [VENDOR, [TYPE, SMARTTV]], [ - /hbbtv.+maple;(\d+)/i - ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [ - /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i // LG SmartTV - ], [[VENDOR, LG], [TYPE, SMARTTV]], [ - /(apple) ?tv/i // Apple TV - ], [VENDOR, [MODEL, APPLE+' TV'], [TYPE, SMARTTV]], [ - /crkey/i // Google Chromecast - ], [[MODEL, CHROME+'cast'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [ - /droid.+aft(\w)( bui|\))/i // Fire TV - ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [ - /\(dtv[\);].+(aquos)/i // Sharp - ], [MODEL, [VENDOR, 'Sharp'], [TYPE, SMARTTV]], [ - /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku - /hbbtv\/\d+\.\d+\.\d+ +\([\w ]*; *(\w[^;]*);([^;]*)/i // HbbTV devices - ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [ - /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i // SmartTV from Unidentified Vendors - ], [[TYPE, SMARTTV]], [ - - /////////////////// - // WEARABLES - /////////////////// - - /((pebble))app/i // Pebble - ], [VENDOR, MODEL, [TYPE, WEARABLE]], [ - /droid.+; (glass) \d/i // Google Glass - ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [ - /droid.+; (wt63?0{2,3})\)/i - ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [ - - /////////////////// - // EMBEDDED - /////////////////// - - /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla - ], [VENDOR, [TYPE, EMBEDDED]], [ - - //////////////////// - // MIXED (GENERIC) - /////////////////// - - /droid .+?; ([^;]+?)(?: bui|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors - ], [MODEL, [TYPE, MOBILE]], [ - /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors - ], [MODEL, [TYPE, TABLET]], [ - /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet - ], [[TYPE, TABLET]], [ - /(phone|mobile(?:[;\/]| safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile - ], [[TYPE, MOBILE]], [ - /(android[-\w\. ]{0,9});.+buil/i // Generic Android Device - ], [MODEL, [VENDOR, 'Generic']] - ], - - engine : [[ - - /windows.+ edge\/([\w\.]+)/i // EdgeHTML - ], [VERSION, [NAME, EDGE+'HTML']], [ - - /webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i // Blink - ], [VERSION, [NAME, 'Blink']], [ - - /(presto)\/([\w\.]+)/i, // Presto - /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna - /ekioh(flow)\/([\w\.]+)/i, // Flow - /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links - /(icab)[\/ ]([23]\.[\d\.]+)/i // iCab - ], [NAME, VERSION], [ - - /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko - ], [VERSION, NAME] - ], - - os : [[ - - // Windows - /microsoft (windows) (vista|xp)/i // Windows (iTunes) - ], [NAME, VERSION], [ - /(windows) nt 6\.2; (arm)/i, // Windows RT - /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, // Windows Phone - /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i - ], [NAME, [VERSION, strMapper, windowsVersionMap]], [ - /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i - ], [[NAME, 'Windows'], [VERSION, strMapper, windowsVersionMap]], [ - - // iOS/macOS - /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS - /cfnetwork\/.+darwin/i - ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [ - /(mac os x) ?([\w\. ]*)/i, - /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS - ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [ - - // Mobile OSes - /droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86 - ], [VERSION, NAME], [ // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS - /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i, - /(blackberry)\w*\/([\w\.]*)/i, // Blackberry - /(tizen|kaios)[\/ ]([\w\.]+)/i, // Tizen/KaiOS - /\((series40);/i // Series 40 - ], [NAME, VERSION], [ - /\(bb(10);/i // BlackBerry 10 - ], [VERSION, [NAME, BLACKBERRY]], [ - /(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i // Symbian - ], [VERSION, [NAME, 'Symbian']], [ - /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS - ], [VERSION, [NAME, FIREFOX+' OS']], [ - /web0s;.+rt(tv)/i, - /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS - ], [VERSION, [NAME, 'webOS']], [ - - // Google Chromecast - /crkey\/([\d\.]+)/i // Google Chromecast - ], [VERSION, [NAME, CHROME+'cast']], [ - /(cros) [\w]+ ([\w\.]+\w)/i // Chromium OS - ], [[NAME, 'Chromium OS'], VERSION],[ - - // Console - /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation - /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S) - - // Other - /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm - /(mint)[\/\(\) ]?(\w*)/i, // Mint - /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux - /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, - // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire - /(hurd|linux) ?([\w\.]*)/i, // Hurd/Linux - /(gnu) ?([\w\.]*)/i, // GNU - /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly - /(haiku) (\w+)/i // Haiku - ], [NAME, VERSION], [ - /(sunos) ?([\w\.\d]*)/i // Solaris - ], [[NAME, 'Solaris'], VERSION], [ - /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris - /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX - /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX - /(unix) ?([\w\.]*)/i // UNIX - ], [NAME, VERSION] - ] - }; - - ///////////////// - // Constructor - //////////////// - - var UAParser = function (ua, extensions) { - - if (typeof ua === OBJ_TYPE) { - extensions = ua; - ua = undefined; + } } - - if (!(this instanceof UAParser)) { - return new UAParser(ua, extensions).getResult(); + i += 2; + } + }, + strMapper = function (str, map) { + for (var i in map) { + // check if current value is array + if (typeof map[i] === OBJ_TYPE && map[i].length > 0) { + for (var j = 0; j < map[i].length; j++) { + if (has(map[i][j], str)) { + return i === UNKNOWN ? undefined : i; + } + } + } else if (has(map[i], str)) { + return i === UNKNOWN ? undefined : i; } - - var _ua = ua || ((typeof window !== UNDEF_TYPE && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); - var _rgxmap = extensions ? extend(regexes, extensions) : regexes; - - this.getBrowser = function () { - var _browser = {}; - _browser[NAME] = undefined; - _browser[VERSION] = undefined; - rgxMapper.call(_browser, _ua, _rgxmap.browser); - _browser.major = majorize(_browser.version); - return _browser; - }; - this.getCPU = function () { - var _cpu = {}; - _cpu[ARCHITECTURE] = undefined; - rgxMapper.call(_cpu, _ua, _rgxmap.cpu); - return _cpu; - }; - this.getDevice = function () { - var _device = {}; - _device[VENDOR] = undefined; - _device[MODEL] = undefined; - _device[TYPE] = undefined; - rgxMapper.call(_device, _ua, _rgxmap.device); - return _device; - }; - this.getEngine = function () { - var _engine = {}; - _engine[NAME] = undefined; - _engine[VERSION] = undefined; - rgxMapper.call(_engine, _ua, _rgxmap.engine); - return _engine; - }; - this.getOS = function () { - var _os = {}; - _os[NAME] = undefined; - _os[VERSION] = undefined; - rgxMapper.call(_os, _ua, _rgxmap.os); - return _os; - }; - this.getResult = function () { - return { - ua : this.getUA(), - browser : this.getBrowser(), - engine : this.getEngine(), - os : this.getOS(), - device : this.getDevice(), - cpu : this.getCPU() - }; - }; - this.getUA = function () { - return _ua; - }; - this.setUA = function (ua) { - _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua; - return this; - }; - this.setUA(_ua); - return this; + } + return str; }; - UAParser.VERSION = LIBVERSION; - UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]); - UAParser.CPU = enumerize([ARCHITECTURE]); - UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]); - UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]); + /////////////// + // String map + ////////////// - /////////// - // Export - ////////// + // Safari < 3.0 + var oldSafariMap = { + "1.0": "/8", + 1.2: "/1", + 1.3: "/3", + "2.0": "/412", + "2.0.2": "/416", + "2.0.3": "/417", + "2.0.4": "/419", + "?": "/" + }, + windowsVersionMap = { + ME: "4.90", + "NT 3.11": "NT3.51", + "NT 4.0": "NT4.0", + 2000: "NT 5.0", + XP: ["NT 5.1", "NT 5.2"], + Vista: "NT 6.0", + 7: "NT 6.1", + 8: "NT 6.2", + 8.1: "NT 6.3", + 10: ["NT 6.4", "NT 10.0"], + RT: "ARM" + }; - // check js environment - if (typeof(exports) !== UNDEF_TYPE) { - // nodejs env - if (typeof module !== UNDEF_TYPE && module.exports) { - exports = module.exports = UAParser; - } - exports.UAParser = UAParser; - } else { - // requirejs env (optional) - if (typeof(define) === FUNC_TYPE && define.amd) { - define(function () { - return UAParser; - }); - } else if (typeof window !== UNDEF_TYPE) { - // browser env - window.UAParser = UAParser; - } + ////////////// + // Regex map + ///////////// + + var regexes = { + browser: [ + [ + /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS + ], + [VERSION, [NAME, "Chrome"]], + [ + /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge + ], + [VERSION, [NAME, "Edge"]], + [ + // Presto based + /(opera mini)\/([-\w\.]+)/i, // Opera Mini + /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, // Opera Mobi/Tablet + /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i // Opera + ], + [NAME, VERSION], + [ + /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0 + ], + [VERSION, [NAME, OPERA + " Mini"]], + [ + /\bopr\/([\w\.]+)/i // Opera Webkit + ], + [VERSION, [NAME, OPERA]], + [ + // Mixed + /(kindle)\/([\w\.]+)/i, // Kindle + /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer + // Trident based + /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser + /(ba?idubrowser)[\/ ]?([\w\.]+)/i, // Baidu Browser + /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer + + // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon + /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq)\/([-\w\.]+)/i, + // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ + /(weibo)__([\d\.]+)/i // Weibo + ], + [NAME, VERSION], + [ + /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser + ], + [VERSION, [NAME, "UC" + BROWSER]], + [ + /\bqbcore\/([\w\.]+)/i // WeChat Desktop for Windows Built-in Browser + ], + [VERSION, [NAME, "WeChat(Win) Desktop"]], + [ + /micromessenger\/([\w\.]+)/i // WeChat + ], + [VERSION, [NAME, "WeChat"]], + [ + /konqueror\/([\w\.]+)/i // Konqueror + ], + [VERSION, [NAME, "Konqueror"]], + [ + /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11 + ], + [VERSION, [NAME, "IE"]], + [ + /yabrowser\/([\w\.]+)/i // Yandex + ], + [VERSION, [NAME, "Yandex"]], + [ + /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser + ], + [[NAME, /(.+)/, "$1 Secure " + BROWSER], VERSION], + [ + /\bfocus\/([\w\.]+)/i // Firefox Focus + ], + [VERSION, [NAME, FIREFOX + " Focus"]], + [ + /\bopt\/([\w\.]+)/i // Opera Touch + ], + [VERSION, [NAME, OPERA + " Touch"]], + [ + /coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser + ], + [VERSION, [NAME, "Coc Coc"]], + [ + /dolfin\/([\w\.]+)/i // Dolphin + ], + [VERSION, [NAME, "Dolphin"]], + [ + /coast\/([\w\.]+)/i // Opera Coast + ], + [VERSION, [NAME, OPERA + " Coast"]], + [ + /miuibrowser\/([\w\.]+)/i // MIUI Browser + ], + [VERSION, [NAME, "MIUI " + BROWSER]], + [ + /fxios\/([-\w\.]+)/i // Firefox for iOS + ], + [VERSION, [NAME, FIREFOX]], + [ + /\bqihu|(qi?ho?o?|360)browser/i // 360 + ], + [[NAME, "360 " + BROWSER]], + [/(oculus|samsung|sailfish)browser\/([\w\.]+)/i], + [[NAME, /(.+)/, "$1 " + BROWSER], VERSION], + [ + // Oculus/Samsung/Sailfish Browser + /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon + ], + [[NAME, /_/g, " "], VERSION], + [ + /(electron)\/([\w\.]+) safari/i, // Electron-based App + /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla + /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/Baidu App/2345 Browser + ], + [NAME, VERSION], + [ + /(metasr)[\/ ]?([\w\.]+)/i, // SouGouBrowser + /(lbbrowser)/i // LieBao Browser + ], + [NAME], + [ + // WebView + /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android + ], + [[NAME, FACEBOOK], VERSION], + [ + /safari (line)\/([\w\.]+)/i, // Line App for iOS + /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android + /(chromium|instagram)[\/ ]([-\w\.]+)/i // Chromium/Instagram + ], + [NAME, VERSION], + [ + /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS + ], + [VERSION, [NAME, "GSA"]], + [ + /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless + ], + [VERSION, [NAME, CHROME + " Headless"]], + [ + / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView + ], + [[NAME, CHROME + " WebView"], VERSION], + [ + /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser + ], + [VERSION, [NAME, "Android " + BROWSER]], + [ + /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia + ], + [NAME, VERSION], + [ + /version\/([\w\.]+) .*mobile\/\w+ (safari)/i // Mobile Safari + ], + [VERSION, [NAME, "Mobile Safari"]], + [ + /version\/([\w\.]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile + ], + [VERSION, NAME], + [ + /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 + ], + [NAME, [VERSION, strMapper, oldSafariMap]], + [/(webkit|khtml)\/([\w\.]+)/i], + [NAME, VERSION], + [ + // Gecko based + /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape + ], + [[NAME, "Netscape"], VERSION], + [ + /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality + ], + [VERSION, [NAME, FIREFOX + " Reality"]], + [ + /ekiohf.+(flow)\/([\w\.]+)/i, // Flow + /(swiftfox)/i, // Swiftfox + /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, + // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar + /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, + // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix + /(firefox)\/([\w\.]+)/i, // Other Firefox-based + /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla + + // Other + /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, + // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser + /(links) \(([\w\.]+)/i // Links + ], + [NAME, VERSION] + ], + + cpu: [ + [ + /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64) + ], + [[ARCHITECTURE, "amd64"]], + [ + /(ia32(?=;))/i // IA32 (quicktime) + ], + [[ARCHITECTURE, lowerize]], + [ + /((?:i[346]|x)86)[;\)]/i // IA32 (x86) + ], + [[ARCHITECTURE, "ia32"]], + [ + /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64 + ], + [[ARCHITECTURE, "arm64"]], + [ + /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF + ], + [[ARCHITECTURE, "armhf"]], + [ + // PocketPC mistakenly identified as PowerPC + /windows (ce|mobile); ppc;/i + ], + [[ARCHITECTURE, "arm"]], + [ + /((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i // PowerPC + ], + [[ARCHITECTURE, /ower/, EMPTY, lowerize]], + [ + /(sun4\w)[;\)]/i // SPARC + ], + [[ARCHITECTURE, "sparc"]], + [ + /((?:avr32|ia64(?=;))|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i + // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC + ], + [[ARCHITECTURE, lowerize]] + ], + + device: [ + [ + ////////////////////////// + // MOBILES & TABLETS + // Ordered by popularity + ///////////////////////// + + // Samsung + /\b(sch-i[89]0\d|shw-m380s|sm-[pt]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i + ], + [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], + [ + /\b((?:s[cgp]h|gt|sm)-\w+|galaxy nexus)/i, + /samsung[- ]([-\w]+)/i, + /sec-(sgh\w+)/i + ], + [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], + [ + // Apple + /((ipod|iphone)\d+,\d+)/i // iPod/iPhone model + ], + [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], + [ + /(ipad\d+,\d+)/i // iPad model + ], + [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], + [ + /\((ip(?:hone|od)[\w ]*);/i // iPod/iPhone + ], + [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], + [ + /\((ipad);[-\w\),; ]+apple/i, // iPad + /applecoremedia\/[\w\.]+ \((ipad)/i, + /\b(ipad)\d\d?,\d\d?[;\]].+ios/i + ], + [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], + [ + // Huawei + /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i + ], + [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], + [ + /(?:huawei|honor)([-\w ]+)[;\)]/i, + /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i + ], + [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], + [ + // Xiaomi + /\b(poco[\w ]+)(?: bui|\))/i, // Xiaomi POCO + /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models + /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi + /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi + /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi + ], + [ + [MODEL, /_/g, " "], + [VENDOR, XIAOMI], + [TYPE, MOBILE] + ], + [ + /\b(mi[-_ ]?(?:pad)(?:[\w_ ]+))(?: bui|\))/i // Mi Pad tablets + ], + [ + [MODEL, /_/g, " "], + [VENDOR, XIAOMI], + [TYPE, TABLET] + ], + [ + // OPPO + /; (\w+) bui.+ oppo/i, + /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i + ], + [MODEL, [VENDOR, "OPPO"], [TYPE, MOBILE]], + [ + // Vivo + /vivo (\w+)(?: bui|\))/i, + /\b(v[12]\d{3}\w?[at])(?: bui|;)/i + ], + [MODEL, [VENDOR, "Vivo"], [TYPE, MOBILE]], + [ + // Realme + /\b(rmx[12]\d{3})(?: bui|;|\))/i + ], + [MODEL, [VENDOR, "Realme"], [TYPE, MOBILE]], + [ + // Motorola + /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i, + /\bmot(?:orola)?[- ](\w*)/i, + /((?:moto[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i + ], + [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], + [/\b(mz60\d|xoom[2 ]{0,2}) build\//i], + [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], + [ + // LG + /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i + ], + [MODEL, [VENDOR, LG], [TYPE, TABLET]], + [ + /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i, + /\blg[-e;\/ ]+((?!browser|netcast|android tv)\w+)/i, + /\blg-?([\d\w]+) bui/i + ], + [MODEL, [VENDOR, LG], [TYPE, MOBILE]], + [ + // Lenovo + /(ideatab[-\w ]+)/i, + /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i + ], + [MODEL, [VENDOR, "Lenovo"], [TYPE, TABLET]], + [ + // Nokia + /(?:maemo|nokia).*(n900|lumia \d+)/i, + /nokia[-_ ]?([-\w\.]*)/i + ], + [ + [MODEL, /_/g, " "], + [VENDOR, "Nokia"], + [TYPE, MOBILE] + ], + [ + // Google + /(pixel c)\b/i // Google Pixel C + ], + [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], + [ + /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel + ], + [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], + [ + // Sony + /droid.+ (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i + ], + [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], + [/sony tablet [ps]/i, /\b(?:sony)?sgp\w+(?: bui|\))/i], + [ + [MODEL, "Xperia Tablet"], + [VENDOR, SONY], + [TYPE, TABLET] + ], + [ + // OnePlus + / (kb2005|in20[12]5|be20[12][59])\b/i, + /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i + ], + [MODEL, [VENDOR, "OnePlus"], [TYPE, MOBILE]], + [ + // Amazon + /(alexa)webm/i, + /(kf[a-z]{2}wi)( bui|\))/i, // Kindle Fire without Silk + /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD + ], + [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], + [ + /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone + ], + [ + [MODEL, /(.+)/g, "Fire Phone $1"], + [VENDOR, AMAZON], + [TYPE, MOBILE] + ], + [ + // BlackBerry + /(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook + ], + [MODEL, VENDOR, [TYPE, TABLET]], + [ + /\b((?:bb[a-f]|st[hv])100-\d)/i, + /\(bb10; (\w+)/i // BlackBerry 10 + ], + [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], + [ + // Asus + /(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i + ], + [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], + [/ (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i], + [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], + [ + // HTC + /(nexus 9)/i // HTC Nexus 9 + ], + [MODEL, [VENDOR, "HTC"], [TYPE, TABLET]], + [ + /(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, // HTC + + // ZTE + /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i, + /(alcatel|geeksphone|nexian|panasonic|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony + ], + [VENDOR, [MODEL, /_/g, " "], [TYPE, MOBILE]], + [ + // Acer + /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i + ], + [MODEL, [VENDOR, "Acer"], [TYPE, TABLET]], + [ + // Meizu + /droid.+; (m[1-5] note) bui/i, + /\bmz-([-\w]{2,})/i + ], + [MODEL, [VENDOR, "Meizu"], [TYPE, MOBILE]], + [ + // Sharp + /\b(sh-?[altvz]?\d\d[a-ekm]?)/i + ], + [MODEL, [VENDOR, "Sharp"], [TYPE, MOBILE]], + [ + // MIXED + /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\w]*)/i, + // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron + /(hp) ([\w ]+\w)/i, // HP iPAQ + /(asus)-?(\w+)/i, // Asus + /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia + /(lenovo)[-_ ]?([-\w]+)/i, // Lenovo + /(jolla)/i, // Jolla + /(oppo) ?([\w ]+) bui/i // OPPO + ], + [VENDOR, MODEL, [TYPE, MOBILE]], + [ + /(archos) (gamepad2?)/i, // Archos + /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad + /(kindle)\/([\w\.]+)/i, // Kindle + /(nook)[\w ]+build\/(\w+)/i, // Nook + /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak + /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets + /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets + /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets + /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone + ], + [VENDOR, MODEL, [TYPE, TABLET]], + [ + /(surface duo)/i // Surface Duo + ], + [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], + [ + /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone + ], + [MODEL, [VENDOR, "Fairphone"], [TYPE, MOBILE]], + [ + /(u304aa)/i // AT&T + ], + [MODEL, [VENDOR, "AT&T"], [TYPE, MOBILE]], + [ + /\bsie-(\w*)/i // Siemens + ], + [MODEL, [VENDOR, "Siemens"], [TYPE, MOBILE]], + [ + /\b(rct\w+) b/i // RCA Tablets + ], + [MODEL, [VENDOR, "RCA"], [TYPE, TABLET]], + [ + /\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets + ], + [MODEL, [VENDOR, "Dell"], [TYPE, TABLET]], + [ + /\b(q(?:mv|ta)\w+) b/i // Verizon Tablet + ], + [MODEL, [VENDOR, "Verizon"], [TYPE, TABLET]], + [ + /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet + ], + [MODEL, [VENDOR, "Barnes & Noble"], [TYPE, TABLET]], + [/\b(tm\d{3}\w+) b/i], + [MODEL, [VENDOR, "NuVision"], [TYPE, TABLET]], + [ + /\b(k88) b/i // ZTE K Series Tablet + ], + [MODEL, [VENDOR, "ZTE"], [TYPE, TABLET]], + [ + /\b(nx\d{3}j) b/i // ZTE Nubia + ], + [MODEL, [VENDOR, "ZTE"], [TYPE, MOBILE]], + [ + /\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile + ], + [MODEL, [VENDOR, "Swiss"], [TYPE, MOBILE]], + [ + /\b(zur\d{3}) b/i // Swiss ZUR Tablet + ], + [MODEL, [VENDOR, "Swiss"], [TYPE, TABLET]], + [ + /\b((zeki)?tb.*\b) b/i // Zeki Tablets + ], + [MODEL, [VENDOR, "Zeki"], [TYPE, TABLET]], + [ + /\b([yr]\d{2}) b/i, + /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet + ], + [[VENDOR, "Dragon Touch"], MODEL, [TYPE, TABLET]], + [ + /\b(ns-?\w{0,9}) b/i // Insignia Tablets + ], + [MODEL, [VENDOR, "Insignia"], [TYPE, TABLET]], + [ + /\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets + ], + [MODEL, [VENDOR, "NextBook"], [TYPE, TABLET]], + [ + /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones + ], + [[VENDOR, "Voice"], MODEL, [TYPE, MOBILE]], + [ + /\b(lvtel\-)?(v1[12]) b/i // LvTel Phones + ], + [[VENDOR, "LvTel"], MODEL, [TYPE, MOBILE]], + [ + /\b(ph-1) /i // Essential PH-1 + ], + [MODEL, [VENDOR, "Essential"], [TYPE, MOBILE]], + [ + /\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets + ], + [MODEL, [VENDOR, "Envizen"], [TYPE, TABLET]], + [ + /\b(trio[-\w\. ]+) b/i // MachSpeed Tablets + ], + [MODEL, [VENDOR, "MachSpeed"], [TYPE, TABLET]], + [ + /\btu_(1491) b/i // Rotor Tablets + ], + [MODEL, [VENDOR, "Rotor"], [TYPE, TABLET]], + [ + /(shield[\w ]+) b/i // Nvidia Shield Tablets + ], + [MODEL, [VENDOR, "Nvidia"], [TYPE, TABLET]], + [ + /(sprint) (\w+)/i // Sprint Phones + ], + [VENDOR, MODEL, [TYPE, MOBILE]], + [ + /(kin\.[onetw]{3})/i // Microsoft Kin + ], + [ + [MODEL, /\./g, " "], + [VENDOR, MICROSOFT], + [TYPE, MOBILE] + ], + [ + /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra + ], + [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], + [/droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i], + [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], + [ + /////////////////// + // CONSOLES + /////////////////// + + /(ouya)/i, // Ouya + /(nintendo) ([wids3utch]+)/i // Nintendo + ], + [VENDOR, MODEL, [TYPE, CONSOLE]], + [ + /droid.+; (shield) bui/i // Nvidia + ], + [MODEL, [VENDOR, "Nvidia"], [TYPE, CONSOLE]], + [ + /(playstation [345portablevi]+)/i // Playstation + ], + [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], + [ + /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox + ], + [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], + [ + /////////////////// + // SMARTTVS + /////////////////// + + /smart-tv.+(samsung)/i // Samsung + ], + [VENDOR, [TYPE, SMARTTV]], + [/hbbtv.+maple;(\d+)/i], + [ + [MODEL, /^/, "SmartTV"], + [VENDOR, SAMSUNG], + [TYPE, SMARTTV] + ], + [ + /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i // LG SmartTV + ], + [ + [VENDOR, LG], + [TYPE, SMARTTV] + ], + [ + /(apple) ?tv/i // Apple TV + ], + [VENDOR, [MODEL, APPLE + " TV"], [TYPE, SMARTTV]], + [ + /crkey/i // Google Chromecast + ], + [ + [MODEL, CHROME + "cast"], + [VENDOR, GOOGLE], + [TYPE, SMARTTV] + ], + [ + /droid.+aft(\w)( bui|\))/i // Fire TV + ], + [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], + [ + /\(dtv[\);].+(aquos)/i // Sharp + ], + [MODEL, [VENDOR, "Sharp"], [TYPE, SMARTTV]], + [ + /(bravia[\w- ]+) bui/i // Sony + ], + [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], + [ + /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku + /hbbtv\/\d+\.\d+\.\d+ +\([\w ]*; *(\w[^;]*);([^;]*)/i // HbbTV devices + ], + [ + [VENDOR, trim], + [MODEL, trim], + [TYPE, SMARTTV] + ], + [ + /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i // SmartTV from Unidentified Vendors + ], + [[TYPE, SMARTTV]], + [ + /////////////////// + // WEARABLES + /////////////////// + + /((pebble))app/i // Pebble + ], + [VENDOR, MODEL, [TYPE, WEARABLE]], + [ + /droid.+; (glass) \d/i // Google Glass + ], + [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], + [/droid.+; (wt63?0{2,3})\)/i], + [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], + [ + /(quest( 2)?)/i // Oculus Quest + ], + [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], + [ + /////////////////// + // EMBEDDED + /////////////////// + + /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla + ], + [VENDOR, [TYPE, EMBEDDED]], + [ + //////////////////// + // MIXED (GENERIC) + /////////////////// + + /droid .+?; ([^;]+?)(?: bui|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors + ], + [MODEL, [TYPE, MOBILE]], + [ + /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors + ], + [MODEL, [TYPE, TABLET]], + [ + /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet + ], + [[TYPE, TABLET]], + [ + /(phone|mobile(?:[;\/]| safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile + ], + [[TYPE, MOBILE]], + [ + /(android[-\w\. ]{0,9});.+buil/i // Generic Android Device + ], + [MODEL, [VENDOR, "Generic"]] + ], + + engine: [ + [ + /windows.+ edge\/([\w\.]+)/i // EdgeHTML + ], + [VERSION, [NAME, EDGE + "HTML"]], + [ + /webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i // Blink + ], + [VERSION, [NAME, "Blink"]], + [ + /(presto)\/([\w\.]+)/i, // Presto + /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna + /ekioh(flow)\/([\w\.]+)/i, // Flow + /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links + /(icab)[\/ ]([23]\.[\d\.]+)/i // iCab + ], + [NAME, VERSION], + [ + /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko + ], + [VERSION, NAME] + ], + + os: [ + [ + // Windows + /microsoft (windows) (vista|xp)/i // Windows (iTunes) + ], + [NAME, VERSION], + [ + /(windows) nt 6\.2; (arm)/i, // Windows RT + /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, // Windows Phone + /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i + ], + [NAME, [VERSION, strMapper, windowsVersionMap]], + [/(win(?=3|9|n)|win 9x )([nt\d\.]+)/i], + [ + [NAME, "Windows"], + [VERSION, strMapper, windowsVersionMap] + ], + [ + // iOS/macOS + /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS + /cfnetwork\/.+darwin/i + ], + [ + [VERSION, /_/g, "."], + [NAME, "iOS"] + ], + [ + /(mac os x) ?([\w\. ]*)/i, + /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS + ], + [ + [NAME, "Mac OS"], + [VERSION, /_/g, "."] + ], + [ + // Mobile OSes + /droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86 + ], + [VERSION, NAME], + [ + // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS + /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i, + /(blackberry)\w*\/([\w\.]*)/i, // Blackberry + /(tizen|kaios)[\/ ]([\w\.]+)/i, // Tizen/KaiOS + /\((series40);/i // Series 40 + ], + [NAME, VERSION], + [ + /\(bb(10);/i // BlackBerry 10 + ], + [VERSION, [NAME, BLACKBERRY]], + [ + /(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i // Symbian + ], + [VERSION, [NAME, "Symbian"]], + [ + /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS + ], + [VERSION, [NAME, FIREFOX + " OS"]], + [ + /web0s;.+rt(tv)/i, + /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS + ], + [VERSION, [NAME, "webOS"]], + [ + // Google Chromecast + /crkey\/([\d\.]+)/i // Google Chromecast + ], + [VERSION, [NAME, CHROME + "cast"]], + [ + /(cros) [\w]+ ([\w\.]+\w)/i // Chromium OS + ], + [[NAME, "Chromium OS"], VERSION], + [ + // Console + /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation + /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S) + + // Other + /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm + /(mint)[\/\(\) ]?(\w*)/i, // Mint + /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux + /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, + // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire + /(hurd|linux) ?([\w\.]*)/i, // Hurd/Linux + /(gnu) ?([\w\.]*)/i, // GNU + /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly + /(haiku) (\w+)/i // Haiku + ], + [NAME, VERSION], + [ + /(sunos) ?([\w\.\d]*)/i // Solaris + ], + [[NAME, "Solaris"], VERSION], + [ + /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris + /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX + /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX + /(unix) ?([\w\.]*)/i // UNIX + ], + [NAME, VERSION] + ] + }; + + ///////////////// + // Constructor + //////////////// + + var UAParser = function (ua, extensions) { + if (typeof ua === OBJ_TYPE) { + extensions = ua; + ua = undefined; } - // jQuery/Zepto specific (optional) - // Note: - // In AMD env the global scope should be kept clean, but jQuery is an exception. - // jQuery always exports to global scope, unless jQuery.noConflict(true) is used, - // and we should catch that. - var $ = typeof window !== UNDEF_TYPE && (window.jQuery || window.Zepto); - if ($ && !$.ua) { - var parser = new UAParser(); - $.ua = parser.getResult(); - $.ua.get = function () { - return parser.getUA(); - }; - $.ua.set = function (ua) { - parser.setUA(ua); - var result = parser.getResult(); - for (var prop in result) { - $.ua[prop] = result[prop]; - } - }; + if (!(this instanceof UAParser)) { + return new UAParser(ua, extensions).getResult(); } -})(typeof window === 'object' ? window : this); + var _ua = + ua || + (typeof window !== UNDEF_TYPE && + window.navigator && + window.navigator.userAgent ? window.navigator.userAgent : EMPTY); + var _rgxmap = extensions ? extend(regexes, extensions) : regexes; + + this.getBrowser = function () { + var _browser = {}; + _browser[NAME] = undefined; + _browser[VERSION] = undefined; + rgxMapper.call(_browser, _ua, _rgxmap.browser); + _browser.major = majorize(_browser.version); + return _browser; + }; + this.getCPU = function () { + var _cpu = {}; + _cpu[ARCHITECTURE] = undefined; + rgxMapper.call(_cpu, _ua, _rgxmap.cpu); + return _cpu; + }; + this.getDevice = function () { + var _device = {}; + _device[VENDOR] = undefined; + _device[MODEL] = undefined; + _device[TYPE] = undefined; + rgxMapper.call(_device, _ua, _rgxmap.device); + return _device; + }; + this.getEngine = function () { + var _engine = {}; + _engine[NAME] = undefined; + _engine[VERSION] = undefined; + rgxMapper.call(_engine, _ua, _rgxmap.engine); + return _engine; + }; + this.getOS = function () { + var _os = {}; + _os[NAME] = undefined; + _os[VERSION] = undefined; + rgxMapper.call(_os, _ua, _rgxmap.os); + return _os; + }; + this.getResult = function () { + return { + ua: this.getUA(), + browser: this.getBrowser(), + engine: this.getEngine(), + os: this.getOS(), + device: this.getDevice(), + cpu: this.getCPU() + }; + }; + this.getUA = function () { + return _ua; + }; + this.setUA = function (ua) { + _ua = + typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua; + return this; + }; + this.setUA(_ua); + return this; + }; + + UAParser.VERSION = LIBVERSION; + UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]); + UAParser.CPU = enumerize([ARCHITECTURE]); + UAParser.DEVICE = enumerize([ + MODEL, + VENDOR, + TYPE, + CONSOLE, + MOBILE, + SMARTTV, + TABLET, + WEARABLE, + EMBEDDED + ]); + UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]); + + /////////// + // Export + ////////// + + // check js environment + if (typeof exports !== UNDEF_TYPE) { + // nodejs env + if (typeof module !== UNDEF_TYPE && module.exports) { + exports = module.exports = UAParser; + } + exports.UAParser = UAParser; + } else { + // requirejs env (optional) + if (typeof define === FUNC_TYPE && define.amd) { + define(function () { + return UAParser; + }); + } else if (typeof window !== UNDEF_TYPE) { + // browser env + window.UAParser = UAParser; + } + } + + // jQuery/Zepto specific (optional) + // Note: + // In AMD env the global scope should be kept clean, but jQuery is an exception. + // jQuery always exports to global scope, unless jQuery.noConflict(true) is used, + // and we should catch that. + var $ = typeof window !== UNDEF_TYPE && (window.jQuery || window.Zepto); + if ($ && !$.ua) { + var parser = new UAParser(); + $.ua = parser.getResult(); + $.ua.get = function () { + return parser.getUA(); + }; + $.ua.set = function (ua) { + parser.setUA(ua); + var result = parser.getResult(); + for (var prop in result) { + $.ua[prop] = result[prop]; + } + }; + } +})(typeof window === "object" ? window : this); diff --git a/test/browser-test.json b/test/browser-test.json index 2f4c2e0..fd413b9 100644 --- a/test/browser-test.json +++ b/test/browser-test.json @@ -189,6 +189,16 @@ "major" : "20" } }, + { + "desc" : "Chrome", + "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4758.102 Safari/537.36", + "expect" : + { + "name" : "Chrome", + "version" : "100.0.4758.102", + "major" : "100" + } + }, { "desc" : "Chrome Headless", "ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome Safari/537.36", @@ -409,6 +419,16 @@ "major" : "15" } }, + { + "desc" : "Firefox", + "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0", + "expect" : + { + "name" : "Firefox", + "version" : "100.0", + "major" : "100" + } + }, { "desc" : "Firefox Reality", "ua" : "Mozilla/5.0 (Android 7.1.2; Mobile VR; rv:65.0) Gecko/65.0 Firefox/65.0", @@ -798,6 +818,16 @@ "major" : "3" } }, + { + "desc" : "Oculus Browser", + "ua" : "Mozilla/5.0 (Linux; Android 10; Quest 2) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/15.0.0.0.22.280317669 SamsungBrowser/4.0 Chrome/89.0.4389.90 VR Safari/537.36", + "expect" : + { + "name" : "Oculus Browser", + "version" : "15.0.0.0.22.280317669", + "major" : "15" + } + }, { "desc" : "OmniWeb", "ua" : "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.48", @@ -1248,6 +1278,16 @@ "major" : "18" } }, + { + "desc" : "Microsoft Edge 100", + "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.1108.55 Safari/537.36 Edg/100.0.1108.55", + "expect" : + { + "name" : "Edge", + "version" : "100.0.1108.55", + "major" : "100" + } + }, { "desc" : "Microsoft Edge on iOS", "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 EdgiOS/42.1.1.0 Mobile/15F79 Safari/605.1.15", @@ -1453,5 +1493,15 @@ "version" : "4.2.7", "major" : "4" } + }, + { + "desc" : "IE11 on Windows 7 (ua length >255)", + "ua" : "Mozilla/5.0 (Windows NT 6.1; WOW64; APCPMS=^N201205020840572565478A37A6F9C41BD33F_9975^; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; MARKANYEPS#25118; Zoom 3.6.0; rv:11.0) like Gecko", + "expect" : + { + "name" : "IE", + "version" : "11.0", + "major" : "11" + } } ] diff --git a/test/device-test.json b/test/device-test.json index 0ef7764..135a5c8 100644 --- a/test/device-test.json +++ b/test/device-test.json @@ -268,6 +268,24 @@ "type": "mobile" } }, + { + "desc": "Huawei Honor 20 Pro", + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L41) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.127 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YAL-L41", + "type": "mobile" + } + }, + { + "desc": "Huawei Honor 20 Pro", + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.127 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YAL-AL10", + "type": "mobile" + } + }, { "desc": "Huawei Nexus 6P", "ua": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6P Build/MTC19V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537", @@ -421,6 +439,42 @@ "type": "mobile" } }, + { + "desc": "Huawei Mate 20 Pro", + "ua": "Mozilla/5.0 (Linux; Android 9; LYA-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.90 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "LYA-AL10", + "type": "mobile" + } + }, + { + "desc": "Huawei Mate 20 Pro", + "ua": "Mozilla/5.0 (Linux; Android 9; LYA-L0C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.90 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "LYA-L0C", + "type": "mobile" + } + }, + { + "desc": "Huawei Mate 20 Pro", + "ua": "Mozilla/5.0 (Linux; Android 9; LYA-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.90 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "LYA-L29", + "type": "mobile" + } + }, + { + "desc": "Huawei Mate 20 Pro", + "ua": "Mozilla/5.0 (Linux; Android 9; LYA-TL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.90 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "LYA-TL00", + "type": "mobile" + } + }, { "desc": "Huawei P20 Lite", "ua": "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.143 Mobile Safari/537.36", @@ -502,6 +556,69 @@ "type": "mobile" } }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YAL-L21", + "type": "mobile" + } + }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L61) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YAL-L61", + "type": "mobile" + } + }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L71) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YAL-L71", + "type": "mobile" + } + }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YAL-L61D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YAL-L61D", + "type": "mobile" + } + }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YALE-L61A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YALE-L61A", + "type": "mobile" + } + }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YALE-L61D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YALE-L61D", + "type": "mobile" + } + }, + { + "desc": "Huawei Nova 5T", + "ua": "Mozilla/5.0 (Linux; Android 10; YALE-L71A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Mobile Safari/537.36", + "expect": { + "vendor": "Huawei", + "model": "YALE-L71A", + "type": "mobile" + } + }, { "desc": "Huawei Enjoy10e", "ua": "Dalvik/2.1.0 (Linux; U; Android 10; MED-AL00 Build/HUAWEIMED-AL00)", @@ -1053,6 +1170,24 @@ "type": "mobile" } }, + { + "desc": "Oculus Quest", + "ua": "Mozilla/5.0 (Linux; Android 10; Quest) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/15.0.0.0.22.280317669 SamsungBrowser/4.0 Chrome/89.0.4389.90 VR Safari/537.36", + "expect": { + "vendor": "Facebook", + "model": "Quest", + "type": "wearable" + } + }, + { + "desc": "Oculus Quest 2", + "ua": "Mozilla/5.0 (Linux; Android 10; Quest 2) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/15.0.0.0.22.280317669 SamsungBrowser/4.0 Chrome/89.0.4389.90 VR Safari/537.36", + "expect": { + "vendor": "Facebook", + "model": "Quest 2", + "type": "wearable" + } + }, { "desc": "OnePlus One", "ua": "Mozilla/5.0 (Linux; Android 4.4.4; A0001 Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.59 Mobile Safari/537.36", @@ -1224,6 +1359,15 @@ "type": "mobile" } }, + { + "desc": "OPPO Reno5 A", + "ua": "Mozilla/5.0 (Linux; Android 11; A101OP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Mobile Safari/537.36", + "expect": { + "vendor": "OPPO", + "model": "A101OP", + "type": "mobile" + } + }, { "desc": "OPPO Find X", "ua": "Mozilla/5.0 (Linux; Android 8.1; PAFM00 Build/OPM1.171019.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", @@ -1575,6 +1719,15 @@ "type": "mobile" } }, + { + "desc": "SONY Xperia 1 III", + "ua": "Mozilla/5.0 (Linux; Android 11; A101SO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36", + "expect": { + "vendor": "Sony", + "model": "A101SO", + "type": "mobile" + } + }, { "desc": "Sony G8141 (Xperia XZ Premium)", "ua": "Mozilla/5.0 (Linux; Android 8.0.0; G8141) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", @@ -1647,6 +1800,15 @@ "type": "mobile" } }, + { + "desc": "Sony Xperia 1ii", + "ua": "Mozilla/5.0 (Linux; Android 10; SOG01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.127 Mobile Safari/537.36", + "expect": { + "vendor": "Sony", + "model": "SOG01", + "type": "mobile" + } + }, { "desc": "Sony Xperia 10ii", "ua": "Mozilla/5.0 (Linux; Android 10; XQ-AU52) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36", @@ -1701,6 +1863,15 @@ "type": "tablet" } }, + { + "desc": "Sony BRAVIA 4K GB ATV3", + "ua": "Mozilla/5.0 (Linux; Andr0id 9; BRAVIA 4K GB ATV3 Build/PTT1.190515.001.S38) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 OPR/46.0.2207.0 OMI/4.13.0.180.DIA5.104 Model/Sony-BRAVIA-4K-GB-ATV3", + "expect": { + "vendor": "Sony", + "model": "BRAVIA 4K GB ATV3", + "type": "smarttv" + } + }, { "desc" : "Tesla", "ua" : "Mozilla/5.0 (X11; GNU/Linux) AppleWebKit/601.1 (KHTML, like Gecko) Tesla QtCarBrowser Safari/601.1", @@ -1847,6 +2018,15 @@ "type": "mobile" } }, + { + "desc": "Xiaomi Mi CC9", + "ua": "Mozilla/5.0 (Linux; U; Android 11; zh-cn; MI CC 9 Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.116 Mobile Safari/537.36 XiaoMi/MiuiBrowser/15.5.18", + "expect": { + "vendor": "Xiaomi", + "model": "MI CC 9", + "type": "mobile" + } + }, { "desc": "Xiaomi MI PAD 2", "ua": "Mozilla/5.0 (Linux; Android 5.1; MI PAD 2 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Safari/537.36 [FB_IAB/FB4A;FBAV/137.0.0.24.91;]", diff --git a/test/test.js b/test/test.js index ad54ef4..fc7ebc5 100644 --- a/test/test.js +++ b/test/test.js @@ -2,6 +2,8 @@ var fs = require('fs'); var safe = require('safe-regex'); var assert = require('assert'); var requirejs = require('requirejs'); +var parseJS = require('@babel/parser').parse; +var traverse = require('@babel/traverse').default; var UAParser = require('./../src/ua-parser'); var browsers = require('./browser-test.json'); var cpus = require('./cpu-test.json'); @@ -107,7 +109,7 @@ describe('Extending Regex', function () { }); describe('User-agent length', function () { - var UA_MAX_LENGTH = 255; + var UA_MAX_LENGTH = 275; // Real data from https://stackoverflow.com/questions/654921/how-big-can-a-user-agent-string-get#answer-6595973 var uaString = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; (R1 1.6); SLCC1; .NET CLR 2.0.50727; InfoPath.2; OfficeLiveConnector.1.3; OfficeLivePatch.0.0; .NET CLR 3.5.30729; .NET CLR 3.0.30618; 66760635803; runtime 11.00294; 876906799603; 97880703; 669602703; 9778063903; 877905603; 89670803; 96690803; 8878091903; 7879040603; 999608065603; 799808803; 6666059903; 669602102803; 888809342903; 696901603; 788907703; 887806555703; 97690214703; 66760903; 968909903; 796802422703; 8868026703; 889803611803; 898706903; 977806408603; 976900799903; 9897086903; 88780803; 798802301603; 9966008603; 66760703; 97890452603; 9789064803; 96990759803; 99960107703; 8868087903; 889801155603; 78890703; 8898070603; 89970603; 89970539603; 89970488703; 8789007603; 87890903; 877904603; 9887077703; 798804903; 97890264603; 967901703; 87890703; 97690420803; 79980706603; 9867086703; 996602846703; 87690803; 6989010903; 977809603; 666601903; 876905337803; 89670603; 89970200903; 786903603; 696901911703; 788905703; 896709803; 96890703; 998601903; 88980703; 666604769703; 978806603; 7988020803; 996608803; 788903297903; 98770043603; 899708803; 66960371603; 9669088903; 69990703; 99660519903; 97780603; 888801803; 9867071703; 79780803; 9779087603; 899708603; 66960456803; 898706824603; 78890299903; 99660703; 9768079803; 977901591603; 89670605603; 787903608603; 998607934903; 799808573903; 878909603; 979808146703; 9996088603; 797803154903; 69790603; 99660565603; 7869028603; 896707703; 97980965603; 976907191703; 88680703; 888809803; 69690903; 889805523703; 899707703; 997605035603; 89970029803; 9699094903; 877906803; 899707002703; 786905857603; 69890803; 97980051903; 997603978803; 9897097903; 66960141703; 7968077603; 977804603; 88980603; 989700803; 999607887803; 78690772803; 96990560903; 98970961603; 9996032903; 9699098703; 69890655603; 978903803; 698905066803; 977806903; 9789061703; 967903747703; 976900550903; 88980934703; 8878075803; 8977028703; 97980903; 9769006603; 786900803; 98770682703; 78790903; 878906967903; 87690399603; 99860976703; 796805703; 87990603; 968906803; 967904724603; 999606603; 988705903; 989702842603; 96790603; 99760703; 88980166703; 9799038903; 98670903; 697905248603; 7968043603; 66860703; 66860127903; 9779048903; 89670123903; 78890397703; 97890603; 87890803; 8789030603; 69990603; 88880763703; 9769000603; 96990203903; 978900405903; 7869022803; 699905422903; 97890703; 87990903; 878908703; 7998093903; 898702507603; 97780637603; 966907903; 896702603; 9769004803; 7869007903; 99660158803; 7899099603; 8977055803; 99660603; 7889080903; 66660981603; 997604603; 6969089803; 899701903; 9769072703; 666603903; 99860803; 997608803; 69790903; 88680756703; 979805677903; 9986047703; 89970803; 66660603; 96690903; 8997051603; 789901209803; 8977098903; 968900326803; 87790703; 98770024803; 697901794603; 69990803; 887805925803; 968908903; 97880603; 897709148703; 877909476903; 66760197703; 977908603; 698902703; 988706504803; 977802026603; 88680964703; 8878068703; 987705107903; 978902878703; 8898069803; 9768031703; 79680803; 79980803; 669609328703; 89870238703; 99960593903; 969904218703; 78890603; 9788000703; 69690630903; 889800982903; 988709748803; 7968052803; 99960007803; 969900800803; 668604817603; 66960903; 78790734603; 8868007703; 79780034903; 8878085903; 976907603; 89670830803; 877900903; 969904889703; 7978033903; 8987043903; 99860703; 979805903; 667603803; 976805348603; 999604127603; 97790701603; 78990342903; 98770672903; 87990253903; 9877027703; 97790803; 877901895603; 8789076903; 896708595603; 997601903; 799806903; 97690603; 87790371703; 667605603; 99760303703; 97680283803; 788902750803; 787909803; 79780603; 79880866903; 9986050903; 87890543903; 979800803; 97690179703; 876901603; 699909903; 96990192603; 878904903; 877904734903; 796801446903; 977904803; 9887044803; 797805565603; 98870789703; 7869093903; 87790727703; 797801232803; 666604803; 9778071903; 9799086703; 6969000903; 89670903; 8799075903; 897708903; 88680903; 97980362603; 97980503903; 889803256703; 88980388703; 789909376803; 69690703; 6969025903; 89970309903; 96690703; 877901847803; 968901903; 96690603; 88680607603; 7889001703; 789904761803; 976807703; 976902903; 878907889703; 9897014903; 896707046603; 696909903; 666603998903; 969902703; 79680421803; 9769075603; 798800192703; 97990903; 9689024903; 668604803; 969908671903; 9996094703; 69990642703; 97890895903; 977805619903; 79980859903; 88980443803; 98970649603; 997602703; 888802169903; 699907803; 667602028803; 786903283903; 997607703; 969909803; 798809925903; 9976045603; 97790903; 9789001903; 966903603; 9789069603; 968906603; 6989091803; 896701603; 6979059803; 978803903; 997606362603; 88980803; 98970803; 88880921703; 8997065703; 899700703; 698908703; 797801027903; 7889050903; 87890603; 78690703; 99660069703; 97980309903; 976800603; 666606803; 898707703; 79880019803; 66960250803; 7978049803; 88780602603; 79680903; 88880792703; 96990903; 667608603; 87790730903; 98970903; 9699032903; 8987004803; 88880703; 89770046603; 978800803; 969908903; 9798022603; 696901903; 799803703; 989703703; 668605903; 79780903; 998601371703; 796803339703; 87890922603; 898708903; 9966061903; 66960891903; 96790903; 8779050803; 98870858803; 976909298603; 9887029903; 669608703; 979806903; 878903803; 99960703; 9789086703; 979801803; 66960008703; 979806830803; 99760212703; 786906603; 797807603; 789907297703; 96990703; 786901603; 796807766603; 896702651603; 789902585603; 66660925903; 9986085703; 66960302703; 69890703; 789900703; 89970903; 9679060703; 9789002903; 979908821603; 986708140803; 976809828703; 7988082803; 79680997903; 99960803; 9788081903; 979805703; 787908603; 66960602803; 9887098703; 978803237703; 888806804603; 999604703; 977904703; 966904635703; 97680291703; 977809345603; 8878046703; 988709803; 976900773603; 989703903; 88780198603; 87790603; 986708703; 78890604703; 87790544803; 976809850903; 887806703; 987707527603; 79880803; 9897059603; 897709820603; 97880804803; 66960026703; 9789062803; 9867090803; 669600603; 8967087703; 78890903; 89770903; 97980703; 976802687603; 66860400803; 979901288603; 96990160903; 99860228903; 966900703; 66760603; 9689035703; 9779064703; 7968023603; 87890791903; 98770870603; 9798005803; 6969087903; 9779097903; 6979065703; 699903252603; 79780989703; 87690901803; 978905763903; 977809703; 97790369703; 899703269603; 8878012703; 78790803; 87690395603; 8888042803; 667607689903; 8977041803; 6666085603; 6999080703; 69990797803; 88680721603; 99660519803; 889807603; 87890146703; 699906325903; 89770603; 669608615903; 9779028803; 88880603; 97790703; 79780703; 97680355603; 6696024803; 78790784703; 97880329903; 9699077703; 89870803; 79680227903; 976905852703; 8997098903; 896704796703; 66860598803; 9897036703; 66960703; 9699094703; 9699008703; 97780485903; 999603179903; 89770834803; 96790445603; 79680460903; 9867009603; 89870328703; 799801035803; 989702903; 66960758903; 66860150803; 6686088603; 9877092803; 96990603; 99860603; 987703663603; 98870903; 699903325603; 87790803; 97680703; 8868030703; 9799030803; 89870703; 97680803; 9669054803; 6979097603; 987708046603; 999608603; 878904803; 998607408903; 968903903; 696900703; 977907491703; 6686033803; 669601803; 99960290603; 887809169903; 979803703; 69890903; 699901447903; 8987064903; 799800603; 98770903; 8997068703; 967903603; 66760146803; 978805087903; 697908138603; 799801603; 88780964903; 989708339903; 8967048603; 88880981603; 789909703; 796806603; 977905977603; 989700603; 97780703; 9669062603; 88980714603; 897709545903; 988701916703; 667604694903; 786905664603; 877900803; 886805490903; 89970559903; 99960531803; 7998033903; 98770803; 78890418703; 669600872803; 996605216603; 78690962703; 667604903; 996600903; 999608903; 9699083803; 787901803; 97780707603; 787905312703; 977805803; 8977033703; 97890708703; 989705521903; 978800703; 698905703; 78890376903; 878907703; 999602903; 986705903; 668602719603; 979901803; 997606903; 66760393903; 987703603; 78790338903; 96890803; 97680596803; 666601603; 977902178803; 877902803; 78790038603; 8868075703; 99960060603)'; @@ -137,12 +139,19 @@ describe('Testing regexes', function () { var regexes; - // todo: use AST-based instead of grep - before('Read main js file', function (done) { - fs.readFile('src/ua-parser.js', 'utf8', function (err, data) { - regexes = data.match(/(\/.+\/[ig]+)(?=[,\s\n])/g); - done(); + before('Read main js file', function () { + var code = fs.readFileSync('src/ua-parser.js', 'utf8').toString(); + var ast = parseJS(code, { sourceType: "script" }); + regexes = []; + traverse(ast, { + RegExpLiteral: (path) => { + regexes.push(path.node.pattern); + } }); + + if (regexes.length === 0) { + throw new Error("Regexes cannot be empty!"); + } }); describe('Begin testing', function () { @@ -156,4 +165,4 @@ describe('Testing regexes', function () { }); }); }); -}) \ No newline at end of file +});