Update version to 2.0.0-beta.3

This commit is contained in:
Faisal Salman 2024-06-08 01:17:52 +07:00
parent bdcd927304
commit 5328642e18
18 changed files with 254 additions and 103 deletions

View File

@ -16,6 +16,20 @@
- Provided Extensions submodule `'ua-parser-js/extensions'` - Provided Extensions submodule `'ua-parser-js/extensions'`
- Provided Helpers submodule `'ua-parser-js/helpers'` - 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 ## Version 2.0.0-beta.2
- Increase UA_MAX_LENGTH to 500 - Increase UA_MAX_LENGTH to 500

View File

@ -15,7 +15,7 @@
# UAParser.js # 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 user's Browser, Engine, OS, CPU, and Device type/model. Runs either in browser
(client-side) or node.js (server-side). (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
</tr> </tr>
<tr> <tr>
<td>Price</td> <td>Price</td>
<td><strong title="Pay as you want">FREE</strong></td> <td><strong title="Pay as you want">FREE (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/1.0.x/license.md">License</a>)</strong></td>
<td><strong title="Pay as you want">FREE</strong></td> <td><strong title="Pay as you want">FREE (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/master/LICENSE.md">License</a>)</strong></td>
<td><strong title="$12 (one-time fee)">$12</strong></td> <td><strong title="$12 (one-time fee)">$12 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-personal/LICENSE.md">License</a>)</strong></td>
<td><strong title="$25 (one-time fee)">$25</strong></td> <td><strong title="$25 (one-time fee)">$25 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-business/LICENSE.md">License</a>)</strong></td>
<td><strong title="$500 (one-time fee)">$500</strong></td> <td><strong title="$500 (one-time fee)">$500 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-enterprise/LICENSE.md">License</a>)</strong></td>
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
@ -205,8 +205,7 @@ see what's new & breaking.
## Contributors ## Contributors
Large or small, your contribution is valuable here. Please read [CONTRIBUTING](CONTRIBUTING.md) Please read [CONTRIBUTING](CONTRIBUTING.md) guide first for the instruction details.
guide first for the instruction details.
<a href="https://github.com/faisalman/ua-parser-js/graphs/contributors"> <a href="https://github.com/faisalman/ua-parser-js/graphs/contributors">
<img src="https://contrib.rocks/image?repo=faisalman/ua-parser-js" /> <img src="https://contrib.rocks/image?repo=faisalman/ua-parser-js" />

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

7
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.0-beta.2", "version": "2.0.0-beta.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.0-beta.2", "version": "2.0.0-beta.3",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -22,6 +22,9 @@
} }
], ],
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"bin": {
"ua-parser-js": "script/cli.js"
},
"devDependencies": { "devDependencies": {
"@babel/parser": "7.15.8", "@babel/parser": "7.15.8",
"@babel/traverse": "7.23.2", "@babel/traverse": "7.23.2",

View File

@ -1,6 +1,6 @@
Package.describe({ Package.describe({
name: 'faisalman:ua-parser-js', 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', summary: 'Lightweight JavaScript-based user-agent string parser',
git: 'https://github.com/faisalman/ua-parser-js.git', git: 'https://github.com/faisalman/ua-parser-js.git',
documentation: 'readme.md' documentation: 'readme.md'

View File

@ -1,7 +1,7 @@
{ {
"title": "UAParser.js", "title": "UAParser.js",
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.0-beta.2", "version": "2.0.0-beta.3",
"author": "Faisal Salman <f@faisalman.com> (http://faisalman.com)", "author": "Faisal Salman <f@faisalman.com> (http://faisalman.com)",
"description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment", "description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment",
"keywords": [ "keywords": [
@ -18,7 +18,8 @@
"ua-parser-js", "ua-parser-js",
"browser-detection", "browser-detection",
"device-detection", "device-detection",
"os-detection" "os-detection",
"bot-detection"
], ],
"homepage": "https://github.com/faisalman/ua-parser-js", "homepage": "https://github.com/faisalman/ua-parser-js",
"contributors": [ "contributors": [

View File

@ -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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -3,7 +3,7 @@
// Source: /src/enums/ua-parser-enums.js // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -54,7 +54,7 @@ const Browser = Object.freeze({
FENNEC: 'Fennec', FENNEC: 'Fennec',
FLOCK: 'Flock', FLOCK: 'Flock',
FLOW: 'Flow', FLOW: 'Flow',
GO: 'Go Browser', GO: 'GoBrowser',
GOOGLE_SEARCH: 'GSA', GOOGLE_SEARCH: 'GSA',
HEYTAP: 'HeyTap', HEYTAP: 'HeyTap',
HUAWEI: 'Huawei Browser', HUAWEI: 'Huawei Browser',
@ -108,6 +108,7 @@ const Browser = Object.freeze({
PALEMOON: 'PaleMoon', PALEMOON: 'PaleMoon',
PHANTOMJS: 'PhantomJS', PHANTOMJS: 'PhantomJS',
PHOENIX: 'Phoenix', PHOENIX: 'Phoenix',
PICOBROWSER: 'Pico Browser',
POLARIS: 'Polaris', POLARIS: 'Polaris',
PUFFIN: 'Puffin', PUFFIN: 'Puffin',
QQ: 'QQBrowser', QQ: 'QQBrowser',
@ -132,9 +133,9 @@ const Browser = Object.freeze({
TESLA: 'Tesla', TESLA: 'Tesla',
TIKTOK: 'TikTok', TIKTOK: 'TikTok',
TIZEN: 'Tizen Browser', TIZEN: 'Tizen Browser',
TWITTER: 'Twitter',
UC: 'UCBrowser', UC: 'UCBrowser',
UP: 'UP.Browser', UP: 'UP.Browser',
VIERA: 'Viera',
VIVALDI: 'Vivaldi', VIVALDI: 'Vivaldi',
VIVO: 'Vivo Browser', VIVO: 'Vivo Browser',
W3M: 'w3m', W3M: 'w3m',
@ -143,11 +144,21 @@ const Browser = Object.freeze({
WECHAT: 'WeChat', WECHAT: 'WeChat',
WEIBO: 'Weibo', WEIBO: 'Weibo',
WHALE: 'Whale', WHALE: 'Whale',
WOLVIC: 'Wolvic',
YANDEX: 'Yandex' YANDEX: 'Yandex'
// TODO : test! // TODO : test!
}); });
const BrowserType = Object.freeze({
CRAWLER: 'crawler',
CLI: 'cli',
EMAIL: 'email',
FETCHER: 'fetcher',
INAPP: 'inapp',
MODULE: 'module'
});
const CPU = Object.freeze({ const CPU = Object.freeze({
ARM : 'arm', ARM : 'arm',
ARM_64: 'arm64', ARM_64: 'arm64',
@ -175,7 +186,8 @@ const Device = Object.freeze({
MOBILE: 'mobile', MOBILE: 'mobile',
SMARTTV: 'smarttv', SMARTTV: 'smarttv',
TABLET: 'tablet', TABLET: 'tablet',
WEARABLE: 'wearable' WEARABLE: 'wearable',
XR: 'xr'
}); });
const Vendor = Object.freeze({ const Vendor = Object.freeze({
@ -346,6 +358,7 @@ const OS = Object.freeze({
export { export {
Browser, Browser,
BrowserType,
CPU, CPU,
Device, Device,
Vendor, Vendor,

View File

@ -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 // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -3,7 +3,7 @@
// Source: /src/extensions/ua-parser-extensions.js // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -18,33 +18,74 @@ const VENDOR = 'vendor';
const VERSION = 'version'; const VERSION = 'version';
const MOBILE = 'mobile'; const MOBILE = 'mobile';
const TABLET = 'tablet'; 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({ //////////////////////
browser : [ // COMMAND LINE APPS
[/chatlyio\/([\d\.]+)/i], [VERSION, 'Slack', [TYPE, 'app']] /////////////////////
]
});
const Bots = Object.freeze({
browser : [
// Googlebot / BingBot / MSNBot / FacebookBot
[/((?:google|bing|msn|facebook)bot(?:[\-imagevdo]{0,6})|bingpreview)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, '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']]
]
});
const CLIs = Object.freeze({ const CLIs = Object.freeze({
browser : [ browser : [
// wget / curl / lynx // wget / curl / lynx
[/(wget|curl|lynx)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'cli']] [/(wget|curl|lynx)[\/ ]([\w\.]+)/i], [NAME, VERSION, [TYPE, CLI]]
] ]
}); });
////////////////////////
// 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
[/((?: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]]
]
});
//////////////////
// EXTRA DEVICES
/////////////////
const ExtraDevices = Object.freeze({ const ExtraDevices = Object.freeze({
device : [[ device : [[
/(nook)[\w ]+build\/(\w+)/i, // Nook /(nook)[\w ]+build\/(\w+)/i, // Nook
@ -121,13 +162,63 @@ const ExtraDevices = Object.freeze({
] ]
}); });
///////////////
// EMAIL APPS
//////////////
const Emails = Object.freeze({ const Emails = Object.freeze({
browser : [ browser : [
// Microsoft Outlook / Thunderbird // Microsoft Outlook / Thunderbird
[/(microsoft outlook|thunderbird)[\s\/]([\w\.]+)/i], [NAME, VERSION, [TYPE, 'email']] [/(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({ const MediaPlayers = Object.freeze({
browser : [[ browser : [[
@ -234,19 +325,24 @@ const MediaPlayers = Object.freeze({
] ]
}); });
////////////////////////
// MODULES / LIBRARIES
///////////////////////
const Modules = Object.freeze({ const Modules = Object.freeze({
browser : [ browser : [
// Axios/jsdom/Scrapy // Axios/jsdom/Scrapy
[/\b(axios|jsdom|scrapy)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, 'module']] [/\b(axios|jsdom|scrapy)\/([\w\.]+)/i], [NAME, VERSION, [TYPE, MODULE]]
] ]
}); });
export { export {
Apps,
Bots,
CLIs, CLIs,
Crawlers,
ExtraDevices, ExtraDevices,
Emails, Emails,
Fetchers,
InApps,
MediaPlayers, MediaPlayers,
Modules Modules
}; };

View File

@ -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 // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -3,7 +3,7 @@
// Source: /src/helpers/ua-parser-helpers.js // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -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 // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.0-beta.2 /* UAParser.js v2.0.0-beta.3
Copyright © 2012-2023 Faisal Salman <f@faisalman.com> Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
AGPLv3 License *//* AGPLv3 License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
Supports browser & node.js environment. Supports browser & node.js environment.
@ -19,7 +19,7 @@
// Constants // Constants
///////////// /////////////
var LIBVERSION = '2.0.0-beta.2', var LIBVERSION = '2.0.0-beta.3',
EMPTY = '', EMPTY = '',
UNKNOWN = '?', UNKNOWN = '?',
FUNC_TYPE = 'function', FUNC_TYPE = 'function',

View File

@ -3,8 +3,8 @@
// Source: /src/main/ua-parser.js // Source: /src/main/ua-parser.js
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.0-beta.2 /* UAParser.js v2.0.0-beta.3
Copyright © 2012-2023 Faisal Salman <f@faisalman.com> Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
AGPLv3 License *//* AGPLv3 License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
Supports browser & node.js environment. Supports browser & node.js environment.
@ -21,7 +21,7 @@
// Constants // Constants
///////////// /////////////
var LIBVERSION = '2.0.0-beta.2', var LIBVERSION = '2.0.0-beta.3',
EMPTY = '', EMPTY = '',
UNKNOWN = '?', UNKNOWN = '?',
FUNC_TYPE = 'function', FUNC_TYPE = 'function',
@ -40,11 +40,12 @@
TABLET = 'tablet', TABLET = 'tablet',
SMARTTV = 'smarttv', SMARTTV = 'smarttv',
WEARABLE = 'wearable', WEARABLE = 'wearable',
XR = 'xr',
EMBEDDED = 'embedded', EMBEDDED = 'embedded',
USER_AGENT = 'user-agent', USER_AGENT = 'user-agent',
UA_MAX_LENGTH = 500, UA_MAX_LENGTH = 500,
BRANDS = 'brands', BRANDS = 'brands',
FORMFACTOR = 'formFactor', FORMFACTORS = 'formFactors',
FULLVERLIST = 'fullVersionList', FULLVERLIST = 'fullVersionList',
PLATFORM = 'platform', PLATFORM = 'platform',
PLATFORMVER = 'platformVersion', PLATFORMVER = 'platformVersion',
@ -53,12 +54,12 @@
CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list', CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
CH_HEADER_ARCH = CH_HEADER + '-arch', CH_HEADER_ARCH = CH_HEADER + '-arch',
CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS, 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_MOBILE = CH_HEADER + '-' + MOBILE,
CH_HEADER_MODEL = CH_HEADER + '-' + MODEL, CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM, CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version', 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_BROWSER = 'browser',
UA_CPU = 'cpu', UA_CPU = 'cpu',
UA_DEVICE = 'device', UA_DEVICE = 'device',
@ -102,12 +103,21 @@
// Helper // Helper
////////// //////////
var extend = function (regexes, extensions) { var extend = function (defaultRgx, extensions) {
var mergedRegexes = {}; var mergedRgx = {};
for (var i in regexes) { var extraRgx = extensions;
mergedRegexes[i] = extensions[i] && extensions[i].length % 2 === 0 ? extensions[i].concat(regexes[i]) : regexes[i]; 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] : []);
} }
return mergedRegexes; }
}
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) { enumerize = function (arr) {
var enums = {}; var enums = {};
@ -125,9 +135,9 @@
} }
return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
}, },
isExtensions = function (obj) { isExtensions = function (obj, deep) {
for (var prop in obj) { 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) { isString = function (val) {
@ -271,12 +281,13 @@
'RT' : 'ARM' 'RT' : 'ARM'
}, },
formFactorMap = { formFactorsMap = {
'embedded' : 'Automotive', 'embedded' : 'Automotive',
'mobile' : 'Mobile', 'mobile' : 'Mobile',
'tablet' : ['Tablet', 'EInk'], 'tablet' : ['Tablet', 'EInk'],
'smarttv' : 'TV', 'smarttv' : 'TV',
'wearable' : ['VR', 'XR', 'Watch'], 'wearable' : 'Watch',
'xr' : ['VR', 'XR'],
'?' : ['Desktop', 'Unknown'], '?' : ['Desktop', 'Unknown'],
'*' : undefined '*' : undefined
}; };
@ -311,17 +322,20 @@
/\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
], [VERSION, [NAME, 'Baidu']], [ ], [VERSION, [NAME, 'Baidu']], [
/(kindle)\/([\w\.]+)/i, // Kindle /(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 // Trident based
/(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
// Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon // 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, /(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 // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar
/(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi
/(weibo)__([\d\.]+)/i // Weibo /(weibo)__([\d\.]+)/i // Weibo
], [NAME, VERSION], [ ], [NAME, VERSION], [
/\bddg\/([\w\.]+)/i // DuckDuckGo
], [VERSION, [NAME, 'DuckDuckGo']], [
/(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
], [VERSION, [NAME, 'UCBrowser']], [ ], [VERSION, [NAME, 'UCBrowser']], [
/microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
@ -354,8 +368,10 @@
], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [ ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
/\bqihu|(qi?ho?o?|360)browser/i // 360 /\bqihu|(qi?ho?o?|360)browser/i // 360
], [[NAME, '360' + SUFFIX_BROWSER]], [ ], [[NAME, '360' + SUFFIX_BROWSER]], [
/(oculus|sailfish|huawei|vivo)browser\/([\w\.]+)/i /\b(qq)\/([\w\.]+)/i // QQ
], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser ], [[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 /samsungbrowser\/([\w\.]+)/i // Samsung Internet
], [VERSION, [NAME, SAMSUNG + ' Internet']], [ ], [VERSION, [NAME, SAMSUNG + ' Internet']], [
/(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
@ -368,7 +384,7 @@
/(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
/m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser
], [NAME, VERSION], [ ], [NAME, VERSION], [
/(lbbrowser)/i, // LieBao Browser /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
], [NAME], [ ], [NAME], [
@ -381,6 +397,7 @@
/safari (line)\/([\w\.]+)/i, // Line App for iOS /safari (line)\/([\w\.]+)/i, // Line App for iOS
/\b(line)\/([\w\.]+)\/iab/i, // Line App for Android /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
/(alipay)client\/([\w\.]+)/i, // Alipay /(alipay)client\/([\w\.]+)/i, // Alipay
/(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
/(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat
], [NAME, VERSION], [ ], [NAME, VERSION], [
/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
@ -420,23 +437,24 @@
], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [ ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
/(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
], [[NAME, 'Netscape'], VERSION], [ ], [[NAME, 'Netscape'], VERSION], [
/(wolvic)\/([\w\.]+)/i // Wolvic
], [NAME, VERSION], [
/mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
], [VERSION, [NAME, FIREFOX+' Reality']], [ ], [VERSION, [NAME, FIREFOX+' Reality']], [
/ekiohf.+(flow)\/([\w\.]+)/i, // Flow /ekiohf.+(flow)\/([\w\.]+)/i, // Flow
/(swiftfox)/i, // Swiftfox /(swiftfox)/i, // Swiftfox
/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
// IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
// Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
/(firefox)\/([\w\.]+)/i, // Other Firefox-based /(firefox)\/([\w\.]+)/i, // Other Firefox-based
/(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
// Other // 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|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
// Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser
/(links) \(([\w\.]+)/i, // Links /(links) \(([\w\.]+)/i // Links
/panasonic;(viera)/i // Panasonic Viera ], [NAME, [VERSION, /_/g, '.']], [
], [NAME, VERSION], [
/(cobalt)\/([\w\.]+)/i // Cobalt /(cobalt)\/([\w\.]+)/i // Cobalt
], [NAME, [VERSION, /[^\d\.]+./, EMPTY]] ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
@ -523,6 +541,8 @@
/; (\w+) bui.+ oppo/i, /; (\w+) bui.+ oppo/i,
/\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/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]], [ ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
/\b(opd2\d{3}a?) bui/i
], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [
// Vivo // Vivo
/vivo (\w+)(?: bui|\))/i, /vivo (\w+)(?: bui|\))/i,
@ -706,12 +726,17 @@
], [VENDOR, MODEL, [TYPE, WEARABLE]], [ ], [VENDOR, MODEL, [TYPE, WEARABLE]], [
/(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [ ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
/droid.+; (glass) \d/i // Google Glass
], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [
/droid.+; (wt63?0{2,3})\)/i /droid.+; (wt63?0{2,3})\)/i
], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [ ], [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 // EMBEDDED
@ -842,7 +867,7 @@
var defaultProps = (function () { var defaultProps = (function () {
var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}}; var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
setProps.call(props.init, [ setProps.call(props.init, [
[UA_BROWSER, [NAME, VERSION, MAJOR]], [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
[UA_CPU, [ARCHITECTURE]], [UA_CPU, [ARCHITECTURE]],
[UA_DEVICE, [TYPE, MODEL, VENDOR]], [UA_DEVICE, [TYPE, MODEL, VENDOR]],
[UA_ENGINE, [NAME, VERSION]], [UA_ENGINE, [NAME, VERSION]],
@ -970,7 +995,7 @@
[PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])], [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
[PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])], [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
[ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])], [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])] [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
]); ]);
} else { } else {
@ -1090,15 +1115,15 @@
this.set(TYPE, CONSOLE) this.set(TYPE, CONSOLE)
.set(VENDOR, MICROSOFT); .set(VENDOR, MICROSOFT);
} }
if (uaCH[FORMFACTOR]) { if (uaCH[FORMFACTORS]) {
var ff; var ff;
if (typeof uaCH[FORMFACTOR] !== 'string') { if (typeof uaCH[FORMFACTORS] !== 'string') {
var idx = 0; var idx = 0;
while (!ff && idx < uaCH[FORMFACTOR].length) { while (!ff && idx < uaCH[FORMFACTORS].length) {
ff = strMapper(uaCH[FORMFACTOR][idx++], formFactorMap); ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
} }
} else { } else {
ff = strMapper(uaCH[FORMFACTOR], formFactorMap); ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
} }
this.set(TYPE, ff); this.set(TYPE, ff);
} }
@ -1149,7 +1174,7 @@
function UAParser (ua, extensions, headers) { function UAParser (ua, extensions, headers) {
if (typeof ua === OBJ_TYPE) { if (typeof ua === OBJ_TYPE) {
if (isExtensions(ua)) { if (isExtensions(ua, true)) {
if (typeof extensions === OBJ_TYPE) { if (typeof extensions === OBJ_TYPE) {
headers = extensions; // case UAParser(extensions, headers) headers = extensions; // case UAParser(extensions, headers)
} }
@ -1159,7 +1184,7 @@
extensions = undefined; extensions = undefined;
} }
ua = 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) headers = extensions; // case UAParser(ua, headers)
extensions = undefined; extensions = undefined;
} }
@ -1220,7 +1245,7 @@
} }
UAParser.VERSION = LIBVERSION; UAParser.VERSION = LIBVERSION;
UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]); UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]);
UAParser.CPU = enumerize([ARCHITECTURE]); UAParser.CPU = enumerize([ARCHITECTURE]);
UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]); UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]); UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);