From 30de983043dc44e24980c4983bb4f0f250084226 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Wed, 29 Mar 2023 10:44:37 +0700 Subject: [PATCH] Alpha release of v2.0 --- bower.json | 2 +- changelog.md | 68 +++++++---- dist/ua-parser.min.js | 6 +- dist/ua-parser.pack.js | 6 +- package.js | 2 +- package.json | 20 ++-- readme.md | 109 ++++++++++-------- src/{ => enum}/ua-parser-enum.js | 2 +- src/{ => enum}/ua-parser-enum.mjs | 6 +- src/{ => extension}/ua-parser-extension.js | 3 +- src/extension/ua-parser-extension.mjs | 124 +++++++++++++++++++++ src/ua-parser-extension.mjs | 36 ------ src/ua-parser.js | 6 +- src/ua-parser.mjs | 73 ++---------- test/cpu-test.json | 8 ++ test/{es6-test.mjs => test-es6.mjs} | 2 +- 16 files changed, 279 insertions(+), 194 deletions(-) rename src/{ => enum}/ua-parser-enum.js (98%) rename src/{ => enum}/ua-parser-enum.mjs (94%) rename src/{ => extension}/ua-parser-extension.js (98%) create mode 100644 src/extension/ua-parser-extension.mjs delete mode 100644 src/ua-parser-extension.mjs rename test/{es6-test.mjs => test-es6.mjs} (84%) diff --git a/bower.json b/bower.json index c59773a..05b8579 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "ua-parser-js", - "version": "0.7.33", + "version": "2.0.0-alpha.1", "authors": [ "Faisal Salman " ], diff --git a/changelog.md b/changelog.md index addaff4..a4aa6f1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,27 +1,42 @@ # UAParser.js Changelog +# Version 2.0.0-alpha.1 +- Breaking changes: + - Browser detection on mobile device: `Chrome => Mobile Chrome`, `Firefox => Mobile Firefox` + - OS detection: `Mac OS => macOS`, `Chromium OS => Chrome OS` +- Add some new methods in result object: + - Add support for client hints: `withClientHints()` + - Utility for easy comparison: `is()` + - Utility to print full-name: `toString()` +- Add support for ES module `import { UAParser } from 'ua-parser-js'` +- Provide Enums `'ua-parser-js/enums'` +- Provide Extensions `'ua-parser-js/extensions'` +- Add new browser: Heytap, TikTok +- Add new engine: LibWeb +- Add new OS: SerenityOS +- Improve browser detection: Yandex +- Improve device detection: iPhone, Amazon Echo +- Improve OS detection: iOS + # Version 0.7 / 1.0 Version 1.0.x is basically the equivalent of version 0.7.x. See [#536](https://github.com/faisalman/ua-parser-js/issues/536) for the reason behind this confusion. -## Version 0.7.30 / 1.0.1 +## Version 0.7.34 / 1.0.34 +- Fix Sharp Mobile detected as Huawei Tablet +- Fix IE8 bug +- Add new devices : Kobo e-Reader, Apple Watch, and some new SmartTV devices +- Add new OS : watchOS +- Improve browser detection : Kakao, Naver, Brave +- Improve device detection : Oculus, iPad +- Improve OS detection : Chrome OS +- Using navigator.userAgentData as fallback for device.type & os.name -- Add new browser : Obigo, UP.Browser, Klar -- Add new device : Oculus, Roku -- Add new OS: Maemo, HP-UX, Android-x86, Deepin, elementary OS, GhostBSD, Linspire, Manjaro, Sabayon -- Improve detection for Sony Xperia 1ii, LG Android TV, and some more devices -- Improve detection for ARM64 CPU -- Improve detection for Windows Mobile, Netscape, Mac on PowerPC -- Categorize PDA as mobile -- Fix Sharp devices misjudged as Huawei -- Fix trailing comma for ES3 compatibility -- Some code refactor +## Version 0.7.33 / 1.0.33 -## Version 0.7.31 / 1.0.2 - -- Fix OPPO Reno A5 incorrect detection -- Fix TypeError Bug -- Use AST to extract regexes and verify them with safe-regex +- Add new browser : Cobalt +- Identify Macintosh as an Apple device +- Fix ReDoS vulnerability ## Version 0.7.32 / 1.0.32 @@ -38,11 +53,24 @@ Version 1.0.x is basically the equivalent of version 0.7.x. See [#536](https://g - Fix included commas in Safari / Mobile Safari version - Increase UA_MAX_LENGTH to 350 -## Version 0.7.33 / 1.0.33 +## Version 0.7.31 / 1.0.2 -- Add new browser : Cobalt -- Identify Macintosh as an Apple device -- Fix ReDoS vulnerability +- Fix OPPO Reno A5 incorrect detection +- Fix TypeError Bug +- Use AST to extract regexes and verify them with safe-regex + +## Version 0.7.30 / 1.0.1 + +- Add new browser : Obigo, UP.Browser, Klar +- Add new device : Oculus, Roku +- Add new OS: Maemo, HP-UX, Android-x86, Deepin, elementary OS, GhostBSD, Linspire, Manjaro, Sabayon +- Improve detection for Sony Xperia 1ii, LG Android TV, and some more devices +- Improve detection for ARM64 CPU +- Improve detection for Windows Mobile, Netscape, Mac on PowerPC +- Categorize PDA as mobile +- Fix Sharp devices misjudged as Huawei +- Fix trailing comma for ES3 compatibility +- Some code refactor # Version 0.8 diff --git a/dist/ua-parser.min.js b/dist/ua-parser.min.js index 71c56fb..2936c2e 100644 --- a/dist/ua-parser.min.js +++ b/dist/ua-parser.min.js @@ -1,4 +1,4 @@ -/* UAParser.js v1.1.34 - Copyright © 2012-2021 Faisal Salman +/* UAParser.js v2.0.0-alpha.1 + Copyright © 2012-2023 Faisal Salman MIT License */ -(function(window,undefined){"use strict";var LIBVERSION="0.7.32",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=350;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",SHARP="Sharp",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); +(function(window,undefined){"use strict";var LIBVERSION="2.0.0-alpha.1",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=350,BRANDS="brands",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_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","fullVersionList",MOBILE,MODEL,"platform","platformVersion",ARCHITECTURE,"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",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",WINDOWS="Windows";var NAVIGATOR=typeof window!==UNDEF_TYPE&&window.navigator?window.navigator:undefined,NAVIGATOR_UADATA=NAVIGATOR&&NAVIGATOR.userAgentData?NAVIGATOR.userAgentData:undefined;var assignFromEntries=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},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 typeof str1===STR_TYPE?lowerize(str2).indexOf(lowerize(str1))!==-1:false},isExtensions=function(obj){for(var prop in obj){return/^(browser|cpu|device|engine|os)$/.test(prop)}},itemListToArray=function(header){if(!header)return undefined;var arr=[];var tokens=strip(/\\?\"/g,header).split(", ");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;j2){this.set(MODEL,"iPad").set(TYPE,TABLET)}break;case UA_OS:if(!this.get(NAME)&&NAVIGATOR_UADATA&&NAVIGATOR_UADATA[PLATFORM]&&NAVIGATOR_UADATA[PLATFORM]!="Unknown"){this.set(NAME,NAVIGATOR_UADATA[PLATFORM])}break;case UA_RESULT:var createUAParserItem=function(itemType){return new UAParserItem(itemType,ua,rgxMap[itemType],uaCH).get()};this.set("ua",ua).set(UA_BROWSER,createUAParserItem(UA_BROWSER)).set(UA_CPU,createUAParserItem(UA_CPU)).set(UA_DEVICE,createUAParserItem(UA_DEVICE)).set(UA_ENGINE,createUAParserItem(UA_ENGINE)).set(UA_OS,createUAParserItem(UA_OS)).get()}return this}UAParserItem.prototype.get=function(prop){if(!prop)return this.data;return this.data.hasOwnProperty(prop)?this.data[prop]:undefined};UAParserItem.prototype.parse=function(){if(this.itemType!=UA_RESULT){rgxMapper.call(this.data,this.ua,this.rgxMap)}return this};UAParserItem.prototype.parseCH=function(){var ua=this.ua,uaCH=this.uaCH,rgxMap=this.rgxMap;switch(this.itemType){case UA_BROWSER:var brands=uaCH[FULLVERLIST]||uaCH[BRANDS];if(brands){for(var i in brands){var brandName=brands[i].brand,brandVersion=brands[i].version;if(!/not.a.brand/i.test(brandName)||/chromi/i.test(this.get(NAME))){this.set(NAME,strip(GOOGLE+" ",brandName)).set(VERSION,brandVersion).set(MAJOR,majorize(brandVersion))}}}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])}break;case UA_OS:var osName=uaCH[PLATFORM];if(osName){var osVersion=uaCH[PLATFORMVER];if(osName==WINDOWS)osVersion=parseInt(majorize(osVersion),10)>=13?"11":"10";this.set(NAME,osName).set(VERSION,osVersion)}break;case UA_RESULT:var createUAParserItemWithCH=function(itemType){return new UAParserItem(itemType,ua,rgxMap[itemType],uaCH).parseCH().get()};this.set("ua",ua).set(UA_BROWSER,createUAParserItemWithCH(UA_BROWSER)).set(UA_CPU,createUAParserItemWithCH(UA_CPU)).set(UA_DEVICE,createUAParserItemWithCH(UA_DEVICE)).set(UA_ENGINE,createUAParserItemWithCH(UA_ENGINE)).set(UA_OS,createUAParserItemWithCH(UA_OS))}return this};UAParserItem.prototype.set=function(prop,val){this.data[prop]=val;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=ua||(NAVIGATOR&&NAVIGATOR.userAgent?NAVIGATOR.userAgent:headers&&headers[USER_AGENT]?headers[USER_AGENT]:EMPTY),HTTP_UACH=new UAParserDataCH(headers,true),regexMap=extensions?extend(defaultRegexes,extensions):defaultRegexes,createUAParserItemFunc=function(itemType){return function(){return new UAParserItem(itemType,userAgent,itemType==UA_RESULT?regexMap:regexMap[itemType],HTTP_UACH).get()}};assignFromEntries.call(this,[["getBrowser",createUAParserItemFunc(UA_BROWSER)],["getCPU",createUAParserItemFunc(UA_CPU)],["getDevice",createUAParserItemFunc(UA_DEVICE)],["getEngine",createUAParserItemFunc(UA_ENGINE)],["getOS",createUAParserItemFunc(UA_OS)],["getResult",createUAParserItemFunc(UA_RESULT)],["getUA",function(){return userAgent}],["setUA",function(ua){userAgent=typeof ua===STR_TYPE&&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(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 9318cbc..c5d1e9c 100644 --- a/dist/ua-parser.pack.js +++ b/dist/ua-parser.pack.js @@ -1,4 +1,4 @@ -/* UAParser.js v1.1.34 - Copyright © 2012-2021 Faisal Salman +/* UAParser.js v2.0.0-alpha.1 + Copyright © 2012-2023 Faisal Salman MIT License */ -!function(a,d){"use strict";function i(i){for(var e={},o=0;oS?L(i,S):i,this},this.setUA(o),this}Q.prototype.is=function(i){for(var e in this.propIs)if(o(this[this.propIs[e]],this.rgxIs)==o(i,this.rgxIs))return!0;return!1},Q.prototype.toString=function(){var i,e="";for(i in this.propToString)typeof this[this.propToString[i]]!==s&&(e+=(e?" ":"")+this[this.propToString[i]]);return e||s},Y.prototype=new Q([l,h],[[l],/\s?browser$/i]),J.prototype=new Q([f],[[f]]),ii.prototype=new Q([m,r],[[p,r,m]]),ei.prototype=new Q([l,h],[[l]]),oi.prototype=new Q([l,h],[[l],/\s?os$/i]),ti.VERSION="0.7.32",ti.BROWSER=i([l,h,w]),ti.CPU=i([f]),ti.DEVICE=i([r,m,p,g,v,k,x,y,_]),ti.ENGINE=ti.OS=i([l,h]),typeof exports!==s?(typeof module!==s&&module.exports&&(exports=module.exports=ti),exports.UAParser=ti):typeof define==u&&define.amd?define(function(){return ti}):typeof a!==s&&(a.UAParser=ti);var ai,ni=typeof a!==s&&(a.jQuery||a.Zepto);ni&&!ni.ua&&(ai=new ti,ni.ua=ai.getResult(),ni.ua.get=function(){return ai.getUA()},ni.ua.set=function(i){ai.setUA(i);var e,o=ai.getResult();for(e in o)ni.ua[e]=o[e]})}("object"==typeof window?window:this); +!function(i,u){"use strict";function e(i){for(var e={},t=0;tS?yi(i,S):i,this}]]).setUA(o),this}Ni.prototype.get=function(i){return i?this.data.hasOwnProperty(i)?this.data[i]:u:this.data},Ni.prototype.parse=function(){return this.itemType!=L&&w.call(this.data,this.ua,this.rgxMap),this},Ni.prototype.parseCH=function(){var e=this.ua,t=this.uaCH,o=this.rgxMap;switch(this.itemType){case V:var i=t[C]||t[q];if(i)for(var r in i){var a=i[r].brand,r=i[r].version;/not.a.brand/i.test(a)&&!/chromi/i.test(this.get(m))||this.set(m,xi(K+" ",a)).set(v,r).set(h,vi(r))}break;case B:var s=t[x];s&&(s&&"64"==t[A]&&(s+="64"),w.call(this.data,s+";",o));break;case F:t[k]&&this.set(g,k),t[f]&&this.set(f,t[f]);break;case D:s=t[N];s&&(n=t[z],s==ui&&(n=13<=parseInt(vi(n),10)?"11":"10"),this.set(m,s).set(v,n));break;case L:var n=function(i){return new Ni(i,e,o[i],t).parseCH().get()};this.set("ua",e).set(V,n(V)).set(B,n(B)).set(F,n(F)).set($,n($)).set(D,n(D))}return this},Ni.prototype.set=function(i,e){return this.data[i]=e,this},zi.VERSION="2.0.0-alpha.1",zi.BROWSER=e([m,v,h]),zi.CPU=e([x]),zi.DEVICE=e([f,o,g,r,k,n,a,y,_]),zi.ENGINE=zi.OS=e([m,v]),typeof exports!==d?(typeof module!==d&&module.exports&&(exports=module.exports=zi),exports.UAParser=zi):typeof define===c&&define.amd?define(function(){return zi}):typeof i!==d&&(i.UAParser=zi);var Ai,Oi=typeof i!==d&&(i.jQuery||i.Zepto);Oi&&!Oi.ua&&(Ai=new zi,Oi.ua=Ai.getResult(),Oi.ua.get=function(){return Ai.getUA()},Oi.ua.set=function(i){Ai.setUA(i);var e,t=Ai.getResult();for(e in t)Oi.ua[e]=t[e]})}("object"==typeof window?window:this); \ No newline at end of file diff --git a/package.js b/package.js index a3bcdb3..3f2ddf1 100644 --- a/package.js +++ b/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'faisalman:ua-parser-js', - version: '0.7.33', + version: '2.0.0-alpha.1', 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 e10152a..37191dc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UAParser.js", "name": "ua-parser-js", - "version": "0.7.33", + "version": "2.0.0-alpha.1", "author": "Faisal Salman (http://faisalman.com)", "description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Supports browser & node.js environment", "keywords": [ @@ -139,22 +139,22 @@ "yuanyang ", "Yun Young-jin ", "Zach Bjornson " - ], + ], "type": "commonjs", "main": "src/ua-parser.js", "module": "src/ua-parser.mjs", "exports": { - "." : { + ".": { "require": "./src/ua-parser.js", "import": "./src/ua-parser.mjs" }, - "./enums" : { - "require": "./src/ua-parser-enum.js", - "import": "./src/ua-parser-enum.mjs" + "./enums": { + "require": "./src/enum/ua-parser-enum.js", + "import": "./src/enum/ua-parser-enum.mjs" }, - "./extensions" : { - "require": "./src/ua-parser-extension.js", - "import": "./src/ua-parser-extension.mjs" + "./extensions": { + "require": "./src/extension/ua-parser-extension.js", + "import": "./src/extension/ua-parser-extension.mjs" } }, "files": [ @@ -162,7 +162,7 @@ "src" ], "scripts": { - "build": "uglifyjs src/ua-parser.js -o dist/ua-parser.min.js --comments '/^ UA/' && uglifyjs src/ua-parser.js -o dist/ua-parser.pack.js --comments '/^ UA/' --compress --mangle && uglifyjs src/ua-parser-enum.js -o dist/ua-parser-enum.min.js --comments '/^ Enum/' && node -e \"const fs=require('fs');fs.writeFileSync('src/ua-parser.mjs','// Generated ESM version of UAParser.js\\n// DO NOT EDIT THIS FILE!\\n// Source: /src/ua-parser.js\\n\\nconst window = undefined;\\n\\n'+fs.readFileSync('src/ua-parser.js','utf-8').replace(/\\(func[\\s\\S]+strict\\';/ig,'').replace(/\\/[\\/\\s]+export[\\s\\S]+/ig,'export {UAParser};'),'utf-8');fs.writeFileSync('src/ua-parser-enum.mjs','// Generated ESM version of UAParser.js enums\\n// DO NOT EDIT THIS FILE!\\n// Source: /src/ua-parser-enum.js\\n\\n'+fs.readFileSync('src/ua-parser-enum.js','utf-8').replace(/module\\.exports =/ig,'export'),'utf-8');fs.writeFileSync('src/ua-parser-extension.mjs','// Generated ESM version of UAParser.js extensions\\n// DO NOT EDIT THIS FILE!\\n// Source: /src/ua-parser-extension.js\\n\\n'+fs.readFileSync('src/ua-parser-extension.js','utf-8').replace(/module\\.exports =/ig,'export'),'utf-8')\"", + "build": "uglifyjs src/ua-parser.js -o dist/ua-parser.min.js --comments '/^ UA/' && uglifyjs src/ua-parser.js -o dist/ua-parser.pack.js --comments '/^ UA/' --compress --mangle && node -e \"const fs=require('fs');fs.writeFileSync('src/ua-parser.mjs','// Generated ESM version of UAParser.js\\n// DO NOT EDIT THIS FILE!\\n// Source: /src/ua-parser.js\\n\\nconst window = undefined;\\n\\n'+fs.readFileSync('src/ua-parser.js','utf-8').replace(/\\(func[\\s\\S]+strict\\';/ig,'').replace(/\\/[\\/\\s]+export[\\s\\S]+/ig,'export {UAParser};'),'utf-8');fs.writeFileSync('src/enum/ua-parser-enum.mjs','// Generated ESM version of UAParser.js enums\\n// DO NOT EDIT THIS FILE!\\n// Source: /src/enum/ua-parser-enum.js\\n\\n'+fs.readFileSync('src/enum/ua-parser-enum.js','utf-8').replace(/module\\.exports =/ig,'export'),'utf-8');fs.writeFileSync('src/extension/ua-parser-extension.mjs','// Generated ESM version of UAParser.js extensions\\n// DO NOT EDIT THIS FILE!\\n// Source: /src/extension/ua-parser-extension.js\\n\\n'+fs.readFileSync('src/extension/ua-parser-extension.js','utf-8').replace(/const UA.+\\)/ig,'import UAParser from \\'ua-parser-js\\'').replace(/module\\.exports =/ig,'export'),'utf-8')\"", "test": "jshint src/ua-parser.js && mocha -R nyan test", "test-ci": "jshint src/ua-parser.js && mocha -R spec test", "verup": "node ./node_modules/verup", diff --git a/readme.md b/readme.md index 071593d..ad229f3 100644 --- a/readme.md +++ b/readme.md @@ -43,8 +43,11 @@ JavaScript library to detect Browser, Engine, OS, CPU, and Device type/model fro --- +# Version 2.0 +What's new & breaking, please read [CHANGELOG](changelog.md) before upgrading. + # Documentation -### UAParser([user-agent:string][,extensions:object][,headers:object(since@1.1)]) +### UAParser([user-agent:string][,extensions:object][,headers:object(since@2.0)]) In the browser environment you dont need to pass the user-agent string to the function, you can just call the funtion and it should automatically get the string from the `window.navigator.userAgent`, but that is not the case in nodejs. The user-agent string must be passed in' nodejs for the function to work. Usually you can find the user agent in: `request.headers["user-agent"]`. @@ -52,7 +55,7 @@ In the browser environment you dont need to pass the user-agent string to the fu ## Constructor When you call `UAParser` with the `new` keyword, `UAParser` will return a new instance with an empty result object, you have to call one of the available methods to get the information from the user-agent string. Like so: -* `new UAParser([user-agent:string][,extensions:object][,headers:object(since@1.1)])` +* `new UAParser([user-agent:string][,extensions:object][,headers:object(since@2.0)])` ```js let parser = new UAParser("your user-agent here"); // you need to pass the user-agent for nodejs console.log(parser); // {} @@ -65,22 +68,19 @@ console.log(parserResults); "os" : {}, "device" : {}, "cpu" : {} - - // since@1.1 - ,"ua_ch" : {} } */ ``` When you call UAParser without the `new` keyword, it will automatically call `getResult()` function and return the parsed results. -* `UAParser([user-agent:string][,extensions:object][,headers:object(since@1.1)])` - * returns result object `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} /* added since@1.1: ua_ch: {} */ }` +* `UAParser([user-agent:string][,extensions:object][,headers:object(since@2.0)])` + * returns result object `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} }` ## Methods #### Methods table The methods are self explanatory, here's a small overview on all the available methods: * `getResult()` - returns all function object calls, user-agent string, browser info, cpu, device, engine, os: -`{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} /* added since@1.1: ua_ch: {} */ }`. +`{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} }`. * `getBrowser()` - returns the browser name and version. * `getDevice()` - returns the device model, type, vendor. @@ -93,7 +93,7 @@ The methods are self explanatory, here's a small overview on all the available m --- * `getResult()` - * returns `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} /* added since@1.1: ua_ch: {} */ }` + * returns `{ ua: '', browser: {}, cpu: {}, device: {}, engine: {}, os: {} }` * `getBrowser()` * returns `{ name: '', version: '' }` @@ -113,7 +113,7 @@ NetSurf, Netfront, Netscape, NokiaBrowser, Obigo, Oculus Browser, OmniWeb, Opera Coast, Opera [Mini/Mobi/Tablet], PaleMoon, PhantomJS, Phoenix, Polaris, Puffin, QQ, QQBrowser, QQBrowserLite, Quark, QupZilla, RockMelt, [Mobile] Safari, Sailfish Browser, Samsung Browser, SeaMonkey, Silk, Skyfire, Sleipnir, Slim, -SlimBrowser, Swiftfox, Tesla, Tizen Browser, UCBrowser, UP.Browser, Viera, +SlimBrowser, Swiftfox, Tesla, TikTok, Tizen Browser, UCBrowser, UP.Browser, Viera, Vivaldi, Waterfox, WeChat, Weibo, Yandex, baidu, iCab, w3m, Whale Browser, ... # 'browser.version' determined dynamically @@ -148,8 +148,8 @@ Siemens, Sony[Ericsson], Sprint, Tesla, Vivo, Vodafone, Xbox, Xiaomi, Zebra, ZTE ```sh # Possible 'engine.name' -Amaya, Blink, EdgeHTML, Flow, Gecko, Goanna, iCab, KHTML, Links, Lynx, NetFront, -NetSurf, Presto, Tasman, Trident, w3m, WebKit +Amaya, Blink, EdgeHTML, Flow, Gecko, Goanna, iCab, KHTML, LibWeb, Links, Lynx, +NetFront, NetSurf, Presto, Tasman, Trident, w3m, WebKit # 'engine.version' determined dynamically ``` @@ -165,8 +165,9 @@ Fuchsia, Gentoo, GhostBSD, GNU, Haiku, HarmonyOS, HP-UX, Hurd, iOS, Joli, KaiOS, Linpus, Linspire,Linux, Mac OS, Maemo, Mageia, Mandriva, Manjaro, MeeGo, Minix, Mint, Morph OS, NetBSD, NetRange, NetTV, Nintendo, OpenBSD, OpenVMS, OS/2, Palm, PC-BSD, PCLinuxOS, Plan9, PlayStation, QNX, Raspbian, RedHat, RIM Tablet OS, -RISC OS, Sabayon, Sailfish, Series40, Slackware, Solaris, SUSE, Symbian, Tizen, -Ubuntu, Unix, VectorLinux, Viera, watchOS, WebOS, Windows [Phone/Mobile], Zenwalk, ... +RISC OS, Sabayon, Sailfish, SerenityOS, Series40, Slackware, Solaris, SUSE, Symbian, +Tizen, Ubuntu, Unix, VectorLinux, Viera, watchOS, WebOS, Windows [Phone/Mobile], +Zenwalk, ... # 'os.version' determined dynamically ``` @@ -186,10 +187,10 @@ Ubuntu, Unix, VectorLinux, Viera, watchOS, WebOS, Windows [Phone/Mobile], Zenwal * set UA string to be parsed * returns current instance -#### * `is():boolean` utility `since@1.1` +#### * `is():boolean` utility `since@2.0` ```js -// Is just a shorthand to check whether specified item has a property with equals value (case-insensitive) +// Is just a shorthand comparison to check whether the value of specified item equals one of its properties (in a case-insensitive way) // so that instead of write it using `==` operator like this: let ua = UAParser(); @@ -202,15 +203,10 @@ if (device.type == "smarttv" || device.vendor == "Samsung") {} // we can also write the comparison above into as follow: if (device.is("mobile") && !os.is("iOS")) {} -if (device.is("smarttv") || device.is("Samsung")) {} +if (device.is("SmartTV") || device.is("SaMsUnG")) {} /* - Each properties will be checked in this particular order: - * browser : name - * cpu : architecture - * device : type, model, vendor - * engine : name - * os : name + For device, properties will be checked in this particular order: type, model, vendor */ // Another examples: @@ -250,7 +246,7 @@ let engine = uap.getEngine(); engine.is("Blink"); // true ``` -#### * `toString():string` utility `since@1.1` +#### * `toString():string` utility `since@2.0` ```js // Retrieve full-name values as a string @@ -291,11 +287,12 @@ engine.version; // "28.0.1500.95" engine.toString(); // "Blink 28.0.1500.95" ``` -#### * `withClientHints():Promise|Thenable` `since@1.1` +#### * `withClientHints():Promise|Thenable` `since@2.0` -Unlike reading user-agent data, accessing client-hints data in browser-environment must be done in an asynchronous way. Worry not, you can chain the UAParser's `get*` method with `withClientHints()` to read the client-hints data as well that will return the updated data as a `Promise`. In nodejs-environment / browser-environment with non-secure context or without client-hints support (basically anything that's not chromium-based) this will return the updated data as a `Thenable` (can be chained with `then()`). +Recently Chrome limits the information exposed through user-agent and introduces a new experimental set of data called "client-hints". In browser-environment, obtaining the client-hints data via JavaScript must be done in an asynchronous way. In `UAParser` you can chain the result object from `get*` method with `withClientHints()` to also read the client-hints data from the browser and return the updated data as a `Promise`. ```js +// client-side example (async function () { let ua = new UAParser(); @@ -314,12 +311,43 @@ Unlike reading user-agent data, accessing client-hints data in browser-environme })(); ``` +Along with `User-Agent` HTTP header, Chrome also sends this client-hints data by default under `Sec-CH-UA-*` HTTP headers in each request. In server-side development, you can capture this extra information by passing the `req.headers` to `UAParser()` (see examples below). When using `withClientHints()` in nodejs environment and browser without client-hints support (basically anything that's not Chromium-based) the updated data will be returned as a `Thenable` (has `then()` method). + +```js +// server-side example + +// Suppose we got a request having these HTTP headers: +const request = { + headers : { + 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36', + + 'sec-ch-ua-mobile' : '?1', + 'sec-ch-ua-model' : 'Galaxy S3 Marketing', + 'sec-ch-ua-platform' : 'Android' + } +}; + +const result1 = UAParser(request.headers); // parse only "user-agent" header +const result2 = UAParser(request.headers).withClientHints(); // update with "sec-ch-ua" headers + +console.log(result1.os.name); // "Linux" +console.log(result1.device.type); // undefined +console.log(result1.device.model); // undefined + +console.log(result2.os.name); // "Android" +console.log(result2.device.type); // "mobile" +console.log(result2.device.model); // "Galaxy S3 Marketing" + +new UAParser(request.headers).getBrowser().withClientHints().then((browser) => { + console.log(browser.toString()); // Chrome 110.0.0.0 +}); +``` ## Extending Regex If you want to detect something that's not currently provided by UAParser.js (eg: `bots`, specific apps, etc), you can pass a list of regexes to extend internal UAParser.js regexes with your own. -* `UAParser([uastring,] extensions [,headers:object(since@1.1)])` +* `UAParser([uastring,] extensions [,headers:object(since@2.0)])` ```js // Example: @@ -389,18 +417,6 @@ console.log(myParser2.setUA(myUA2).getDevice()); // {vendor: "MyTab", model: "1 cpu: { architecture: "" } - - // added since@1.1: - ,ua_ch: { - architecture: "", - brands: "", - bitness: "", - fullVersionList: "", - mobile: "", - model: "", - platform: "", - platformVersion: "" - } } */ // Default result depends on current window.navigator.userAgent value @@ -453,7 +469,7 @@ http.createServer(function (req, res) { // get user-agent header var ua = uap(req.headers['user-agent']); - /* // BEGIN since@1.1 - you can also pass client-hints data to UAParser + /* // BEGIN since@2.0 - you can also pass client-hints data to UAParser // note: only works in secure context (https:// or localhost or file://) @@ -463,7 +479,7 @@ http.createServer(function (req, res) { var ua = uap(req.headers); - // END since@1.1 */ + // END since@2.0 */ // write the result as response res.end(JSON.stringify(ua, null, ' ')); @@ -477,14 +493,13 @@ console.log('Server running at http://127.0.0.1:1337/'); ```js import { UAParser } from 'ua-parser-js'; -import { CPUArch, DeviceType } from 'ua-parser-js/enums'; -const { cpu, device } = UAParser('Mozilla/5.0 (X11; U; Linux armv7l; en-GB; rv:1.9.2a1pre) Gecko/20090928 Firefox/3.5 Maemo Browser 1.4.1.22 RX-51 N900'); +const { browser, cpu, device } = UAParser('Mozilla/5.0 (X11; U; Linux armv7l; en-GB; rv:1.9.2a1pre) Gecko/20090928 Firefox/3.5 Maemo Browser 1.4.1.22 RX-51 N900'); -console.log(browser.name) // Maemo Browser -console.log(cpu.is(CPUArch.ARM)) // true -console.log(device.is(DeviceType.MOBILE)) // true -console.log(device.model) // N900 +console.log(browser.name); // Maemo Browser +console.log(cpu.is('arm')); // true +console.log(device.is('mobile')); // true +console.log(device.model); // N900 ``` ## Using TypeScript diff --git a/src/ua-parser-enum.js b/src/enum/ua-parser-enum.js similarity index 98% rename from src/ua-parser-enum.js rename to src/enum/ua-parser-enum.js index 4b21b72..8333eaf 100644 --- a/src/ua-parser-enum.js +++ b/src/enum/ua-parser-enum.js @@ -1,5 +1,5 @@ /////////////////////////////////////////////// -/* Enums for UAParser.js v2.0 +/* Enums for UAParser.js v2.0.0-alpha.1 https://github.com/faisalman/ua-parser-js Author: Faisal Salman MIT License */ diff --git a/src/ua-parser-enum.mjs b/src/enum/ua-parser-enum.mjs similarity index 94% rename from src/ua-parser-enum.mjs rename to src/enum/ua-parser-enum.mjs index 74e7537..7708532 100644 --- a/src/ua-parser-enum.mjs +++ b/src/enum/ua-parser-enum.mjs @@ -1,8 +1,9 @@ // Generated ESM version of UAParser.js enums -// Source file: /src/ua-parser-enum.js +// DO NOT EDIT THIS FILE! +// Source: /src/enum/ua-parser-enum.js /////////////////////////////////////////////// -/* Enums for UAParser.js v2.0 +/* Enums for UAParser.js v2.0.0-alpha.1 https://github.com/faisalman/ua-parser-js Author: Faisal Salman MIT License */ @@ -71,6 +72,7 @@ const EngineName = Object.freeze({ GECKO : 'Gecko', GOANNA : 'Goanna', ICAB : 'iCab', + LIBWEB : 'LibWeb', KHTML : 'KHTML', LINKS : 'Links', LYNX : 'Lynx', diff --git a/src/ua-parser-extension.js b/src/extension/ua-parser-extension.js similarity index 98% rename from src/ua-parser-extension.js rename to src/extension/ua-parser-extension.js index c9c64bd..dfa90ed 100644 --- a/src/ua-parser-extension.js +++ b/src/extension/ua-parser-extension.js @@ -1,11 +1,10 @@ /////////////////////////////////////////////// -/* Extensions for UAParser.js v2.0 +/* Extensions for UAParser.js v2.0.0-alpha.1 https://github.com/faisalman/ua-parser-js Author: Faisal Salman MIT License */ ////////////////////////////////////////////// -const UAParser = require('ua-parser-js'); const MODEL = 'model'; const NAME = 'name'; const TYPE = 'type'; diff --git a/src/extension/ua-parser-extension.mjs b/src/extension/ua-parser-extension.mjs new file mode 100644 index 0000000..8b645fc --- /dev/null +++ b/src/extension/ua-parser-extension.mjs @@ -0,0 +1,124 @@ +// Generated ESM version of UAParser.js extensions +// DO NOT EDIT THIS FILE! +// Source: /src/extension/ua-parser-extension.js + +/////////////////////////////////////////////// +/* Extensions for UAParser.js v2.0.0-alpha.1 + https://github.com/faisalman/ua-parser-js + Author: Faisal Salman + MIT License */ +////////////////////////////////////////////// + +const MODEL = 'model'; +const NAME = 'name'; +const TYPE = 'type'; +const VENDOR = 'vendor'; +const VERSION = 'version'; +const MOBILE = 'mobile'; +const TABLET = 'tablet'; + +const Bots = Object.freeze({ + browser : [ + // Googlebot / BingBot / MSNBot / FacebookBot + [/((?:google|bing|msn|facebook)bot(?:\-[imagevdo]{5})?|bingpreview)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'bot']] + ] +}); + +const ExtraDevices = Object.freeze({ + device : [ + [ + /(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]], [ + + /(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 + ], [MODEL, [VENDOR, 'Dragon Touch'], [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] + ] + ] +}); + +const Emails = Object.freeze({ + browser : [ + // Microsoft Outlook / Thunderbird + [/(microsoft outlook|thunderbird)[\s\/]([\w\.]+)/i], [NAME, VERSION, [TYPE, 'email']] + ] +}); + +const Tools = Object.freeze({ + browser : [ + // wget / curl / lynx + [/(wget|curl|lynx)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'tool']] + ] +}); + +export { + Bots, + ExtraDevices, + Emails, + Tools +} \ No newline at end of file diff --git a/src/ua-parser-extension.mjs b/src/ua-parser-extension.mjs deleted file mode 100644 index a6b4032..0000000 --- a/src/ua-parser-extension.mjs +++ /dev/null @@ -1,36 +0,0 @@ -// Generated ESM version of UAParser.js extensions -// DO NOT EDIT THIS FILE! -// Source: /src/ua-parser-extension.js - -/////////////////////////////////////////////// -/* Extensions for UAParser.js v2.0 - https://github.com/faisalman/ua-parser-js - Author: Faisal Salman - MIT License */ -////////////////////////////////////////////// - -const UAParser = require("./ua-parser") - -const Bots = Object.freeze({ - browser : [ - [/((?:google|bing|msn|facebook)bot(?:\-[imagevdo]{5})?|bingpreview)\/([\w\.]+)/i], [UAParser.BROWSER.NAME, UAParser.BROWSER.VERSION, ['type', 'bot']] - ] -}); - -const Emails = Object.freeze({ - browser : [ - [/(microsoft outlook|thunderbird)[\s\/]([\w\.]+)/i], [UAParser.BROWSER.NAME, UAParser.BROWSER.VERSION, ['type', 'email']] - ] -}); - -const Tools = Object.freeze({ - browser : [ - [/(wget|curl|lynx)\/([\w\.]+)/i], [UAParser.BROWSER.NAME, UAParser.BROWSER.VERSION, ['type', 'tool']] - ] -}); - -export { - Bots, - Emails, - Tools -} \ No newline at end of file diff --git a/src/ua-parser.js b/src/ua-parser.js index 7ac4aa3..6a82ed1 100755 --- a/src/ua-parser.js +++ b/src/ua-parser.js @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////////// -/* UAParser.js v1.1.34 +/* UAParser.js v2.0.0-alpha.1 Copyright © 2012-2023 Faisal Salman MIT License *//* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. @@ -17,7 +17,7 @@ ///////////// - var LIBVERSION = '1.1.34', + var LIBVERSION = '2.0.0-alpha.1', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', @@ -960,7 +960,6 @@ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get(); }; this.set('ua', ua) - .set('ua_ch', uaCH) .set(UA_BROWSER, createUAParserItem(UA_BROWSER)) .set(UA_CPU, createUAParserItem(UA_CPU)) .set(UA_DEVICE, createUAParserItem(UA_DEVICE)) @@ -1029,7 +1028,6 @@ return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get(); }; this.set('ua', ua) - .set('ua_ch', uaCH) .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER)) .set(UA_CPU, createUAParserItemWithCH(UA_CPU)) .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE)) diff --git a/src/ua-parser.mjs b/src/ua-parser.mjs index 1821d97..e0d93d0 100644 --- a/src/ua-parser.mjs +++ b/src/ua-parser.mjs @@ -1,10 +1,11 @@ // Generated ESM version of UAParser.js -// Source file: /src/ua-parser.js +// DO NOT EDIT THIS FILE! +// Source: /src/ua-parser.js const window = undefined; ///////////////////////////////////////////////////////////////////////////////// -/* UAParser.js v1.1.34 +/* UAParser.js v2.0.0-alpha.1 Copyright © 2012-2023 Faisal Salman MIT License *//* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. @@ -20,7 +21,7 @@ const window = undefined; ///////////// - var LIBVERSION = '1.1.34', + var LIBVERSION = '2.0.0-alpha.1', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', @@ -74,10 +75,8 @@ const window = undefined; SAMSUNG = 'Samsung', SHARP = 'Sharp', SONY = 'Sony', - SWISS = 'Swiss', XIAOMI = 'Xiaomi', ZEBRA = 'Zebra', - ZTE = 'ZTE', PREFIX_MOBILE = 'Mobile ', SUFFIX_BROWSER = ' Browser', CHROME = 'Chrome', @@ -269,10 +268,6 @@ const window = undefined; '8.1' : 'NT 6.3', '10' : ['NT 6.4', 'NT 10.0'], 'RT' : 'ARM' - }, - archEquivalenceMap = { - 'amd64' : ['x86-64', 'x64'], - 'ia32' : ['x86'] }; ////////////// @@ -368,6 +363,8 @@ const window = undefined; ], [NAME, VERSION], [ /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS ], [VERSION, [NAME, 'GSA']], [ + /musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok + ], [VERSION, [NAME, 'TikTok']], [ /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless ], [VERSION, [NAME, CHROME+' Headless']], [ @@ -610,62 +607,13 @@ const window = undefined; /(kobo)\s(ereader|touch)/i, // Kobo /(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 + /(kindle)\/([\w\.]+)/i // Kindle ], [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 @@ -774,7 +722,8 @@ const window = undefined; /(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 + /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab + /\b(libweb)/i ], [NAME, VERSION], [ /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko @@ -852,7 +801,7 @@ const window = undefined; ], [[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 + /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS /(unix) ?([\w\.]*)/i // UNIX ], [NAME, VERSION] ] @@ -1015,7 +964,6 @@ const window = undefined; return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).get(); }; this.set('ua', ua) - .set('ua_ch', uaCH) .set(UA_BROWSER, createUAParserItem(UA_BROWSER)) .set(UA_CPU, createUAParserItem(UA_CPU)) .set(UA_DEVICE, createUAParserItem(UA_DEVICE)) @@ -1084,7 +1032,6 @@ const window = undefined; return new UAParserItem(itemType, ua, rgxMap[itemType], uaCH).parseCH().get(); }; this.set('ua', ua) - .set('ua_ch', uaCH) .set(UA_BROWSER, createUAParserItemWithCH(UA_BROWSER)) .set(UA_CPU, createUAParserItemWithCH(UA_CPU)) .set(UA_DEVICE, createUAParserItemWithCH(UA_DEVICE)) diff --git a/test/cpu-test.json b/test/cpu-test.json index cf314f9..2a7d189 100644 --- a/test/cpu-test.json +++ b/test/cpu-test.json @@ -206,5 +206,13 @@ { "architecture" : "irix64" } + }, + { + "desc" : "68k", + "ua" : "'Mozilla/1.1 (Macintosh; U; 68K)'", + "expect" : + { + "architecture" : "68k" + } } ] diff --git a/test/es6-test.mjs b/test/test-es6.mjs similarity index 84% rename from test/es6-test.mjs rename to test/test-es6.mjs index e3e0cbc..8165ec9 100644 --- a/test/es6-test.mjs +++ b/test/test-es6.mjs @@ -7,7 +7,7 @@ describe('Returns', () => { assert.deepEqual(new UAParser('').getResult(), { ua : '', - ua_ch : { architecture: undefined, bitness: undefined, brands: undefined, fullVersionList: undefined, mobile: false, model: undefined, platform: undefined, platformVersion: undefined }, + //ua_ch : { architecture: undefined, bitness: undefined, brands: undefined, fullVersionList: undefined, mobile: false, model: undefined, platform: undefined, platformVersion: undefined }, browser: { name: undefined, version: undefined, major: undefined }, cpu: { architecture: undefined }, device: { vendor: undefined, model: undefined, type: undefined },