From 5328642e1831e4e7adf6a9dc994e997c63e1bfff Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 8 Jun 2024 01:17:52 +0700 Subject: [PATCH] Update version to `2.0.0-beta.3` --- CHANGELOG.md | 14 +++ README.md | 15 ++- dist/ua-parser.min.js | 6 +- dist/ua-parser.pack.js | 6 +- package-lock.json | 7 +- package.js | 2 +- package.json | 5 +- src/enums/ua-parser-enums.js | 2 +- src/enums/ua-parser-enums.mjs | 23 +++- src/extensions/ua-parser-extensions.d.ts | 2 +- src/extensions/ua-parser-extensions.js | 2 +- src/extensions/ua-parser-extensions.mjs | 142 +++++++++++++++++++---- src/helpers/ua-parser-helpers.d.ts | 2 +- src/helpers/ua-parser-helpers.js | 2 +- src/helpers/ua-parser-helpers.mjs | 2 +- src/main/ua-parser.d.ts | 2 +- src/main/ua-parser.js | 6 +- src/main/ua-parser.mjs | 109 ++++++++++------- 18 files changed, 250 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3541fe62..cc30afa4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,20 @@ - Provided Extensions submodule `'ua-parser-js/extensions'` - Provided Helpers submodule `'ua-parser-js/helpers'` +## Version 2.0.0-beta.3 + +- Breaking: + - AR/VR devices moved to new device type: `xr` + - New property in `browser`: `type` + - In `ua-parser-js/extensions` submodule, `bots` divided into `crawler` / `fetcher` +- New features: + - Parse directly from command line using `npx ua-parser-js` + - Extensions can be passed as a list to `UAParser()` +- Add new browser: Pico Browser, Twitter, Wolvic +- Improve browser detection: DuckDuckGo, ICEBrowser, Klar, QQ, Sleipnir +- Improve device detection: Oculus Quest & Oppo Pad +- Update latest client hints spec: `formFactor` -> `formFactors` + ## Version 2.0.0-beta.2 - Increase UA_MAX_LENGTH to 500 diff --git a/README.md b/README.md index e1afb0594..116870e39 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ # UAParser.js -The most comprehensive, compact, & up-to-date JavaScript library to detect +The most comprehensive, compact, & up-to-date isomorphic JavaScript library to detect user's Browser, Engine, OS, CPU, and Device type/model. Runs either in browser (client-side) or node.js (server-side). @@ -176,11 +176,11 @@ user's Browser, Engine, OS, CPU, and Device type/model. Runs either in browser Price - FREE - FREE - $12 - $25 - $500 + FREE (License) + FREE (License) + $12 (License) + $25 (License) + $500 (License) @@ -205,8 +205,7 @@ see what's new & breaking. ## Contributors -Large or small, your contribution is valuable here. Please read [CONTRIBUTING](CONTRIBUTING.md) -guide first for the instruction details. +Please read [CONTRIBUTING](CONTRIBUTING.md) guide first for the instruction details. diff --git a/dist/ua-parser.min.js b/dist/ua-parser.min.js index f23c2c4e9..8819c5a6f 100644 --- a/dist/ua-parser.min.js +++ b/dist/ua-parser.min.js @@ -1,4 +1,4 @@ -/* UAParser.js v2.0.0-beta.2 - Copyright © 2012-2023 Faisal Salman +/* UAParser.js v2.0.0-beta.3 + Copyright © 2012-2024 Faisal Salman AGPLv3 License */ -(function(window,undefined){"use strict";var LIBVERSION="2.0.0-beta.2",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",USER_AGENT="user-agent",UA_MAX_LENGTH=500,BRANDS="brands",FORMFACTOR="formFactor",FULLVERLIST="fullVersionList",PLATFORM="platform",PLATFORMVER="platformVersion",BITNESS="bitness",CH_HEADER="sec-ch-ua",CH_HEADER_FULL_VER_LIST=CH_HEADER+"-full-version-list",CH_HEADER_ARCH=CH_HEADER+"-arch",CH_HEADER_BITNESS=CH_HEADER+"-"+BITNESS,CH_HEADER_FORM_FACTOR=CH_HEADER+"-form-factor",CH_HEADER_MOBILE=CH_HEADER+"-"+MOBILE,CH_HEADER_MODEL=CH_HEADER+"-"+MODEL,CH_HEADER_PLATFORM=CH_HEADER+"-"+PLATFORM,CH_HEADER_PLATFORM_VER=CH_HEADER_PLATFORM+"-version",CH_ALL_VALUES=[BRANDS,FULLVERLIST,MOBILE,MODEL,PLATFORM,PLATFORMVER,ARCHITECTURE,FORMFACTOR,BITNESS],UA_BROWSER="browser",UA_CPU="cpu",UA_DEVICE="device",UA_ENGINE="engine",UA_OS="os",UA_RESULT="result",AMAZON="Amazon",APPLE="Apple",ASUS="ASUS",BLACKBERRY="BlackBerry",GOOGLE="Google",HUAWEI="Huawei",LENOVO="Lenovo",LG="LG",MICROSOFT="Microsoft",MOTOROLA="Motorola",SAMSUNG="Samsung",SHARP="Sharp",SONY="Sony",XIAOMI="Xiaomi",ZEBRA="Zebra",PREFIX_MOBILE="Mobile ",SUFFIX_BROWSER=" Browser",CHROME="Chrome",EDGE="Edge",FIREFOX="Firefox",OPERA="Opera",FACEBOOK="Facebook",SOGOU="Sogou",WINDOWS="Windows";var isWindow=typeof window!==UNDEF_TYPE,NAVIGATOR=isWindow&&window.navigator?window.navigator:undefined,NAVIGATOR_UADATA=NAVIGATOR&&NAVIGATOR.userAgentData?NAVIGATOR.userAgentData:undefined;var extend=function(regexes,extensions){var mergedRegexes={};for(var i in regexes){mergedRegexes[i]=extensions[i]&&extensions[i].length%2===0?extensions[i].concat(regexes[i]):regexes[i]}return mergedRegexes},enumerize=function(arr){var enums={};for(var i=0;i0){for(var i in str1){if(lowerize(str1[i])==lowerize(str2))return true}return false}return isString(str1)?lowerize(str2).indexOf(lowerize(str1))!==-1:false},isExtensions=function(obj){for(var prop in obj){return/^(browser|cpu|device|engine|os)$/.test(prop)}},isString=function(val){return typeof val===STR_TYPE},itemListToArray=function(header){if(!header)return undefined;var arr=[];var tokens=strip(/\\?\"/g,header).split(",");for(var i=0;i-1){var token=trim(tokens[i]).split(";v=");arr[i]={brand:token[0],version:token[1]}}else{arr[i]=trim(tokens[i])}}return arr},lowerize=function(str){return isString(str)?str.toLowerCase():str},majorize=function(version){return isString(version)?strip(/[^\d\.]/g,version).split(".")[0]:undefined},setProps=function(arr){for(var i in arr){var propName=arr[i];if(typeof propName==OBJ_TYPE&&propName.length==2){this[propName[0]]=propName[1]}else{this[propName]=undefined}}return this},strip=function(pattern,str){return isString(str)?str.replace(pattern,EMPTY):str},stripQuotes=function(str){return strip(/\\?\"/g,str)},trim=function(str,len){if(isString(str)){str=strip(/^\s\s*/,str);return typeof len===UNDEF_TYPE?str:str.substring(0,UA_MAX_LENGTH)}};var rgxMapper=function(ua,arrays){if(!ua||!arrays)return;var i=0,j,k,p,q,matches,match;while(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;j2){this.set(MODEL,"iPad").set(TYPE,TABLET)}break;case UA_OS:if(!this.get(NAME)&&NAVIGATOR_UADATA&&NAVIGATOR_UADATA[PLATFORM]){this.set(NAME,NAVIGATOR_UADATA[PLATFORM])}break;case UA_RESULT:var data=this.data;var detect=function(itemType){return data[itemType].getItem().detectFeature().get()};this.set(UA_BROWSER,detect(UA_BROWSER)).set(UA_CPU,detect(UA_CPU)).set(UA_DEVICE,detect(UA_DEVICE)).set(UA_ENGINE,detect(UA_ENGINE)).set(UA_OS,detect(UA_OS))}}return this};this.parseUA=function(){if(this.itemType!=UA_RESULT){rgxMapper.call(this.data,this.ua,this.rgxMap)}if(this.itemType==UA_BROWSER){this.set(MAJOR,majorize(this.get(VERSION)))}return this};this.parseCH=function(){var uaCH=this.uaCH,rgxMap=this.rgxMap;switch(this.itemType){case UA_BROWSER:var brands=uaCH[FULLVERLIST]||uaCH[BRANDS],prevName;if(brands){for(var i in brands){var brandName=strip(/(Google|Microsoft) /,brands[i].brand||brands[i]),brandVersion=brands[i].version;if(!/not.a.brand/i.test(brandName)&&(!prevName||/chrom/i.test(prevName)&&!/chromi/i.test(brandName))){this.set(NAME,brandName).set(VERSION,brandVersion).set(MAJOR,majorize(brandVersion));prevName=brandName}}}break;case UA_CPU:var archName=uaCH[ARCHITECTURE];if(archName){if(archName&&uaCH[BITNESS]=="64")archName+="64";rgxMapper.call(this.data,archName+";",rgxMap)}break;case UA_DEVICE:if(uaCH[MOBILE]){this.set(TYPE,MOBILE)}if(uaCH[MODEL]){this.set(MODEL,uaCH[MODEL])}if(uaCH[MODEL]=="Xbox"){this.set(TYPE,CONSOLE).set(VENDOR,MICROSOFT)}if(uaCH[FORMFACTOR]){var ff;if(typeof uaCH[FORMFACTOR]!=="string"){var idx=0;while(!ff&&idx=13?"11":"10";this.set(NAME,osName).set(VERSION,osVersion)}if(this.get(NAME)==WINDOWS&&uaCH[MODEL]=="Xbox"){this.set(NAME,"Xbox").set(VERSION,undefined)}break;case UA_RESULT:var data=this.data;var parse=function(itemType){return data[itemType].getItem().setCH(uaCH).parseCH().get()};this.set(UA_BROWSER,parse(UA_BROWSER)).set(UA_CPU,parse(UA_CPU)).set(UA_DEVICE,parse(UA_DEVICE)).set(UA_ENGINE,parse(UA_ENGINE)).set(UA_OS,parse(UA_OS))}return this};setProps.call(this,[["itemType",itemType],["ua",ua],["uaCH",uaCH],["rgxMap",rgxMap],["data",createIData(this,itemType)]]);return this}function UAParser(ua,extensions,headers){if(typeof ua===OBJ_TYPE){if(isExtensions(ua)){if(typeof extensions===OBJ_TYPE){headers=extensions}extensions=ua}else{headers=ua;extensions=undefined}ua=undefined}else if(typeof ua===STR_TYPE&&!isExtensions(extensions)){headers=extensions;extensions=undefined}if(!(this instanceof UAParser)){return new UAParser(ua,extensions,headers).getResult()}var userAgent=typeof ua===STR_TYPE?ua:NAVIGATOR&&NAVIGATOR.userAgent?NAVIGATOR.userAgent:headers&&headers[USER_AGENT]?headers[USER_AGENT]:EMPTY,httpUACH=new UACHData(headers,true),regexMap=extensions?extend(defaultRegexes,extensions):defaultRegexes,createItemFunc=function(itemType){if(itemType==UA_RESULT){return function(){return new UAItem(itemType,userAgent,regexMap,httpUACH).set("ua",userAgent).set(UA_BROWSER,this.getBrowser()).set(UA_CPU,this.getCPU()).set(UA_DEVICE,this.getDevice()).set(UA_ENGINE,this.getEngine()).set(UA_OS,this.getOS()).get()}}else{return function(){return new UAItem(itemType,userAgent,regexMap[itemType],httpUACH).parseUA().get()}}};setProps.call(this,[["getBrowser",createItemFunc(UA_BROWSER)],["getCPU",createItemFunc(UA_CPU)],["getDevice",createItemFunc(UA_DEVICE)],["getEngine",createItemFunc(UA_ENGINE)],["getOS",createItemFunc(UA_OS)],["getResult",createItemFunc(UA_RESULT)],["getUA",function(){return userAgent}],["setUA",function(ua){if(isString(ua))userAgent=ua.length>UA_MAX_LENGTH?trim(ua,UA_MAX_LENGTH):ua;return this}]]).setUA(userAgent);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(isWindow){window.UAParser=UAParser}}var $=isWindow&&(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="2.0.0-beta.3",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",XR="xr",EMBEDDED="embedded",USER_AGENT="user-agent",UA_MAX_LENGTH=500,BRANDS="brands",FORMFACTORS="formFactors",FULLVERLIST="fullVersionList",PLATFORM="platform",PLATFORMVER="platformVersion",BITNESS="bitness",CH_HEADER="sec-ch-ua",CH_HEADER_FULL_VER_LIST=CH_HEADER+"-full-version-list",CH_HEADER_ARCH=CH_HEADER+"-arch",CH_HEADER_BITNESS=CH_HEADER+"-"+BITNESS,CH_HEADER_FORM_FACTORS=CH_HEADER+"-form-factors",CH_HEADER_MOBILE=CH_HEADER+"-"+MOBILE,CH_HEADER_MODEL=CH_HEADER+"-"+MODEL,CH_HEADER_PLATFORM=CH_HEADER+"-"+PLATFORM,CH_HEADER_PLATFORM_VER=CH_HEADER_PLATFORM+"-version",CH_ALL_VALUES=[BRANDS,FULLVERLIST,MOBILE,MODEL,PLATFORM,PLATFORMVER,ARCHITECTURE,FORMFACTORS,BITNESS],UA_BROWSER="browser",UA_CPU="cpu",UA_DEVICE="device",UA_ENGINE="engine",UA_OS="os",UA_RESULT="result",AMAZON="Amazon",APPLE="Apple",ASUS="ASUS",BLACKBERRY="BlackBerry",GOOGLE="Google",HUAWEI="Huawei",LENOVO="Lenovo",LG="LG",MICROSOFT="Microsoft",MOTOROLA="Motorola",SAMSUNG="Samsung",SHARP="Sharp",SONY="Sony",XIAOMI="Xiaomi",ZEBRA="Zebra",PREFIX_MOBILE="Mobile ",SUFFIX_BROWSER=" Browser",CHROME="Chrome",EDGE="Edge",FIREFOX="Firefox",OPERA="Opera",FACEBOOK="Facebook",SOGOU="Sogou",WINDOWS="Windows";var isWindow=typeof window!==UNDEF_TYPE,NAVIGATOR=isWindow&&window.navigator?window.navigator:undefined,NAVIGATOR_UADATA=NAVIGATOR&&NAVIGATOR.userAgentData?NAVIGATOR.userAgentData:undefined;var extend=function(defaultRgx,extensions){var mergedRgx={};var extraRgx=extensions;if(!isExtensions(extensions)){extraRgx={};for(var i in extensions){for(var j in extensions[i]){extraRgx[j]=extensions[i][j].concat(extraRgx[j]?extraRgx[j]:[])}}}for(var k in defaultRgx){mergedRgx[k]=extraRgx[k]&&extraRgx[k].length%2===0?extraRgx[k].concat(defaultRgx[k]):defaultRgx[k]}return mergedRgx},enumerize=function(arr){var enums={};for(var i=0;i0){for(var i in str1){if(lowerize(str1[i])==lowerize(str2))return true}return false}return isString(str1)?lowerize(str2).indexOf(lowerize(str1))!==-1:false},isExtensions=function(obj,deep){for(var prop in obj){return/^(browser|cpu|device|engine|os)$/.test(prop)||(deep?isExtensions(obj[prop]):false)}},isString=function(val){return typeof val===STR_TYPE},itemListToArray=function(header){if(!header)return undefined;var arr=[];var tokens=strip(/\\?\"/g,header).split(",");for(var i=0;i-1){var token=trim(tokens[i]).split(";v=");arr[i]={brand:token[0],version:token[1]}}else{arr[i]=trim(tokens[i])}}return arr},lowerize=function(str){return isString(str)?str.toLowerCase():str},majorize=function(version){return isString(version)?strip(/[^\d\.]/g,version).split(".")[0]:undefined},setProps=function(arr){for(var i in arr){var propName=arr[i];if(typeof propName==OBJ_TYPE&&propName.length==2){this[propName[0]]=propName[1]}else{this[propName]=undefined}}return this},strip=function(pattern,str){return isString(str)?str.replace(pattern,EMPTY):str},stripQuotes=function(str){return strip(/\\?\"/g,str)},trim=function(str,len){if(isString(str)){str=strip(/^\s\s*/,str);return typeof len===UNDEF_TYPE?str:str.substring(0,UA_MAX_LENGTH)}};var rgxMapper=function(ua,arrays){if(!ua||!arrays)return;var i=0,j,k,p,q,matches,match;while(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;j2){this.set(MODEL,"iPad").set(TYPE,TABLET)}break;case UA_OS:if(!this.get(NAME)&&NAVIGATOR_UADATA&&NAVIGATOR_UADATA[PLATFORM]){this.set(NAME,NAVIGATOR_UADATA[PLATFORM])}break;case UA_RESULT:var data=this.data;var detect=function(itemType){return data[itemType].getItem().detectFeature().get()};this.set(UA_BROWSER,detect(UA_BROWSER)).set(UA_CPU,detect(UA_CPU)).set(UA_DEVICE,detect(UA_DEVICE)).set(UA_ENGINE,detect(UA_ENGINE)).set(UA_OS,detect(UA_OS))}}return this};this.parseUA=function(){if(this.itemType!=UA_RESULT){rgxMapper.call(this.data,this.ua,this.rgxMap)}if(this.itemType==UA_BROWSER){this.set(MAJOR,majorize(this.get(VERSION)))}return this};this.parseCH=function(){var uaCH=this.uaCH,rgxMap=this.rgxMap;switch(this.itemType){case UA_BROWSER:var brands=uaCH[FULLVERLIST]||uaCH[BRANDS],prevName;if(brands){for(var i in brands){var brandName=strip(/(Google|Microsoft) /,brands[i].brand||brands[i]),brandVersion=brands[i].version;if(!/not.a.brand/i.test(brandName)&&(!prevName||/chrom/i.test(prevName)&&!/chromi/i.test(brandName))){this.set(NAME,brandName).set(VERSION,brandVersion).set(MAJOR,majorize(brandVersion));prevName=brandName}}}break;case UA_CPU:var archName=uaCH[ARCHITECTURE];if(archName){if(archName&&uaCH[BITNESS]=="64")archName+="64";rgxMapper.call(this.data,archName+";",rgxMap)}break;case UA_DEVICE:if(uaCH[MOBILE]){this.set(TYPE,MOBILE)}if(uaCH[MODEL]){this.set(MODEL,uaCH[MODEL])}if(uaCH[MODEL]=="Xbox"){this.set(TYPE,CONSOLE).set(VENDOR,MICROSOFT)}if(uaCH[FORMFACTORS]){var ff;if(typeof uaCH[FORMFACTORS]!=="string"){var idx=0;while(!ff&&idx=13?"11":"10";this.set(NAME,osName).set(VERSION,osVersion)}if(this.get(NAME)==WINDOWS&&uaCH[MODEL]=="Xbox"){this.set(NAME,"Xbox").set(VERSION,undefined)}break;case UA_RESULT:var data=this.data;var parse=function(itemType){return data[itemType].getItem().setCH(uaCH).parseCH().get()};this.set(UA_BROWSER,parse(UA_BROWSER)).set(UA_CPU,parse(UA_CPU)).set(UA_DEVICE,parse(UA_DEVICE)).set(UA_ENGINE,parse(UA_ENGINE)).set(UA_OS,parse(UA_OS))}return this};setProps.call(this,[["itemType",itemType],["ua",ua],["uaCH",uaCH],["rgxMap",rgxMap],["data",createIData(this,itemType)]]);return this}function UAParser(ua,extensions,headers){if(typeof ua===OBJ_TYPE){if(isExtensions(ua,true)){if(typeof extensions===OBJ_TYPE){headers=extensions}extensions=ua}else{headers=ua;extensions=undefined}ua=undefined}else if(typeof ua===STR_TYPE&&!isExtensions(extensions,true)){headers=extensions;extensions=undefined}if(!(this instanceof UAParser)){return new UAParser(ua,extensions,headers).getResult()}var userAgent=typeof ua===STR_TYPE?ua:NAVIGATOR&&NAVIGATOR.userAgent?NAVIGATOR.userAgent:headers&&headers[USER_AGENT]?headers[USER_AGENT]:EMPTY,httpUACH=new UACHData(headers,true),regexMap=extensions?extend(defaultRegexes,extensions):defaultRegexes,createItemFunc=function(itemType){if(itemType==UA_RESULT){return function(){return new UAItem(itemType,userAgent,regexMap,httpUACH).set("ua",userAgent).set(UA_BROWSER,this.getBrowser()).set(UA_CPU,this.getCPU()).set(UA_DEVICE,this.getDevice()).set(UA_ENGINE,this.getEngine()).set(UA_OS,this.getOS()).get()}}else{return function(){return new UAItem(itemType,userAgent,regexMap[itemType],httpUACH).parseUA().get()}}};setProps.call(this,[["getBrowser",createItemFunc(UA_BROWSER)],["getCPU",createItemFunc(UA_CPU)],["getDevice",createItemFunc(UA_DEVICE)],["getEngine",createItemFunc(UA_ENGINE)],["getOS",createItemFunc(UA_OS)],["getResult",createItemFunc(UA_RESULT)],["getUA",function(){return userAgent}],["setUA",function(ua){if(isString(ua))userAgent=ua.length>UA_MAX_LENGTH?trim(ua,UA_MAX_LENGTH):ua;return this}]]).setUA(userAgent);return this}UAParser.VERSION=LIBVERSION;UAParser.BROWSER=enumerize([NAME,VERSION,MAJOR,TYPE]);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(isWindow){window.UAParser=UAParser}}var $=isWindow&&(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 320b5712a..5b538966c 100644 --- a/dist/ua-parser.pack.js +++ b/dist/ua-parser.pack.js @@ -1,4 +1,4 @@ -/* UAParser.js v2.0.0-beta.2 - Copyright © 2012-2023 Faisal Salman +/* UAParser.js v2.0.0-beta.3 + Copyright © 2012-2024 Faisal Salman AGPLv3 License */ -!function(i,u){"use strict";function e(i){for(var e={},t=0;t_?Ti(i,_):i),this}]]).setUA(o),this}Hi.VERSION="2.0.0-beta.2",Hi.BROWSER=e([f,v,p]),Hi.CPU=e([x]),Hi.DEVICE=e([h,g,m,k,y,t,r,o,a]),Hi.ENGINE=Hi.OS=e([f,v]),typeof exports!==b?(typeof module!==b&&module.exports&&(exports=module.exports=Hi),exports.UAParser=Hi):typeof define===c&&define.amd?define(function(){return Hi}):di&&(i.UAParser=Hi);var Ei,Mi=di&&(i.jQuery||i.Zepto);Mi&&!Mi.ua&&(Ei=new Hi,Mi.ua=Ei.getResult(),Mi.ua.get=function(){return Ei.getUA()},Mi.ua.set=function(i){Ei.setUA(i);var e,t=Ei.getResult();for(e in t)Mi.ua[e]=t[e]})}("object"==typeof window?window:this); \ No newline at end of file +!function(i,c){"use strict";function e(i){for(var e={},t=0;t_?Si(i,_):i),this}]]).setUA(o),this}Ui.VERSION="2.0.0-beta.3",Ui.BROWSER=e([f,v,p,m]),Ui.CPU=e([x]),Ui.DEVICE=e([h,g,m,k,y,t,r,o,a]),Ui.ENGINE=Ui.OS=e([f,v]),typeof exports!==b?(typeof module!==b&&module.exports&&(exports=module.exports=Ui),exports.UAParser=Ui):typeof define===u&&define.amd?define(function(){return Ui}):ui&&(i.UAParser=Ui);var Hi,Ei=ui&&(i.jQuery||i.Zepto);Ei&&!Ei.ua&&(Hi=new Ui,Ei.ua=Hi.getResult(),Ei.ua.get=function(){return Hi.getUA()},Ei.ua.set=function(i){Hi.setUA(i);var e,t=Hi.getResult();for(e in t)Ei.ua[e]=t[e]})}("object"==typeof window?window:this); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 818a3bc68..71498414b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ua-parser-js", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ua-parser-js", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.3", "funding": [ { "type": "opencollective", @@ -22,6 +22,9 @@ } ], "license": "AGPL-3.0-or-later", + "bin": { + "ua-parser-js": "script/cli.js" + }, "devDependencies": { "@babel/parser": "7.15.8", "@babel/traverse": "7.23.2", diff --git a/package.js b/package.js index d58154c96..0ff949d95 100644 --- a/package.js +++ b/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'faisalman:ua-parser-js', - version: '2.0.0-beta.2', + version: '2.0.0-beta.3', summary: 'Lightweight JavaScript-based user-agent string parser', git: 'https://github.com/faisalman/ua-parser-js.git', documentation: 'readme.md' diff --git a/package.json b/package.json index b4d336218..35fb6d143 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UAParser.js", "name": "ua-parser-js", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.3", "author": "Faisal Salman (http://faisalman.com)", "description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment", "keywords": [ @@ -18,7 +18,8 @@ "ua-parser-js", "browser-detection", "device-detection", - "os-detection" + "os-detection", + "bot-detection" ], "homepage": "https://github.com/faisalman/ua-parser-js", "contributors": [ diff --git a/src/enums/ua-parser-enums.js b/src/enums/ua-parser-enums.js index ea1ce8706..e60c4826f 100644 --- a/src/enums/ua-parser-enums.js +++ b/src/enums/ua-parser-enums.js @@ -1,5 +1,5 @@ /////////////////////////////////////////////// -/* Enums for UAParser.js v2.0.0-beta.2 +/* Enums for UAParser.js v2.0.0-beta.3 https://github.com/faisalman/ua-parser-js Author: Faisal Salman AGPLv3 License */ diff --git a/src/enums/ua-parser-enums.mjs b/src/enums/ua-parser-enums.mjs index 756194259..92aa605fd 100644 --- a/src/enums/ua-parser-enums.mjs +++ b/src/enums/ua-parser-enums.mjs @@ -3,7 +3,7 @@ // Source: /src/enums/ua-parser-enums.js /////////////////////////////////////////////// -/* Enums for UAParser.js v2.0.0-beta.2 +/* Enums for UAParser.js v2.0.0-beta.3 https://github.com/faisalman/ua-parser-js Author: Faisal Salman AGPLv3 License */ @@ -54,7 +54,7 @@ const Browser = Object.freeze({ FENNEC: 'Fennec', FLOCK: 'Flock', FLOW: 'Flow', - GO: 'Go Browser', + GO: 'GoBrowser', GOOGLE_SEARCH: 'GSA', HEYTAP: 'HeyTap', HUAWEI: 'Huawei Browser', @@ -108,6 +108,7 @@ const Browser = Object.freeze({ PALEMOON: 'PaleMoon', PHANTOMJS: 'PhantomJS', PHOENIX: 'Phoenix', + PICOBROWSER: 'Pico Browser', POLARIS: 'Polaris', PUFFIN: 'Puffin', QQ: 'QQBrowser', @@ -132,9 +133,9 @@ const Browser = Object.freeze({ TESLA: 'Tesla', TIKTOK: 'TikTok', TIZEN: 'Tizen Browser', + TWITTER: 'Twitter', UC: 'UCBrowser', UP: 'UP.Browser', - VIERA: 'Viera', VIVALDI: 'Vivaldi', VIVO: 'Vivo Browser', W3M: 'w3m', @@ -143,11 +144,21 @@ const Browser = Object.freeze({ WECHAT: 'WeChat', WEIBO: 'Weibo', WHALE: 'Whale', + WOLVIC: 'Wolvic', YANDEX: 'Yandex' // TODO : test! }); +const BrowserType = Object.freeze({ + CRAWLER: 'crawler', + CLI: 'cli', + EMAIL: 'email', + FETCHER: 'fetcher', + INAPP: 'inapp', + MODULE: 'module' +}); + const CPU = Object.freeze({ ARM : 'arm', ARM_64: 'arm64', @@ -175,7 +186,8 @@ const Device = Object.freeze({ MOBILE: 'mobile', SMARTTV: 'smarttv', TABLET: 'tablet', - WEARABLE: 'wearable' + WEARABLE: 'wearable', + XR: 'xr' }); const Vendor = Object.freeze({ @@ -345,7 +357,8 @@ const OS = Object.freeze({ }); export { - Browser, + Browser, + BrowserType, CPU, Device, Vendor, diff --git a/src/extensions/ua-parser-extensions.d.ts b/src/extensions/ua-parser-extensions.d.ts index 893f347c9..5d6f300de 100644 --- a/src/extensions/ua-parser-extensions.d.ts +++ b/src/extensions/ua-parser-extensions.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Helpers submodule of UAParser.js v2.0.0-beta.2 +// Type definitions for Helpers submodule of UAParser.js v2.0.0-beta.3 // Project: https://github.com/faisalman/ua-parser-js // Definitions by: Faisal Salman diff --git a/src/extensions/ua-parser-extensions.js b/src/extensions/ua-parser-extensions.js index 760f5aa25..55a0a0a86 100644 --- a/src/extensions/ua-parser-extensions.js +++ b/src/extensions/ua-parser-extensions.js @@ -1,5 +1,5 @@ /////////////////////////////////////////////// -/* Extensions for UAParser.js v2.0.0-beta.2 +/* Extensions for UAParser.js v2.0.0-beta.3 https://github.com/faisalman/ua-parser-js Author: Faisal Salman AGPLv3 License */ diff --git a/src/extensions/ua-parser-extensions.mjs b/src/extensions/ua-parser-extensions.mjs index e0f9c8acf..9bec89023 100644 --- a/src/extensions/ua-parser-extensions.mjs +++ b/src/extensions/ua-parser-extensions.mjs @@ -3,7 +3,7 @@ // Source: /src/extensions/ua-parser-extensions.js /////////////////////////////////////////////// -/* Extensions for UAParser.js v2.0.0-beta.2 +/* Extensions for UAParser.js v2.0.0-beta.3 https://github.com/faisalman/ua-parser-js Author: Faisal Salman AGPLv3 License */ @@ -18,32 +18,73 @@ const VENDOR = 'vendor'; const VERSION = 'version'; const MOBILE = 'mobile'; const TABLET = 'tablet'; +const CRAWLER = 'crawler'; +const CLI = 'cli'; +const EMAIL = 'email'; +const FETCHER = 'fetcher'; +const INAPP = 'inapp'; +const MODULE = 'module'; -const Apps = Object.freeze({ +////////////////////// +// COMMAND LINE APPS +///////////////////// + +const CLIs = Object.freeze({ browser : [ - [/chatlyio\/([\d\.]+)/i], [VERSION, 'Slack', [TYPE, 'app']] + // wget / curl / lynx + [/(wget|curl|lynx)[\/ ]([\w\.]+)/i], [NAME, VERSION, [TYPE, CLI]] ] }); -const Bots = Object.freeze({ - browser : [ - // Googlebot / BingBot / MSNBot / FacebookBot - [/((?:google|bing|msn|facebook)bot(?:[\-imagevdo]{0,6})|bingpreview)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'bot']], +//////////////////////// +// CRAWLERS / SPIDERS +/////////////////////// +const Crawlers = Object.freeze({ + browser : [ + // Amazonbot - https://developer.amazon.com/amazonbot + // Applebot - http://apple.com/go/applebot + // Bingbot - http://www.bing.com/bingbot.htm + // DuckDuckBot - http://duckduckgo.com/duckduckbot.html + // FacebookBot - https://developers.facebook.com/docs/sharing/bot/ // GPTBot - https://platform.openai.com/docs/gptbot - [/(gptbot)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'bot']], - - // Slackbot - https://api.slack.com/robots - [/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i], [NAME, VERSION, [TYPE, 'bot']] + [/((?:amazon|apple|bing|duckduck|facebook|gpt)bot)\/([\w\.]+)/i], + [NAME, VERSION, [TYPE, CRAWLER]], + + // Baiduspider https://help.baidu.com/question?prod_id=99&class=0&id=3001 + [/(baiduspider)[-imagevdonsfcpr]{0,6}\/([\w\.]+)/i], + [NAME, VERSION, [TYPE, CRAWLER]], + + // Bytespider + // Yahoo! Slurp - http://help.yahoo.com/help/us/ysearch/slurp + [/((?:bytespider|(?=yahoo! )slurp))/i], + [NAME, [TYPE, CRAWLER]], + + // ClaudeBot + [/(claude(?:bot|-web))\/([\w\.]+)/i], + [NAME, VERSION, [TYPE, CRAWLER]], + + // Googlebot - http://www.google.com/bot.html + [ + /(google(?:bot|other)(?:-image|-video|-news|-extended)?|(?:storebot-)?google(?:-inspectiontool)?)\/?([\w\.]*)/i + ], + [NAME, VERSION, [TYPE, CRAWLER]], + + // Sogou Spider + [/(sogou (?:pic|head|web|orion|news) spider)\/([\w\.]+)/i], + [NAME, VERSION, [TYPE, CRAWLER]], + + // Yandex Bots - https://yandex.com/bots + [ + /(yandex(?:(?:mobile)?(?:accessibility|additional|renderresources|screenshot|sprav)?bot|image(?:s|resizer)|video(?:parser)?|blogs|adnet|favicons|fordomain|market|media|metrika|news|ontodb(?:api)?|pagechecker|partner|rca|tracker|turbo|vertis|webmaster|antivirus))\/([\w\.]+)/i + ], + [NAME, VERSION, [TYPE, CRAWLER]] ] }); -const CLIs = Object.freeze({ - browser : [ - // wget / curl / lynx - [/(wget|curl|lynx)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'cli']] - ] -}); +////////////////// +// EXTRA DEVICES +///////////////// const ExtraDevices = Object.freeze({ device : [[ @@ -121,13 +162,63 @@ const ExtraDevices = Object.freeze({ ] }); +/////////////// +// EMAIL APPS +////////////// + const Emails = Object.freeze({ browser : [ - // Microsoft Outlook / Thunderbird - [/(microsoft outlook|thunderbird)[\s\/]([\w\.]+)/i], [NAME, VERSION, [TYPE, 'email']] + // Microsoft Outlook / Thunderbird + [/(microsoft outlook|thunderbird)[\s\/]([\w\.]+)/i], [NAME, VERSION, [TYPE, EMAIL]] ] }); +/////////////////////// +// ON-DEMAND SCRAPERS +////////////////////// + +const Fetchers = Object.freeze({ + browser : [ + // BingPreview / Mastodon / Pinterestbot / Redditbot / Telegrambot / Twitterbot + [/(bingpreview|mastodon|(?:discord|linkedin|pinterest|reddit|telegram|twitter)bot)\/([\w\.]+)/i], + [NAME, VERSION, [TYPE, FETCHER]], + + // Google Bots / Snapchat + [/(feedfetcher-google|google-read-aloud|(?=bot; )snapchat)/i], + [NAME, [TYPE, FETCHER]], + + + // Slackbot - https://api.slack.com/robots + [/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i], + [NAME, VERSION, [TYPE, FETCHER]], + + // WhatsApp + [/(whatsapp)\/([\w\.]+)[\/ ][ianw]/i], + [NAME, VERSION, [TYPE, FETCHER]], + + // Yandex Bots - https://yandex.com/bots + [ + /(yandex(?:calendar|direct(?:dyn)?|searchshop)|yadirectfetcher)\/([\w\.]+)/i, + /(yandex(?:sitelinks|userproxy))/i + ], + [NAME, VERSION, [TYPE, FETCHER]] + ] +}); + +//////////////////// +// IN-APP BROWSERS +/////////////////// + +const InApps = Object.freeze({ + browser : [ + [/chatlyio\/([\d\.]+)/i], [VERSION, 'Slack', [TYPE, INAPP]] + ] +}); + +////////////////////// +// MEDIA PLAYER APPS +///////////////////// + const MediaPlayers = Object.freeze({ browser : [[ @@ -234,19 +325,24 @@ const MediaPlayers = Object.freeze({ ] }); +//////////////////////// +// MODULES / LIBRARIES +/////////////////////// + const Modules = Object.freeze({ browser : [ - // Axios/jsdom/Scrapy - [/\b(axios|jsdom|scrapy)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'module']] + // Axios/jsdom/Scrapy + [/\b(axios|jsdom|scrapy)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, MODULE]] ] }); export { - Apps, - Bots, CLIs, + Crawlers, ExtraDevices, Emails, + Fetchers, + InApps, MediaPlayers, Modules }; \ No newline at end of file diff --git a/src/helpers/ua-parser-helpers.d.ts b/src/helpers/ua-parser-helpers.d.ts index 81023616b..89f64f0cf 100644 --- a/src/helpers/ua-parser-helpers.d.ts +++ b/src/helpers/ua-parser-helpers.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Helpers submodule of UAParser.js v2.0.0-beta.2 +// Type definitions for Helpers submodule of UAParser.js v2.0.0-beta.3 // Project: https://github.com/faisalman/ua-parser-js // Definitions by: Faisal Salman diff --git a/src/helpers/ua-parser-helpers.js b/src/helpers/ua-parser-helpers.js index 17eea7a86..4cbf30eb8 100644 --- a/src/helpers/ua-parser-helpers.js +++ b/src/helpers/ua-parser-helpers.js @@ -1,5 +1,5 @@ /////////////////////////////////////////////// -/* Helpers for UAParser.js v2.0.0-beta.2 +/* Helpers for UAParser.js v2.0.0-beta.3 https://github.com/faisalman/ua-parser-js Author: Faisal Salman AGPLv3 License */ diff --git a/src/helpers/ua-parser-helpers.mjs b/src/helpers/ua-parser-helpers.mjs index d710c2880..cc3533d2b 100644 --- a/src/helpers/ua-parser-helpers.mjs +++ b/src/helpers/ua-parser-helpers.mjs @@ -3,7 +3,7 @@ // Source: /src/helpers/ua-parser-helpers.js /////////////////////////////////////////////// -/* Helpers for UAParser.js v2.0.0-beta.2 +/* Helpers for UAParser.js v2.0.0-beta.3 https://github.com/faisalman/ua-parser-js Author: Faisal Salman AGPLv3 License */ diff --git a/src/main/ua-parser.d.ts b/src/main/ua-parser.d.ts index 0c3594602..2fa75c759 100644 --- a/src/main/ua-parser.d.ts +++ b/src/main/ua-parser.d.ts @@ -1,4 +1,4 @@ -// Type definitions for UAParser.js v2.0.0-beta.2 +// Type definitions for UAParser.js v2.0.0-beta.3 // Project: https://github.com/faisalman/ua-parser-js // Definitions by: Faisal Salman diff --git a/src/main/ua-parser.js b/src/main/ua-parser.js index eda9ba451..a92cb8624 100755 --- a/src/main/ua-parser.js +++ b/src/main/ua-parser.js @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// -/* UAParser.js v2.0.0-beta.2 - Copyright © 2012-2023 Faisal Salman +/* UAParser.js v2.0.0-beta.3 + Copyright © 2012-2024 Faisal Salman AGPLv3 License *//* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Supports browser & node.js environment. @@ -19,7 +19,7 @@ // Constants ///////////// - var LIBVERSION = '2.0.0-beta.2', + var LIBVERSION = '2.0.0-beta.3', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', diff --git a/src/main/ua-parser.mjs b/src/main/ua-parser.mjs index 0f4c2a87b..e0e4f4ed3 100644 --- a/src/main/ua-parser.mjs +++ b/src/main/ua-parser.mjs @@ -3,8 +3,8 @@ // Source: /src/main/ua-parser.js ///////////////////////////////////////////////////////////////////////////////// -/* UAParser.js v2.0.0-beta.2 - Copyright © 2012-2023 Faisal Salman +/* UAParser.js v2.0.0-beta.3 + Copyright © 2012-2024 Faisal Salman AGPLv3 License *//* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Supports browser & node.js environment. @@ -21,7 +21,7 @@ // Constants ///////////// - var LIBVERSION = '2.0.0-beta.2', + var LIBVERSION = '2.0.0-beta.3', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', @@ -40,11 +40,12 @@ TABLET = 'tablet', SMARTTV = 'smarttv', WEARABLE = 'wearable', + XR = 'xr', EMBEDDED = 'embedded', USER_AGENT = 'user-agent', UA_MAX_LENGTH = 500, BRANDS = 'brands', - FORMFACTOR = 'formFactor', + FORMFACTORS = 'formFactors', FULLVERLIST = 'fullVersionList', PLATFORM = 'platform', PLATFORMVER = 'platformVersion', @@ -53,12 +54,12 @@ CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list', CH_HEADER_ARCH = CH_HEADER + '-arch', CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS, - CH_HEADER_FORM_FACTOR = CH_HEADER + '-form-factor', + CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors', CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE, CH_HEADER_MODEL = CH_HEADER + '-' + MODEL, CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM, CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version', - CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTOR, BITNESS], + CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS], UA_BROWSER = 'browser', UA_CPU = 'cpu', UA_DEVICE = 'device', @@ -102,12 +103,21 @@ // Helper ////////// - var extend = function (regexes, extensions) { - var mergedRegexes = {}; - for (var i in regexes) { - mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i]; + var extend = function (defaultRgx, extensions) { + var mergedRgx = {}; + var extraRgx = extensions; + if (!isExtensions(extensions)) { + extraRgx = {}; + for (var i in extensions) { + for (var j in extensions[i]) { + extraRgx[j] = extensions[i][j].concat(extraRgx[j] ? extraRgx[j] : []); + } + } + } + for (var k in defaultRgx) { + mergedRgx[k] = extraRgx[k] && extraRgx[k].length % 2 === 0 ? extraRgx[k].concat(defaultRgx[k]) : defaultRgx[k]; } - return mergedRegexes; + return mergedRgx; }, enumerize = function (arr) { var enums = {}; @@ -125,9 +135,9 @@ } return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; }, - isExtensions = function (obj) { + isExtensions = function (obj, deep) { for (var prop in obj) { - return /^(browser|cpu|device|engine|os)$/.test(prop); + return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false); } }, isString = function (val) { @@ -271,12 +281,13 @@ 'RT' : 'ARM' }, - formFactorMap = { + formFactorsMap = { 'embedded' : 'Automotive', 'mobile' : 'Mobile', 'tablet' : ['Tablet', 'EInk'], 'smarttv' : 'TV', - 'wearable' : ['VR', 'XR', 'Watch'], + 'wearable' : 'Watch', + 'xr' : ['VR', 'XR'], '?' : ['Desktop', 'Unknown'], '*' : undefined }; @@ -311,17 +322,20 @@ /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu ], [VERSION, [NAME, 'Baidu']], [ /(kindle)\/([\w\.]+)/i, // Kindle - /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer + /(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i, + // Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir // Trident based /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser /(?: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(?!.+naver)|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i, - // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo + /(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, + // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi /(weibo)__([\d\.]+)/i // Weibo ], [NAME, VERSION], [ + /\bddg\/([\w\.]+)/i // DuckDuckGo + ], [VERSION, [NAME, 'DuckDuckGo']], [ /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser ], [VERSION, [NAME, 'UCBrowser']], [ /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser @@ -354,8 +368,10 @@ ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [ /\bqihu|(qi?ho?o?|360)browser/i // 360 ], [[NAME, '360' + SUFFIX_BROWSER]], [ - /(oculus|sailfish|huawei|vivo)browser\/([\w\.]+)/i - ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser + /\b(qq)\/([\w\.]+)/i // QQ + ], [[NAME, /(.+)/, '$1Browser'], VERSION], [ + /(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i + ], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser /samsungbrowser\/([\w\.]+)/i // Samsung Internet ], [VERSION, [NAME, SAMSUNG + ' Internet']], [ /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon @@ -368,7 +384,7 @@ /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser ], [NAME, VERSION], [ - /(lbbrowser)/i, // LieBao Browser + /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq /\[(linkedin)app\]/i // LinkedIn App for iOS & Android ], [NAME], [ @@ -381,6 +397,7 @@ /safari (line)\/([\w\.]+)/i, // Line App for iOS /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android /(alipay)client\/([\w\.]+)/i, // Alipay + /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat ], [NAME, VERSION], [ /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS @@ -420,23 +437,24 @@ ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [ /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape ], [[NAME, 'Netscape'], VERSION], [ + /(wolvic)\/([\w\.]+)/i // Wolvic + ], [NAME, 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 + /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i, + // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror /(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 - /panasonic;(viera)/i // Panasonic Viera - ], [NAME, VERSION], [ + /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, + // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser + /(links) \(([\w\.]+)/i // Links + ], [NAME, [VERSION, /_/g, '.']], [ /(cobalt)\/([\w\.]+)/i // Cobalt ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]] @@ -523,6 +541,8 @@ /; (\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]], [ + /\b(opd2\d{3}a?) bui/i + ], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [ // Vivo /vivo (\w+)(?: bui|\))/i, @@ -706,12 +726,17 @@ ], [VENDOR, MODEL, [TYPE, WEARABLE]], [ /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch ], [MODEL, [VENDOR, APPLE], [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| pro)?)/i // Oculus Quest - ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [ + + /////////////////// + // XR + /////////////////// + + /droid.+; (glass) \d/i // Google Glass + ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [ + /(quest( \d| pro)?)/i // Oculus Quest + ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [ /////////////////// // EMBEDDED @@ -842,7 +867,7 @@ var defaultProps = (function () { var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}}; setProps.call(props.init, [ - [UA_BROWSER, [NAME, VERSION, MAJOR]], + [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]], [UA_CPU, [ARCHITECTURE]], [UA_DEVICE, [TYPE, MODEL, VENDOR]], [UA_ENGINE, [NAME, VERSION]], @@ -970,7 +995,7 @@ [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])], [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])], [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])], - [FORMFACTOR, itemListToArray(uach[CH_HEADER_FORM_FACTOR])], + [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])], [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])] ]); } else { @@ -1090,15 +1115,15 @@ this.set(TYPE, CONSOLE) .set(VENDOR, MICROSOFT); } - if (uaCH[FORMFACTOR]) { + if (uaCH[FORMFACTORS]) { var ff; - if (typeof uaCH[FORMFACTOR] !== 'string') { + if (typeof uaCH[FORMFACTORS] !== 'string') { var idx = 0; - while (!ff && idx < uaCH[FORMFACTOR].length) { - ff = strMapper(uaCH[FORMFACTOR][idx++], formFactorMap); + while (!ff && idx < uaCH[FORMFACTORS].length) { + ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap); } } else { - ff = strMapper(uaCH[FORMFACTOR], formFactorMap); + ff = strMapper(uaCH[FORMFACTORS], formFactorsMap); } this.set(TYPE, ff); } @@ -1149,7 +1174,7 @@ function UAParser (ua, extensions, headers) { if (typeof ua === OBJ_TYPE) { - if (isExtensions(ua)) { + if (isExtensions(ua, true)) { if (typeof extensions === OBJ_TYPE) { headers = extensions; // case UAParser(extensions, headers) } @@ -1159,7 +1184,7 @@ extensions = undefined; } ua = undefined; - } else if (typeof ua === STR_TYPE && !isExtensions(extensions)) { + } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) { headers = extensions; // case UAParser(ua, headers) extensions = undefined; } @@ -1220,7 +1245,7 @@ } UAParser.VERSION = LIBVERSION; - UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]); + UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]); UAParser.CPU = enumerize([ARCHITECTURE]); UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]); UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);