1
0
mirror of https://github.com/lancedikson/bowser synced 2024-10-27 20:34:22 +00:00

Merge branch 'release/2.0.0' into production

This commit is contained in:
Denis Demchenko 2019-01-19 16:03:00 +02:00
commit 4ec19a2462
27 changed files with 10912 additions and 14278 deletions

View File

@ -1,6 +1,6 @@
{
"presets": [["env", {
"useBuiltIns": true,
"presets": [["@babel/preset-env", {
"useBuiltIns": "entry",
"modules": "umd",
"targets": {
"ie": "8",
@ -13,7 +13,7 @@
"env": {
"test": {
"plugins": [ "istanbul" ],
"presets": [["env", { "targets": { "node": "current" } }]]
"presets": [["@babel/preset-env", { "targets": { "node": "current" } }]]
}
}
}

View File

@ -3,6 +3,7 @@ root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[{*.js,*.md}]
charset = utf-8

8
.nycrc
View File

@ -1,4 +1,10 @@
{
"sourceMap": false,
"instrument": false
"instrument": false,
"include": [
"src/**/*.js"
],
"exclude": [
"*.js"
]
}

View File

@ -4,5 +4,5 @@ node_js:
- "8.4.0"
script:
- npm run lint
- npm build
- npm run build
- npm test

View File

@ -1,5 +1,12 @@
# Bowser Changelog
### 2.0.0 (January 19, 2019)
- [ADD] Support a non strict equality in `Parser.satisfies()` (#275)
- [ADD] Add Android versions names (#276)
- [ADD] Add a typings file (#277)
- [ADD] Added support for Googlebot recognition (#278)
- [FIX] Update building tools, avoid security issues
### 2.0.0-beta.3 (September 15, 2018)
- [FIX] Fix Chrome Mobile detection (#253)
- [FIX] Use built bowser for CI (#252)

View File

@ -1,7 +1,7 @@
# Contributing
The project runs Git-flow, where the `master` branch is the production one and the `develop` is the developing one.
The project runs Git-flow, where the `master` branch is the development one and `production` is the production one.
In a nutshell, if you're about to propose a new feature with adding new functionality to bowser, it's better to branch from `develop` and make a PR pointing to `develop` as well.
If it's a small hotfix, fix a typo in the docs or you've added support for a new browser/OS/platform/etc, then it's better to branch from `master` and make a PR pointing to `master` as well.
In a nutshell, if you're about to propose a new feature with adding some totally new functionality to `bowser`, it's better to branch from `master` and make a PR pointing back to `master` as well.
If it's a small hotfix, fix a typo in the docs or you've added support for a new browser/OS/platform/etc, then it's better to branch from `production` and make a PR pointing back to `production`.
Following these simple rules will help to maintain the repo a lot! Thanks ❤️

View File

@ -1,7 +1,7 @@
## Bowser
A Browser detector. Because sometimes, there is no other way, and not even good modern browsers always provide good feature detection mechanisms.
A browser detector. Because sometimes, there is no other way, and not even good modern browsers always provide good feature detection mechanisms.
[![Build Status](https://travis-ci.org/lancedikson/bowser.svg?branch=master)](https://travis-ci.org/lancedikson/bowser/) [![Greenkeeper badge](https://badges.greenkeeper.io/lancedikson/bowser.svg)](https://greenkeeper.io/)
[![Build Status](https://travis-ci.org/lancedikson/bowser.svg?branch=master)](https://travis-ci.org/lancedikson/bowser/) [![Greenkeeper badge](https://badges.greenkeeper.io/lancedikson/bowser.svg)](https://greenkeeper.io/)[![Coverage Status](https://coveralls.io/repos/github/lancedikson/bowser/badge.svg?branch=master)](https://coveralls.io/github/lancedikson/bowser?branch=master)
# Contents
- [Overview](#overview)
@ -15,21 +15,22 @@ The library is made to help to detect what browser your user has and gives you a
_Please, note that this is an alpha version. Check out the [1.x](https://github.com/lancedikson/bowser/tree/v1.x) branch for a stable version._
**Changes of the 2.0**
**Changes of version 2.0**
The upcoming 2.0 version has drastically changed API. All available methods can be found in the `docs` folder from now on and on a webpage soon.
# Use cases
First of all, require the library:
First of all, require the library. This is a UMD Module, so it will work for AMD, Typescript and CommonJS module systems.
```javascript
const bowser = require('bowser');
const Bowser = require("bowser"); // CommonJS
import * as Bowser from "bowser" // Typescript
```
By default, `require('bowser')` requires the *ES5 version of files*, which
**do not** include any polyfills.
By default, the exported version is the *ES5 transpiled version*, which **do not** include any polyfills.
In case if you don't use your own `babel-polyfill` you may need to have pre-built bundle with all needed polyfills.
In case you don't use your own `babel-polyfill` you may need to have pre-built bundle with all needed polyfills.
So, for you it's suitable to require bowser like this: `require('bowser/bundled')`.
As the result, you get a ES5 version of bowser with `babel-polyfill` bundled together.
@ -37,7 +38,7 @@ You may need to use the source files, so they will be available in the package a
## Browser props detection
Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to make it with Bowser:
Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to do it with Bowser:
```javascript
const browser = bowser.getParser(window.navigator.userAgent);
@ -63,6 +64,7 @@ or
const browser = bowser.getParser(window.navigator.userAgent);
impression.userTechData = browser.parse();
console.log(impression.userTechData);
// outputs
{
browser: {
@ -103,14 +105,14 @@ const isValidBrowser = browser.satisfies({
// per platform (mobile, desktop or tablet)
mobile: {
safari: '>9',
safari: '>=9',
'android browser': '>3.10'
},
// or in general
chrome: ">20.1.1432",
chrome: "~20.1.1432",
firefox: ">31",
opera: ">22"
opera: ">=22"
// also supports equality operator
chrome: "=20.1.1432", // will match particular build only
@ -127,11 +129,16 @@ Thus, you can define OS or platform specific rules and they will have more prior
More of API and possibilities you will find in the `docs` folder.
# Contributing
We're always open to pull requests or code reviews. Everyone can become a permanent contributor. Just ping @lancedikson in the issues or on Twitter ❤️
If you'd like to contribute a change to bowser, modify the files in `src/`, then run the following (you'll need node + npm installed):
``` sh
$ npm install
$ npm test
$ npm run build #build
$ npm test #run tests
$ npm run lint #check lint rules
```
### Adding tests

View File

@ -230,8 +230,8 @@ All the one-instance stuff is located in Parser class.</p></div>
<h5>Example</h5>
<pre class="prettyprint"><code>const bowser = new Bowser(window.navigator.userAgent);
bowser.getResult()</code></pre>
<pre class="prettyprint"><code>const parser = Bowser.getParser(window.navigator.userAgent);
const result = parser.getResult();</code></pre>
@ -418,7 +418,7 @@ bowser.getResult()</code></pre>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="bowser.js.html">bowser.js</a>, <a href="bowser.js.html#line42">line 42</a>
<a href="bowser.js.html">bowser.js</a>, <a href="bowser.js.html#line45">line 45</a>
</li></ul></dd>
@ -469,6 +469,11 @@ bowser.getResult()</code></pre>
<h5>Example</h5>
<pre class="prettyprint"><code>const result = Bowser.parse(window.navigator.userAgent);</code></pre>
<h5>Parameters:</h5>
@ -567,7 +572,7 @@ bowser.getResult()</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

View File

@ -1564,7 +1564,7 @@ like <a href="Parser.html#parseBrowser">Parser#parseBrowser</a> or <a href="Pars
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line438">line 438</a>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line446">line 446</a>
</li></ul></dd>
@ -2211,7 +2211,7 @@ the OS called &quot;anything&quot; or the platform called &quot;anything&quot;</
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line340">line 340</a>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line339">line 339</a>
</li></ul></dd>
@ -2382,7 +2382,7 @@ Returns <code>undefined</code> when the browser is no described in the checkTree
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line447">line 447</a>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line455">line 455</a>
</li></ul></dd>
@ -2422,7 +2422,7 @@ Returns <code>undefined</code> when the browser is no described in the checkTree
<div class="description">
<p>Check if any of the given values satifies this.is(anything)</p>
<p>Check if any of the given values satisfies this.is(anything)</p>
</div>
@ -2687,7 +2687,7 @@ Returns <code>undefined</code> when the browser is no described in the checkTree
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

View File

@ -66,8 +66,8 @@ class Bowser {
* @throws {Error} when UA is not a String
*
* @example
* const bowser = new Bowser(window.navigator.userAgent);
* bowser.getResult()
* const parser = Bowser.getParser(window.navigator.userAgent);
* const result = parser.getResult();
*/
static getParser(UA, skipParsing = false) {
if (typeof UA !== 'string') {
@ -81,6 +81,9 @@ class Bowser {
*
* @param UA
* @return {ParsedResult}
*
* @example
* const result = Bowser.parse(window.navigator.userAgent);
*/
static parse(UA) {
return (new Parser(UA)).getResult();
@ -102,7 +105,7 @@ export default Bowser;
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

View File

@ -766,7 +766,7 @@ like <code>&quot;iPhone&quot;</code> or <code>&quot;Kindle Fire HD 7&quot;</code
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

View File

@ -50,7 +50,7 @@
<section class="readme">
<article><h2>Bowser</h2><p>A Browser detector. Because sometimes, there is no other way, and not even good modern browsers always provide good feature detection mechanisms.</p>
<article><h2>Bowser</h2><p>A browser detector. Because sometimes, there is no other way, and not even good modern browsers always provide good feature detection mechanisms.</p>
<p><a href="https://travis-ci.org/lancedikson/bowser/"><img src="https://travis-ci.org/lancedikson/bowser.svg?branch=master" alt="Build Status"></a> <a href="https://greenkeeper.io/"><img src="https://badges.greenkeeper.io/lancedikson/bowser.svg" alt="Greenkeeper badge"></a></p>
<h1>Contents</h1><ul>
<li><a href="#overview">Overview</a></li>
@ -60,16 +60,17 @@
</ul>
<h1>Overview</h1><p>The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers.</p>
<p><em>Please, note that this is an alpha version. Check out the <a href="https://github.com/lancedikson/bowser/tree/v1.x">1.x</a> branch for a stable version.</em></p>
<p><strong>Changes of the 2.0</strong>
<p><strong>Changes of version 2.0</strong>
The upcoming 2.0 version has drastically changed API. All available methods can be found in the <code>docs</code> folder from now on and on a webpage soon.</p>
<h1>Use cases</h1><p>First of all, require the library:</p>
<pre class="prettyprint source lang-javascript"><code>const bowser = require('bowser');</code></pre><p>By default, <code>require('bowser')</code> requires the <em>ES5 version of files</em>, which
<strong>do not</strong> include any polyfills.</p>
<p>In case if you don't use your own <code>babel-polyfill</code> you may need to have pre-built bundle with all needed polyfills.
<h1>Use cases</h1><p>First of all, require the library. This is a UMD Module, so it will work for AMD, Typescript and CommonJS module systems.</p>
<pre class="prettyprint source lang-javascript"><code>const Bowser = require(&quot;bowser&quot;); // CommonJS
import * as Bowser from &quot;bowser&quot; // Typescript</code></pre><p>By default, the exported version is the <em>ES5 transpiled version</em>, which <strong>do not</strong> include any polyfills.</p>
<p>In case you don't use your own <code>babel-polyfill</code> you may need to have pre-built bundle with all needed polyfills.
So, for you it's suitable to require bowser like this: <code>require('bowser/bundled')</code>.
As the result, you get a ES5 version of bowser with <code>babel-polyfill</code> bundled together.</p>
<p>You may need to use the source files, so they will be available in the package as well.</p>
<h2>Browser props detection</h2><p>Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to make it with Bowser:</p>
<h2>Browser props detection</h2><p>Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to do it with Bowser:</p>
<pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
console.log(`The current browser name is &quot;${browser.getBrowserName()}&quot;`);
@ -83,6 +84,7 @@ impression.brVer = browserInfo.version;</code></pre><p>or</p>
<pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
impression.userTechData = browser.parse();
console.log(impression.userTechData);
// outputs
{
browser: {
@ -115,14 +117,14 @@ const isValidBrowser = browser.satisfies({
// per platform (mobile, desktop or tablet)
mobile: {
safari: '>9',
safari: '>=9',
'android browser': '>3.10'
},
// or in general
chrome: &quot;>20.1.1432&quot;,
chrome: &quot;~20.1.1432&quot;,
firefox: &quot;>31&quot;,
opera: &quot;>22&quot;
opera: &quot;>=22&quot;
// also supports equality operator
chrome: &quot;=20.1.1432&quot;, // will match particular build only
@ -134,8 +136,9 @@ const isValidBrowser = browser.satisfies({
Thus, you can define OS or platform specific rules and they will have more priority in the end.</p>
<p>More of API and possibilities you will find in the <code>docs</code> folder.</p>
<h1>Contributing</h1><p>If you'd like to contribute a change to bowser, modify the files in <code>src/</code>, then run the following (you'll need node + npm installed):</p>
<pre class="prettyprint source lang-sh"><code>$ npm install
$ npm test</code></pre><h3>Adding tests</h3><p>See the list in <code>test/acceptance/useragentstrings.yml</code> with example user agents and their expected bowser object.</p>
<pre class="prettyprint source lang-sh"><code>$ npm install #build
$ npm test #run tests
$ npm run lint #check lint rules</code></pre><h3>Adding tests</h3><p>See the list in <code>test/acceptance/useragentstrings.yml</code> with example user agents and their expected bowser object.</p>
<p>Whenever you add support for new browsers or notice a bug / mismatch, please update the list and
check if all tests are still passing.</p>
<h3>Similar Projects</h3><ul>
@ -156,7 +159,7 @@ check if all tests are still passing.</p>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

View File

@ -358,8 +358,7 @@ class Parser {
* @return {ParsedResult}
*/
getResult() {
/* TODO: Make this function pure, return a new object instead of the reference */
return this.parsedResult;
return Object.assign({}, this.parsedResult);
}
/**
@ -438,7 +437,7 @@ class Parser {
}
compareVersion(version) {
let expectedResult = 0;
let expectedResults = [0];
let comparableVersion = version;
let isLoose = false;
@ -448,12 +447,19 @@ class Parser {
return void 0;
}
if (version[0] === '>') {
expectedResult = 1;
comparableVersion = version.substr(1);
} else if (version[0] === '&lt;') {
expectedResult = -1;
if (version[0] === '>' || version[0] === '&lt;') {
comparableVersion = version.substr(1);
if (version[1] === '=') {
isLoose = true;
comparableVersion = version.substr(2);
} else {
expectedResults = [];
}
if (version[0] === '>') {
expectedResults.push(1);
} else {
expectedResults.push(-1);
}
} else if (version[0] === '=') {
comparableVersion = version.substr(1);
} else if (version[0] === '~') {
@ -461,7 +467,9 @@ class Parser {
comparableVersion = version.substr(1);
}
return compareVersions(currentBrowserVersion, comparableVersion, isLoose) === expectedResult;
return expectedResults.indexOf(
compareVersions(currentBrowserVersion, comparableVersion, isLoose),
) > -1;
}
isOS(osName) {
@ -483,7 +491,7 @@ class Parser {
}
/**
* Check if any of the given values satifies this.is(anything)
* Check if any of the given values satisfies this.is(anything)
* @param {String[]} anythings
* @returns {Boolean}
*/
@ -507,7 +515,7 @@ export default Parser;
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

View File

@ -94,6 +94,50 @@
}
}
/**
* Get Android version name
* 1.5 - Cupcake
* 1.6 - Donut
* 2.0 - Eclair
* 2.1 - Eclair
* 2.2 - Froyo
* 2.x - Gingerbread
* 3.x - Honeycomb
* 4.0 - Ice Cream Sandwich
* 4.1 - Jelly Bean
* 4.4 - KitKat
* 5.x - Lollipop
* 6.x - Marshmallow
* 7.x - Nougat
* 8.x - Oreo
* 9.x - ?
*
* @example
* getAndroidVersionName("7.0") // 'Nougat'
*
* @param {string} version
* @return {string} versionName
*/
static getAndroidVersionName(version) {
const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);
v.push(0);
if (v[0] === 1 &amp;&amp; v[1] &lt; 5) return undefined;
if (v[0] === 1 &amp;&amp; v[1] &lt; 6) return 'Cupcake';
if (v[0] === 1 &amp;&amp; v[1] >= 6) return 'Donut';
if (v[0] === 2 &amp;&amp; v[1] &lt; 2) return 'Eclair';
if (v[0] === 2 &amp;&amp; v[1] === 2) return 'Froyo';
if (v[0] === 2 &amp;&amp; v[1] > 2) return 'Gingerbread';
if (v[0] === 3) return 'Honeycomb';
if (v[0] === 4 &amp;&amp; v[1] &lt; 1) return 'Ice Cream Sandwich';
if (v[0] === 4 &amp;&amp; v[1] &lt; 4) return 'Jelly Bean';
if (v[0] === 4 &amp;&amp; v[1] >= 4) return 'KitKat';
if (v[0] === 5) return 'Lollipop';
if (v[0] === 6) return 'Marshmallow';
if (v[0] === 7) return 'Nougat';
if (v[0] === 8) return 'Oreo';
return undefined;
}
/**
* Get version precisions count
*
@ -203,7 +247,7 @@ module.exports = Utils;
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Sep 09 2018 15:08:13 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Jan 19 2019 15:43:45 GMT+0200 (EET) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>

224
index.d.ts vendored Normal file
View File

@ -0,0 +1,224 @@
// Type definitions for Bowser v2
// Project: https://github.com/lancedikson/bowser
// Definitions by: Alexander P. Cerutti <https://github.com/alexandercerutti>,
export = Bowser;
export as namespace Bowser;
declare namespace Bowser {
/**
* Creates a Parser instance
* @param {string} UA - User agent string
* @param {boolean} skipParsing
*/
function getParser(UA: string, skipParsing?: boolean): Parser.Parser;
/**
* Creates a Parser instance and runs Parser.getResult immediately
* @param UA - User agent string
* @returns {Parser.ParsedResult}
*/
function parse(UA: string): Parser.ParsedResult;
}
declare namespace Parser {
class Parser {
constructor(UA: string, skipParsing?: boolean);
/**
* Get parsed browser object
* @return {BrowserDetails} Browser's details
*/
getBrowser(): BrowserDetails;
/**
* Get browser's name
* @return {String} Browser's name or an empty string
*/
getBrowserName(): string;
/**
* Get browser's version
* @return {String} version of browser
*/
getBrowserVersion(): string;
/**
* Get OS
* @return {OSDetails} - OS Details
*
* @example
* this.getOS(); // {
* // name: 'macOS',
* // version: '10.11.12',
* // }
*/
getOS(): OSDetails;
/**
* Get OS name
* @param {Boolean} [toLowerCase] return lower-cased value
* @return {String} name of the OS macOS, Windows, Linux, etc.
*/
getOSName(toLowerCase?: boolean): string;
/**
* Get OS version
* @return {String} full version with dots ('10.11.12', '5.6', etc)
*/
getOSVersion(): string;
/**
* Get parsed platform
* @returns {PlatformDetails}
*/
getPlatform(): PlatformDetails;
/**
* Get platform name
* @param {boolean} toLowerCase
*/
getPlatformType(toLowerCase?: boolean): string;
/**
* Get parsed engine
* @returns {EngineDetails}
*/
getEngine(): EngineDetails;
/**
* Get parsed result
* @return {ParsedResult}
*/
getResult(): ParsedResult;
/**
* Get UserAgent string of current Parser instance
* @return {String} User-Agent String of the current <Parser> object
*/
getUA(): string;
/**
* Is anything? Check if the browser is called "anything",
* the OS called "anything" or the platform called "anything"
* @param {String} anything
* @returns {Boolean}
*/
is(anything: any): boolean;
/**
* Parse full information about the browser
*/
parse(): void;
/**
* Get parsed browser object
* @returns {BrowserDetails}
*/
parseBrowser(): BrowserDetails;
/**
* Get parsed engine
* @returns {EngineDetails}
*/
parseEngine(): EngineDetails;
/**
* Parse OS and save it to this.parsedResult.os
* @returns {OSDetails}
*/
parseOS(): OSDetails;
/**
* Get parsed platform
* @returns {PlatformDetails}
*/
parsePlatform(): PlatformDetails;
/**
* Check if parsed browser matches certain conditions
*
* @param {checkTree} checkTree It's one or two layered object,
* which can include a platform or an OS on the first layer
* and should have browsers specs on the bottom-laying layer
*
* @returns {Boolean|undefined} Whether the browser satisfies the set conditions or not.
* Returns `undefined` when the browser is no described in the checkTree object.
*
* @example
* const browser = new Bowser(UA);
* if (browser.check({chrome: '>118.01.1322' }))
* // or with os
* if (browser.check({windows: { chrome: '>118.01.1322' } }))
* // or with platforms
* if (browser.check({desktop: { chrome: '>118.01.1322' } }))
*/
satisfies(checkTree: checkTree): boolean | undefined;
/**
* Check if any of the given values satifies `.is(anything)`
* @param {string[]} anythings
* @returns {boolean} true if at least one condition is satisfied, false otherwise.
*/
some(anythings: string[]): boolean | undefined;
/**
* Test a UA string for a regexp
* @param regex
* @returns {boolean} true if the regex matches the UA, false otherwise.
*/
test(regex: RegExp): boolean;
}
interface ParsedResult {
browser: BrowserDetails;
os: OSDetails;
platform: PlatformDetails;
engine: EngineDetails;
}
interface Details {
name?: string;
version?: string;
}
interface OSDetails extends Details {
versionName?: string;
}
interface PlatformDetails {
type?: string;
vendor?: string;
model?: string;
}
type BrowserDetails = Details;
type EngineDetails = Details;
interface checkTree {
[key: string]: any;
}
}

22533
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "bowser",
"version": "2.0.0-beta.3",
"version": "2.0.0",
"description": "Lightweight browser detector",
"keywords": [
"browser",
@ -26,35 +26,34 @@
"url": "git+https://github.com/lancedikson/bowser.git"
},
"devDependencies": {
"ava": "^0.25.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-eslint": "^9.0.0",
"babel-loader": "^7.1.5",
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/polyfill": "^7.2.5",
"@babel/preset-env": "^7.2.3",
"@babel/register": "^7.0.0",
"ava": "^1.1.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5",
"babel-plugin-add-module-exports": "^1.0.0",
"babel-plugin-istanbul": "^4.1.6",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-register": "^6.26.0",
"babel-plugin-istanbul": "^5.1.1",
"coveralls": "^3.0.2",
"docdash": "^1.0.0",
"eslint": "^5.4.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-ava": "^5.1.0",
"eslint-plugin-import": "^2.13.0",
"eslint-plugin-import": "^2.14.0",
"jsdoc": "^3.5.5",
"nyc": "^12.0.2",
"sinon": "^6.1.5",
"testem": "^2.9.3",
"webpack": "^4.15.1",
"webpack-cli": "^3.0.8",
"webpack": "^4.28.4",
"webpack-cli": "^3.2.1",
"yamljs": "^0.3.0"
},
"ava": {
"require": [
"babel-register"
],
"babel": "inherit"
"@babel/register"
]
},
"bugs": {
"url": "https://github.com/lancedikson/bowser/issues"
@ -64,10 +63,11 @@
},
"scripts": {
"build": "webpack --config webpack.config.js",
"prepublish": "npm run build",
"prepublishOnly": "npm run build",
"lint": "eslint ./src",
"testem": "testem",
"test": "nyc --reporter=html --reporter=text ava",
"test:watch": "ava --watch",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"docs": "jsdoc -c jsdoc.json"
},

View File

@ -23,8 +23,8 @@ class Bowser {
* @throws {Error} when UA is not a String
*
* @example
* const bowser = new Bowser(window.navigator.userAgent);
* bowser.getResult()
* const parser = Bowser.getParser(window.navigator.userAgent);
* const result = parser.getResult();
*/
static getParser(UA, skipParsing = false) {
if (typeof UA !== 'string') {
@ -38,6 +38,9 @@ class Bowser {
*
* @param UA
* @return {ParsedResult}
*
* @example
* const result = Bowser.parse(window.navigator.userAgent);
*/
static parse(UA) {
return (new Parser(UA)).getResult();

View File

@ -31,6 +31,23 @@ import {
const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i;
const browsersList = [
/* Googlebot */
{
test: [/googlebot/i],
describe(ua) {
const browser = {
name: 'Googlebot',
};
const version = getFirstMatch(/googlebot\/(\d+(\.\d+))/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Opera < 13.0 */
{
test: [/opera/i],
@ -259,6 +276,21 @@ const browsersList = [
return browser;
},
},
{
test: [/micromessenger/i],
describe(ua) {
const browser = {
name: 'WeChat',
};
const version = getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/msie|trident/i],
describe(ua) {
@ -540,23 +572,6 @@ const browsersList = [
},
},
/* Googlebot */
{
test: [/googlebot/i],
describe(ua) {
const browser = {
name: 'Googlebot',
};
const version = getFirstMatch(/googlebot\/(\d+(\.\d+))/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Something else */
{
test: [/.*/i],

View File

@ -1,6 +1,7 @@
import {
getFirstMatch,
getWindowsVersionName,
getAndroidVersionName,
} from './utils';
export default [
@ -65,10 +66,15 @@ export default [
},
describe(ua) {
const version = getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i, ua);
return {
const versionName = getAndroidVersionName(version);
const os = {
name: 'Android',
version,
};
if (versionName) {
os.versionName = versionName;
}
return os;
},
},

View File

@ -12,6 +12,33 @@ const TYPES_LABELS = {
*/
export default [
/* Googlebot */
{
test: [/googlebot/i],
describe() {
return {
type: 'bot',
vendor: 'Google',
};
},
},
/* Huawei */
{
test: [/huawei/i],
describe(ua) {
const model = getFirstMatch(/(can-l01)/i, ua) && 'Nova';
const platform = {
type: TYPES_LABELS.mobile,
vendor: 'Huawei',
};
if (model) {
platform.model = model;
}
return platform;
},
},
/* Nexus Tablet */
{
test: [/nexus\s*(?:7|8|9|10).*/i],

View File

@ -315,8 +315,7 @@ class Parser {
* @return {ParsedResult}
*/
getResult() {
/* TODO: Make this function pure, return a new object instead of the reference */
return this.parsedResult;
return Object.assign({}, this.parsedResult);
}
/**
@ -395,7 +394,7 @@ class Parser {
}
compareVersion(version) {
let expectedResult = 0;
let expectedResults = [0];
let comparableVersion = version;
let isLoose = false;
@ -405,12 +404,19 @@ class Parser {
return void 0;
}
if (version[0] === '>') {
expectedResult = 1;
comparableVersion = version.substr(1);
} else if (version[0] === '<') {
expectedResult = -1;
if (version[0] === '>' || version[0] === '<') {
comparableVersion = version.substr(1);
if (version[1] === '=') {
isLoose = true;
comparableVersion = version.substr(2);
} else {
expectedResults = [];
}
if (version[0] === '>') {
expectedResults.push(1);
} else {
expectedResults.push(-1);
}
} else if (version[0] === '=') {
comparableVersion = version.substr(1);
} else if (version[0] === '~') {
@ -418,7 +424,9 @@ class Parser {
comparableVersion = version.substr(1);
}
return compareVersions(currentBrowserVersion, comparableVersion, isLoose) === expectedResult;
return expectedResults.indexOf(
compareVersions(currentBrowserVersion, comparableVersion, isLoose),
) > -1;
}
isOS(osName) {
@ -440,7 +448,7 @@ class Parser {
}
/**
* Check if any of the given values satifies this.is(anything)
* Check if any of the given values satisfies this.is(anything)
* @param {String[]} anythings
* @returns {Boolean}
*/

View File

@ -51,6 +51,50 @@ class Utils {
}
}
/**
* Get Android version name
* 1.5 - Cupcake
* 1.6 - Donut
* 2.0 - Eclair
* 2.1 - Eclair
* 2.2 - Froyo
* 2.x - Gingerbread
* 3.x - Honeycomb
* 4.0 - Ice Cream Sandwich
* 4.1 - Jelly Bean
* 4.4 - KitKat
* 5.x - Lollipop
* 6.x - Marshmallow
* 7.x - Nougat
* 8.x - Oreo
* 9.x - ?
*
* @example
* getAndroidVersionName("7.0") // 'Nougat'
*
* @param {string} version
* @return {string} versionName
*/
static getAndroidVersionName(version) {
const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);
v.push(0);
if (v[0] === 1 && v[1] < 5) return undefined;
if (v[0] === 1 && v[1] < 6) return 'Cupcake';
if (v[0] === 1 && v[1] >= 6) return 'Donut';
if (v[0] === 2 && v[1] < 2) return 'Eclair';
if (v[0] === 2 && v[1] === 2) return 'Froyo';
if (v[0] === 2 && v[1] > 2) return 'Gingerbread';
if (v[0] === 3) return 'Honeycomb';
if (v[0] === 4 && v[1] < 1) return 'Ice Cream Sandwich';
if (v[0] === 4 && v[1] < 4) return 'Jelly Bean';
if (v[0] === 4 && v[1] >= 4) return 'KitKat';
if (v[0] === 5) return 'Lollipop';
if (v[0] === 6) return 'Marshmallow';
if (v[0] === 7) return 'Nougat';
if (v[0] === 8) return 'Oreo';
return undefined;
}
/**
* Get version precisions count
*

View File

@ -9,8 +9,8 @@ const listOfUA = yaml.load(path.join(__dirname, 'useragentstrings.yml'));
const browserNames = Object.keys(listOfUA);
browserNames.forEach((browserName) => {
listOfUA[browserName].forEach((browser) => {
test('Check all the test browsers', (t) => {
listOfUA[browserName].forEach((browser, index) => {
test(`Test ${browserName} ${index}`, (t) => {
const parsed = Bowser.parse(browser.ua);
const parsedBuild = BowserBuild.parse(browser.ua);
t.deepEqual(parsed, browser.spec, `${browser.ua}`);

View File

@ -1,5 +1,21 @@
---
Chrome:
-
ua: "Mozilla/5.0 (Linux; Android 7.0; HUAWEI CAN-L01) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.99 Mobile Safari/537.36"
spec:
browser:
name: "Chrome"
version: "71.0.3578.99"
os:
name: "Android"
version: "7.0"
versionName: "Nougat"
platform:
type: "mobile"
vendor: "Huawei"
model: "Nova"
engine:
name: "Blink"
-
ua: "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 9 Build/LMY48T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Safari/537.36"
spec:
@ -9,6 +25,7 @@
os:
name: "Android"
version: "5.1.1"
versionName: "Lollipop"
platform:
type: "tablet"
vendor: "Nexus"
@ -23,6 +40,7 @@
os:
name: "Android"
version: "4.4.2"
versionName: "KitKat"
platform:
type: "tablet"
vendor: "Nexus"
@ -37,6 +55,7 @@
os:
name: "Android"
version: "4.3"
versionName: "Jelly Bean"
platform:
type: "mobile"
vendor: "Nexus"
@ -51,6 +70,7 @@
os:
name: "Android"
version: "4.1"
versionName: "Jelly Bean"
platform:
type: "mobile"
vendor: "Nexus"
@ -66,6 +86,7 @@
os:
name: "Android"
version: "4.0.3"
versionName: "Ice Cream Sandwich"
platform:
type: "tablet"
engine:
@ -80,6 +101,7 @@
os:
name: "Android"
version: "4.0.3"
versionName: "Ice Cream Sandwich"
platform:
type: "mobile"
vendor: "Nexus"
@ -237,6 +259,7 @@
os:
name: "Android"
version: "5.0.2"
versionName: "Lollipop"
platform:
type: "tablet"
engine:
@ -250,6 +273,7 @@
os:
name: "Android"
version: "6.0.99"
versionName: "Marshmallow"
platform:
type: "tablet"
engine:
@ -263,6 +287,7 @@
os:
name: "Android"
version: "7.0"
versionName: "Nougat"
platform:
type: "mobile"
vendor: "Nexus"
@ -277,6 +302,7 @@
os:
name: "Android"
version: "8.0.0"
versionName: "Oreo"
platform:
type: "mobile"
engine:
@ -291,6 +317,7 @@
os:
name: "Android"
version: "4.0.3"
versionName: "Ice Cream Sandwich"
platform:
type: "tablet"
vendor: "Amazon"
@ -322,6 +349,7 @@
os:
name: "Android"
version: "2.3.4"
versionName: "Gingerbread"
platform:
type: "tablet"
vendor: "Amazon"
@ -353,6 +381,7 @@
os:
name: "Android"
version: "4.4.2"
versionName: "KitKat"
platform:
type: "tablet"
vendor: "Nexus"
@ -367,6 +396,7 @@
os:
name: "Android"
version: "4.3"
versionName: "Jelly Bean"
platform:
type: "mobile"
vendor: "Nexus"
@ -395,6 +425,7 @@
os:
name: "Android"
version: "4.3"
versionName: "Jelly Bean"
platform:
type: "mobile"
engine:
@ -409,6 +440,7 @@
os:
name: "Android"
version: "4.4.2"
versionName: "KitKat"
platform:
type: "tablet"
engine:
@ -588,6 +620,7 @@
os:
name: "Android"
version: "6.0"
versionName: "Marshmallow"
platform:
type: "mobile"
engine:
@ -633,6 +666,7 @@
os:
name: "Android"
version: "5.1.1"
versionName: "Lollipop"
platform:
type: "mobile"
vendor: "Nexus"
@ -1309,6 +1343,7 @@
os:
name: "Android"
version: "8.0"
versionName: "Oreo"
platform:
type: "mobile"
engine:
@ -1909,6 +1944,7 @@
os:
name: "Android"
version: "4.4.2"
versionName: "KitKat"
platform:
type: "tablet"
vendor: "Nexus"
@ -1924,6 +1960,7 @@
os:
name: "Android"
version: "4.3"
versionName: "Jelly Bean"
platform:
type: "mobile"
vendor: "Nexus"
@ -1939,6 +1976,7 @@
os:
name: "Android"
version: "4.2"
versionName: "Jelly Bean"
platform:
type: "tablet"
vendor: "Nexus"
@ -1954,6 +1992,7 @@
os:
name: "Android"
version: "3.2"
versionName: "Honeycomb"
platform:
type: "tablet"
engine:
@ -1968,6 +2007,7 @@
os:
name: "Android"
version: "2.3.4"
versionName: "Gingerbread"
platform:
type: "mobile"
engine:
@ -1982,6 +2022,7 @@
os:
name: "Android"
version: "1.6"
versionName: "Donut"
platform:
type: "mobile"
engine:
@ -2191,8 +2232,85 @@
name: "Googlebot"
version: "2.1"
os: {}
platform: {}
platform:
type: "bot"
vendor: "Google"
engine: {}
-
ua: "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
spec:
browser:
name: "Googlebot"
version: "2.1"
os:
name: "Android"
version: "6.0.1"
versionName: "Marshmallow"
platform:
type: "bot"
vendor: "Google"
engine:
name: "Blink"
-
ua: "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Safari/537.36"
spec:
browser:
name: "Googlebot"
version: "2.1"
os: {}
platform:
type: "bot"
vendor: "Google"
engine:
name: "Blink"
WeChat:
-
ua: "Mozilla/5.0 (iPad; U; CPU OS 9 like Mac OS X; en-us; iPad4,4) AppleWebKit/534.46 (KHTML, like Gecko) MicroMessenger/6.5.2.501 U3/1 Safari/7543.48.3"
spec:
browser:
name: "WeChat"
version: "6.5.2.501"
os:
name: "iOS"
version: "9"
platform:
type: "tablet"
vendor: "Apple"
model: "iPad"
engine:
name: "WebKit"
version: "534.46"
-
ua: "Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; SM-T210R Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 MicroMessenger/6.1.0"
spec:
browser:
name: "WeChat"
version: "6.1.0"
os:
name: "Android"
version: "4.1.2"
versionName: "Jelly Bean"
platform:
type: "tablet"
engine:
name: "WebKit"
version: "534.30"
-
ua: "Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_1 like Mac OS X; en-US) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/13E238 MicroMessenger/6.6.1 Mobile"
spec:
browser:
name: "WeChat"
version: "6.6.1"
os:
name: "iOS"
version: "9.3.1"
platform:
type: "mobile"
vendor: "Apple"
model: "iPhone"
engine:
name: "WebKit"
version: "537.51.1"
UC Browser:
-
ua: "Mozilla/5.0 (iPad; U; CPU OS 9 like Mac OS X; en-us; iPad4,4) AppleWebKit/534.46 (KHTML, like Gecko) UCBrowser/2.4.0.367 U3/1 Safari/7543.48.3"
@ -2219,6 +2337,7 @@
os:
name: "Android"
version: "4.1.2"
versionName: "Jelly Bean"
platform:
type: "tablet"
engine:
@ -2410,6 +2529,7 @@
os:
name: "Android"
version: "5.0.2"
versionName: "Lollipop"
platform:
type: "mobile"
engine:
@ -2439,6 +2559,7 @@
os:
name: "Android"
version: "6.0"
versionName: "Marshmallow"
platform:
type: "mobile"
engine:
@ -2453,6 +2574,7 @@
os:
name: "Android"
version: "7.1.1"
versionName: "Nougat"
platform:
type: "tablet"
engine:

View File

@ -63,6 +63,14 @@ test('Parser.satisfies should make simple comparisons', (t) => {
t.is(parser.satisfies({ opera: '<44' }), true);
t.is(parser.satisfies({ opera: '=43.0.2442.1165' }), true);
t.is(parser.satisfies({ opera: '~43.0' }), true);
t.is(parser.satisfies({ opera: '>=43' }), true);
t.is(parser.satisfies({ opera: '<=43' }), true);
t.is(parser.satisfies({ opera: '>=43.0' }), true);
t.is(parser.satisfies({ opera: '>=43.0.2442.1165' }), true);
t.is(parser.satisfies({ opera: '<=43.0.2442.1165' }), true);
t.is(parser.satisfies({ opera: '>=43.0.2443' }), false);
t.is(parser.satisfies({ opera: '<=43.0.2443' }), true);
t.is(parser.satisfies({ opera: '>=43.0.2441' }), true);
t.is(parser.satisfies({ opera: '~43' }), true);
});

View File

@ -4,7 +4,7 @@ module.exports = {
mode: 'production', // "production" | "development" | "none"
// Chosen mode tells webpack to use its built-in optimizations accordingly.
entry: {
bundled: ['babel-polyfill', './src/bowser.js'],
bundled: ['@babel/polyfill', './src/bowser.js'],
es5: './src/bowser.js',
}, // string | object | array
// defaults to ./src