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

Merge branch 'release/2.0.0-beta.1'

This commit is contained in:
Denis Demchenko 2018-08-18 14:20:19 +03:00
commit 505f19f207
15 changed files with 102 additions and 42 deletions

View File

@ -1,5 +1,10 @@
# Bowser Changelog # Bowser Changelog
### 2.0.0-beta.1 (August 18, 2018)
- [ADD] Add loose version comparison to `Parser.compareVersion()` and `Parser.satisfies()`
- [CHORE] Add CONTRIBUTING.md
- [DOCS] Regenerate docs
### 2.0.0-alpha.4 (August 2, 2018) ### 2.0.0-alpha.4 (August 2, 2018)
- [DOCS] Fix usage docs (#238) - [DOCS] Fix usage docs (#238)
- [CHANGE] Make `./es5.js` the main file of the package (#239) - [CHANGE] Make `./es5.js` the main file of the package (#239)

7
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,7 @@
# Contributing
The project runs Git-flow, where the `master` branch is the production one and the `develop` is the developing 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.
Following these simple rules will help to maintain the repo a lot! Thanks ❤️

View File

@ -111,6 +111,13 @@ const isValidBrowser = browser.satisfies({
chrome: ">20.1.1432", chrome: ">20.1.1432",
firefox: ">31", firefox: ">31",
opera: ">22" opera: ">22"
// also supports equality operator
chrome: "=20.1.1432", // will match particular build only
// and loose-equality operator
chrome: "~20" // will match any 20.* sub-version
chrome: "~20.1" // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1)
}); });
``` ```

View File

@ -559,7 +559,7 @@ bowser.getResult()</code></pre>
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -1558,7 +1558,7 @@ like <a href="Parser.html#parseBrowser">Parser#parseBrowser</a> or <a href="Pars
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line427">line 427</a> <a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line432">line 432</a>
</li></ul></dd> </li></ul></dd>
@ -2376,7 +2376,7 @@ Returns <code>undefined</code> when the browser is no described in the checkTree
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line436">line 436</a> <a href="parser.js.html">parser.js</a>, <a href="parser.js.html#line441">line 441</a>
</li></ul></dd> </li></ul></dd>
@ -2679,7 +2679,7 @@ Returns <code>undefined</code> when the browser is no described in the checkTree
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -65,7 +65,7 @@ class Bowser {
* const bowser = new Bowser(window.navigator.userAgent); * const bowser = new Bowser(window.navigator.userAgent);
* bowser.getResult() * bowser.getResult()
*/ */
static getParser(UA, skipParsing=false) { static getParser(UA, skipParsing = false) {
if (typeof UA !== 'string') { if (typeof UA !== 'string') {
throw new Error('UserAgent should be a string'); throw new Error('UserAgent should be a string');
} }
@ -96,7 +96,7 @@ export default Bowser;
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -758,7 +758,7 @@ like <code>&quot;iPhone&quot;</code> or <code>&quot;Kindle Fire HD 7&quot;</code
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -59,13 +59,12 @@
<p><strong>Changes of the 2.0</strong> <p><strong>Changes of the 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> 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> <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>ES6 version of files</em>, which <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> <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. <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.
So, for you it's suitable to require bowser like this: <code>require('bowser/bundled')</code>. 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> As the result, you get a ES5 version of bowser with <code>babel-polyfill</code> bundled together.</p>
<p>If you use bowser for Node.js, you'd better use <code>require('bowser/es5')</code>, <p>You may need to use the source files, so they will be available in the package as well.</p>
since source files have <code>import</code> statements, which are not compatible with Node.js yet.</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 make it with Bowser:</p>
<pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent); <pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
@ -100,7 +99,7 @@ console.log(impression.userTechData);
} }
}</code></pre><h2>Filtering browsers</h2><p>You could want to filter some particular browsers to provide any special support for them or make any workarounds. }</code></pre><h2>Filtering browsers</h2><p>You could want to filter some particular browsers to provide any special support for them or make any workarounds.
It could look like this:</p> It could look like this:</p>
<pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParsers(window.navigator.userAgent); <pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
const isValidBrowser = browser.satisfies({ const isValidBrowser = browser.satisfies({
// declare browsers per OS // declare browsers per OS
windows: { windows: {
@ -120,6 +119,13 @@ const isValidBrowser = browser.satisfies({
chrome: &quot;>20.1.1432&quot;, chrome: &quot;>20.1.1432&quot;,
firefox: &quot;>31&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
// and loose-equality operator
chrome: &quot;~20&quot; // will match any 20.* sub-version
chrome: &quot;~20.1&quot; // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1)
});</code></pre><p>Settings for any particular OS or platform has more priority and redefines settings of standalone browsers. });</code></pre><p>Settings for any particular OS or platform has more priority and redefines settings of standalone browsers.
Thus, you can define OS or platform specific rules and they will have more priority in the end.</p> 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> <p>More of API and possibilities you will find in the <code>docs</code> folder.</p>
@ -144,7 +150,7 @@ check if all tests are still passing.</p>
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -436,6 +436,7 @@ class Parser {
compareVersion(version) { compareVersion(version) {
let expectedResult = 0; let expectedResult = 0;
let comparableVersion = version; let comparableVersion = version;
let isLoose = false;
if (version[0] === '>') { if (version[0] === '>') {
expectedResult = 1; expectedResult = 1;
@ -445,8 +446,12 @@ class Parser {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} else if (version[0] === '=') { } else if (version[0] === '=') {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} else if (version[0] === '~') {
isLoose = true;
comparableVersion = version.substr(1);
} }
return compareVersions(this.getBrowserVersion(), comparableVersion) === expectedResult;
return compareVersions(this.getBrowserVersion(), comparableVersion, isLoose) === expectedResult;
} }
isOS(osName) { isOS(osName) {
@ -490,7 +495,7 @@ export default Parser;
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -107,23 +107,26 @@
* Calculate browser version weight * Calculate browser version weight
* *
* @example * @example
* compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 * compareVersions('1.10.2.1', '1.8.2.1.90') // 1
* compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 * compareVersions('1.010.2.1', '1.09.2.1.90'); // 1
* compareVersions(['1.10.2.1', '1.10.2.1']); // 0 * compareVersions('1.10.2.1', '1.10.2.1'); // 0
* compareVersions(['1.10.2.1', '1.0800.2']); // -1 * compareVersions('1.10.2.1', '1.0800.2'); // -1
* compareVersions('1.10.2.1', '1.10', true); // 0
* *
* @param {String} versionA versions versions to compare * @param {String} versionA versions versions to compare
* @param {String} versionB versions versions to compare * @param {String} versionB versions versions to compare
* @param {boolean} [isLoose] enable loose comparison
* @return {Number} comparison result: -1 when versionA is lower, * @return {Number} comparison result: -1 when versionA is lower,
* 1 when versionA is bigger, 0 when both equal * 1 when versionA is bigger, 0 when both equal
*/ */
/* eslint consistent-return: 1 */ /* eslint consistent-return: 1 */
static compareVersions(versionA, versionB) { static compareVersions(versionA, versionB, isLoose = false) {
// 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2
let precision = Math.max( const versionAPrecision = Utils.getVersionPrecision(versionA);
Utils.getVersionPrecision(versionA), const versionBPrecision = Utils.getVersionPrecision(versionB);
Utils.getVersionPrecision(versionB),
); let precision = Math.max(versionAPrecision, versionBPrecision);
let lastPrecision = 0;
const chunks = Utils.map([versionA, versionB], (version) => { const chunks = Utils.map([versionA, versionB], (version) => {
const delta = precision - Utils.getVersionPrecision(version); const delta = precision - Utils.getVersionPrecision(version);
@ -135,14 +138,19 @@
return Utils.map(_version.split('.'), chunk => new Array(20 - chunk.length).join('0') + chunk).reverse(); return Utils.map(_version.split('.'), chunk => new Array(20 - chunk.length).join('0') + chunk).reverse();
}); });
// adjust precision for loose comparison
if (isLoose) {
lastPrecision = precision - Math.min(versionAPrecision, versionBPrecision);
}
// iterate in reverse order by reversed chunks array // iterate in reverse order by reversed chunks array
precision -= 1; precision -= 1;
while (precision >= 0) { while (precision >= lastPrecision) {
// 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true)
if (chunks[0][precision] > chunks[1][precision]) { if (chunks[0][precision] > chunks[1][precision]) {
return 1; return 1;
} else if (chunks[0][precision] === chunks[1][precision]) { } else if (chunks[0][precision] === chunks[1][precision]) {
if (precision === 0) { if (precision === lastPrecision) {
// all version chunks are same // all version chunks are same
return 0; return 0;
} }
@ -186,7 +194,7 @@ module.exports = Utils;
<br class="clear"> <br class="clear">
<footer> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jul 22 2018 19:42:18 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 Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> </footer>
<script>prettyPrint();</script> <script>prettyPrint();</script>

View File

@ -1,6 +1,6 @@
{ {
"name": "bowser", "name": "bowser",
"version": "2.0.0-alpha.4", "version": "2.0.0-beta.1",
"description": "Lightweight browser detector", "description": "Lightweight browser detector",
"keywords": [ "keywords": [
"browser", "browser",

View File

@ -397,6 +397,7 @@ class Parser {
compareVersion(version) { compareVersion(version) {
let expectedResult = 0; let expectedResult = 0;
let comparableVersion = version; let comparableVersion = version;
let isLoose = false;
if (version[0] === '>') { if (version[0] === '>') {
expectedResult = 1; expectedResult = 1;
@ -406,8 +407,12 @@ class Parser {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} else if (version[0] === '=') { } else if (version[0] === '=') {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} else if (version[0] === '~') {
isLoose = true;
comparableVersion = version.substr(1);
} }
return compareVersions(this.getBrowserVersion(), comparableVersion) === expectedResult;
return compareVersions(this.getBrowserVersion(), comparableVersion, isLoose) === expectedResult;
} }
isOS(osName) { isOS(osName) {

View File

@ -68,23 +68,26 @@ class Utils {
* Calculate browser version weight * Calculate browser version weight
* *
* @example * @example
* compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 * compareVersions('1.10.2.1', '1.8.2.1.90') // 1
* compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 * compareVersions('1.010.2.1', '1.09.2.1.90'); // 1
* compareVersions(['1.10.2.1', '1.10.2.1']); // 0 * compareVersions('1.10.2.1', '1.10.2.1'); // 0
* compareVersions(['1.10.2.1', '1.0800.2']); // -1 * compareVersions('1.10.2.1', '1.0800.2'); // -1
* compareVersions('1.10.2.1', '1.10', true); // 0
* *
* @param {String} versionA versions versions to compare * @param {String} versionA versions versions to compare
* @param {String} versionB versions versions to compare * @param {String} versionB versions versions to compare
* @param {boolean} [isLoose] enable loose comparison
* @return {Number} comparison result: -1 when versionA is lower, * @return {Number} comparison result: -1 when versionA is lower,
* 1 when versionA is bigger, 0 when both equal * 1 when versionA is bigger, 0 when both equal
*/ */
/* eslint consistent-return: 1 */ /* eslint consistent-return: 1 */
static compareVersions(versionA, versionB) { static compareVersions(versionA, versionB, isLoose = false) {
// 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2
let precision = Math.max( const versionAPrecision = Utils.getVersionPrecision(versionA);
Utils.getVersionPrecision(versionA), const versionBPrecision = Utils.getVersionPrecision(versionB);
Utils.getVersionPrecision(versionB),
); let precision = Math.max(versionAPrecision, versionBPrecision);
let lastPrecision = 0;
const chunks = Utils.map([versionA, versionB], (version) => { const chunks = Utils.map([versionA, versionB], (version) => {
const delta = precision - Utils.getVersionPrecision(version); const delta = precision - Utils.getVersionPrecision(version);
@ -96,14 +99,19 @@ class Utils {
return Utils.map(_version.split('.'), chunk => new Array(20 - chunk.length).join('0') + chunk).reverse(); return Utils.map(_version.split('.'), chunk => new Array(20 - chunk.length).join('0') + chunk).reverse();
}); });
// adjust precision for loose comparison
if (isLoose) {
lastPrecision = precision - Math.min(versionAPrecision, versionBPrecision);
}
// iterate in reverse order by reversed chunks array // iterate in reverse order by reversed chunks array
precision -= 1; precision -= 1;
while (precision >= 0) { while (precision >= lastPrecision) {
// 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true)
if (chunks[0][precision] > chunks[1][precision]) { if (chunks[0][precision] > chunks[1][precision]) {
return 1; return 1;
} else if (chunks[0][precision] === chunks[1][precision]) { } else if (chunks[0][precision] === chunks[1][precision]) {
if (precision === 0) { if (precision === lastPrecision) {
// all version chunks are same // all version chunks are same
return 0; return 0;
} }

View File

@ -57,8 +57,13 @@ test('Skip parsing shouldn\'t parse', (t) => {
t.deepEqual((new Parser(UA, true)).getResult(), {}); t.deepEqual((new Parser(UA, true)).getResult(), {});
}); });
test('Parser.check should make simple comparison', (t) => { test('Parser.check should make simple comparisons', (t) => {
// also covers Parser.compareVersion() method
t.is(parser.satisfies({ opera: '>42' }), true); t.is(parser.satisfies({ opera: '>42' }), true);
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);
}); });
test('Parser.check should make complex comparison', (t) => { test('Parser.check should make complex comparison', (t) => {

View File

@ -22,6 +22,9 @@ test('compareVersions', (t) => {
['1.10.2.1', '1.8.2.1.90', 1], ['1.10.2.1', '1.8.2.1.90', 1],
['1.010.2.1', '1.08.2.1.90', 1], ['1.010.2.1', '1.08.2.1.90', 1],
['1.10.2.1', '1.10.2.1', 0], ['1.10.2.1', '1.10.2.1', 0],
['1.10.2.1', '1.10.2', 0, true],
['1.10.2.1', '1.10', 0, true],
['1.10.2.1', '1', 0, true],
['1.10.2.1', '1.0800.2', -1], ['1.10.2.1', '1.0800.2', -1],
['1.0.0-alpha', '1.0.0-alpha.1', -1], ['1.0.0-alpha', '1.0.0-alpha.1', -1],
['1.0.0-alpha.1', '1.0.0-alpha.beta', -1], ['1.0.0-alpha.1', '1.0.0-alpha.beta', -1],
@ -35,7 +38,8 @@ test('compareVersions', (t) => {
const versionA = testingParams[0]; const versionA = testingParams[0];
const versionB = testingParams[1]; const versionB = testingParams[1];
const result = testingParams[2]; const result = testingParams[2];
let matching = ' == '; const isLoose = testingParams.length > 3 ? testingParams[3] : false;
let matching = isLoose ? '~' : ' == ';
if (result > 0) { if (result > 0) {
matching = ' > '; matching = ' > ';
@ -43,6 +47,6 @@ test('compareVersions', (t) => {
matching = ' < '; matching = ' < ';
} }
t.is(compareVersions(versionA, versionB), result, `version ${versionA} should be ${matching} version ${versionB}`); t.is(compareVersions(versionA, versionB, isLoose), result, `version ${versionA} should be ${matching} version ${versionB}`);
}); });
}); });