diff --git a/CHANGELOG.md b/CHANGELOG.md index d090085..2a30be6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Bowser Changelog +### 2.2.0 (April 7, 2019) +- [ADD] Add short aliases for browser names (#295) +- [FIX] Fix Yandex Browser version detection (#308) + ### 2.1.2 (March 6, 2019) - [FIX] Fix buggy `getFirstMatch` reference diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2652439..79b896a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,12 +12,23 @@ If it's a small hot-fix, an improvement to the docs, or added support for a new Following these simple rules will really help maintain the repo! Thanks ❤️ -## Adding Tests +## Adding Browser Support and Tests See the list in `test/acceptance/useragentstrings.yml` with example user agents and their expected `bowser` object. -Whenever you add support for new browsers or notice a bug / mismatch, please update the list and -check if all tests are still passing. +Whenever you add support for new browsers or notice a bug / mismatch, please update the list and check if all tests are still passing. Also, make sure to keep the list of browser aliases up-to-date in `src/constants.js`. + +For creating aliases, keep the following guidelines in mind: + - use only lowercase letters for names + - replace special characters such as space and dashes by underscore + - whenever possible drop the word `browser` from the original browser name + - always check for possible duplicates + - aliases are supposed to also be a shorter version of the original name + +Examples: +`Opera Coast` --> `opera_coast` +`UC Browser` --> `uc` +`SeaMonkey` --> `seamonkey` ## Testing diff --git a/README.md b/README.md index c130864..7a2b381 100644 --- a/README.md +++ b/README.md @@ -131,8 +131,14 @@ 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. -### Similar Projects +### Browser names for `.satisfies()` + +By default you are supposed to use the full browser name for `.satisfies`. +But, there's a short way to define a browser using short aliases. The full +list of aliases can be found in [the file](src/constants.js). + +## Similar Projects * [Kong](https://github.com/BigBadBleuCheese/Kong) - A C# port of Bowser. -### License +## License Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. diff --git a/docs/Bowser.html b/docs/Bowser.html index 8971ea5..57ecfa7 100644 --- a/docs/Bowser.html +++ b/docs/Bowser.html @@ -26,7 +26,7 @@
@@ -572,7 +572,7 @@ const result = parser.getResult();
diff --git a/docs/Parser.html b/docs/Parser.html index cae36d6..7f0c240 100644 --- a/docs/Parser.html +++ b/docs/Parser.html @@ -26,7 +26,7 @@
@@ -1670,7 +1670,7 @@ like Parser#parseBrowser or Source:
@@ -2488,7 +2488,7 @@ Returns undefined when the browser is no described in the checkTree
Source:
@@ -2793,7 +2793,7 @@ Returns undefined when the browser is no described in the checkTree
- Documentation generated by JSDoc 3.5.5 on Wed Mar 06 2019 14:31:23 GMT+0200 (EET) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Sun Apr 07 2019 11:48:14 GMT+0300 (EEST) using the docdash theme.
diff --git a/docs/bowser.js.html b/docs/bowser.js.html index a3c551b..005f8b9 100644 --- a/docs/bowser.js.html +++ b/docs/bowser.js.html @@ -26,7 +26,7 @@
@@ -105,7 +105,7 @@ export default Bowser;
- Documentation generated by JSDoc 3.5.5 on Wed Mar 06 2019 14:31:23 GMT+0200 (EET) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Sun Apr 07 2019 11:48:14 GMT+0300 (EEST) using the docdash theme.
diff --git a/docs/global.html b/docs/global.html index 6b7e103..73ac0ef 100644 --- a/docs/global.html +++ b/docs/global.html @@ -26,7 +26,7 @@
@@ -133,7 +133,7 @@
Source:
@@ -296,6 +296,162 @@ +

getBrowserAlias(browserName) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get short version/alias for a browser name

+
+ + + + + + + + + +
Example
+ +
getBrowserAlias('Microsoft Edge') // edge
+ + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
browserName + + +string + + + +
+ + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + +

getFirstMatch(regexp, ua) → {Array|Object|*|boolean|string}

@@ -308,7 +464,7 @@
Source:
@@ -494,7 +650,7 @@
Source:
@@ -675,7 +831,7 @@
Source:
@@ -831,7 +987,7 @@
Source:
@@ -1005,7 +1161,7 @@
Source:
@@ -1839,7 +1995,7 @@ like "iPhone" or "Kindle Fire HD 7"
- Documentation generated by JSDoc 3.5.5 on Wed Mar 06 2019 14:31:23 GMT+0200 (EET) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Sun Apr 07 2019 11:48:14 GMT+0300 (EEST) using the docdash theme.
diff --git a/docs/index.html b/docs/index.html index 6a8be54..71f986f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -26,7 +26,7 @@
@@ -136,10 +136,13 @@ const isValidBrowser = browser.satisfies({ });

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.

More of API and possibilities you will find in the docs folder.

-

Similar Projects

    +

    Browser names for .satisfies()

    By default you are supposed to use the full browser name for .satisfies. +But, there's a short way to define a browser using short aliases. The full +list of aliases can be found in the file.

    +

    Similar Projects

    • Kong - A C# port of Bowser.
    -

    License

    Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.

    +

    License

    Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.

    @@ -154,7 +157,7 @@ Thus, you can define OS or platform specific rules and they will have more prior
    - Documentation generated by JSDoc 3.5.5 on Wed Mar 06 2019 14:31:23 GMT+0200 (EET) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Sun Apr 07 2019 11:48:14 GMT+0300 (EEST) using the docdash theme.
    diff --git a/docs/parser.js.html b/docs/parser.js.html index ef5bcc6..9f54378 100644 --- a/docs/parser.js.html +++ b/docs/parser.js.html @@ -26,7 +26,7 @@
    @@ -435,7 +435,7 @@ class Parser { if (browsersCounter > 0) { const browserNames = Object.keys(browsers); - const matchingDefinition = browserNames.find(name => (this.isBrowser(name))); + const matchingDefinition = browserNames.find(name => (this.isBrowser(name, true))); if (matchingDefinition !== void 0) { return this.compareVersion(browsers[matchingDefinition]); @@ -445,8 +445,15 @@ class Parser { return undefined; } - isBrowser(browserName) { - return this.getBrowserName(true) === String(browserName).toLowerCase(); + isBrowser(browserName, loosely = false) { + const defaultBrowserName = this.getBrowserName(); + const possibleNames = [defaultBrowserName.toLowerCase()]; + + if (loosely) { + possibleNames.push(Utils.getBrowserAlias(defaultBrowserName).toLowerCase()); + } + + return possibleNames.indexOf(browserName.toLowerCase()) !== -1; } compareVersion(version) { @@ -532,7 +539,7 @@ export default Parser;
    - Documentation generated by JSDoc 3.5.5 on Wed Mar 06 2019 14:31:23 GMT+0200 (EET) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Sun Apr 07 2019 11:48:14 GMT+0300 (EEST) using the docdash theme.
    diff --git a/docs/utils.js.html b/docs/utils.js.html index 4e1bdcb..184707c 100644 --- a/docs/utils.js.html +++ b/docs/utils.js.html @@ -26,7 +26,7 @@
    @@ -41,7 +41,9 @@
    -
    export default class Utils {
    +            
    import { BROWSER_ALIASES_MAP } from './constants.js';
    +
    +export default class Utils {
       /**
        * Get first matched item for a string
        * @param {RegExp} regexp
    @@ -230,6 +232,19 @@
         }
         return result;
       }
    +
    +  /**
    +   * Get short version/alias for a browser name
    +   *
    +   * @example
    +   *   getBrowserAlias('Microsoft Edge') // edge
    +   *
    +   * @param  {string} browserName
    +   * @return {string}
    +   */
    +  static getBrowserAlias(browserName) {
    +    return BROWSER_ALIASES_MAP[browserName];
    +  }
     }
     
    @@ -245,7 +260,7 @@
    - Documentation generated by JSDoc 3.5.5 on Wed Mar 06 2019 14:31:23 GMT+0200 (EET) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Sun Apr 07 2019 11:48:14 GMT+0300 (EEST) using the docdash theme.
    diff --git a/package-lock.json b/package-lock.json index 35fbd7b..fc5383e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bowser", - "version": "2.1.2", + "version": "2.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f199a70..9db9c71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bowser", - "version": "2.1.2", + "version": "2.2.0", "description": "Lightweight browser detector", "keywords": [ "browser", diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..d0e084c --- /dev/null +++ b/src/constants.js @@ -0,0 +1,41 @@ +// NOTE: this list must be up-to-date with browsers listed in +// test/acceptance/useragentstrings.yml +const BROWSER_ALIASES_MAP = { + 'Amazon Silk': 'amazon_silk', + 'Android Browser': 'android', + Bada: 'bada', + BlackBerry: 'blackberry', + Chrome: 'chrome', + Chromium: 'chromium', + Epiphany: 'epiphany', + Firefox: 'firefox', + Focus: 'focus', + Generic: 'generic', + Googlebot: 'googlebot', + 'Internet Explorer': 'ie', + 'K-Meleon': 'k_meleon', + Maxthon: 'maxthon', + 'Microsoft Edge': 'edge', + 'MZ Browser': 'mz', + 'NAVER Whale Browser': 'naver', + Opera: 'opera', + 'Opera Coast': 'opera_coast', + PhantomJS: 'phantomjs', + Puffin: 'puffin', + QupZilla: 'qupzilla', + Safari: 'safari', + Sailfish: 'sailfish', + SeaMonkey: 'seamonkey', + Sleipnir: 'sleipnir', + Swing: 'swing', + Tizen: 'tizen', + 'UC Browser': 'uc', + Vivaldi: 'vivaldi', + 'WebOS Browser': 'webos', + WeChat: 'wechat', + 'Yandex Browser': 'yandex', +}; + +module.exports = { + BROWSER_ALIASES_MAP, +}; diff --git a/src/parser-browsers.js b/src/parser-browsers.js index 74b2bad..fd9469f 100644 --- a/src/parser-browsers.js +++ b/src/parser-browsers.js @@ -174,7 +174,7 @@ const browsersList = [ const browser = { name: 'Yandex Browser', }; - const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i, ua); + const version = Utils.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); if (version) { browser.version = version; diff --git a/src/parser.js b/src/parser.js index daef7aa..88706a8 100644 --- a/src/parser.js +++ b/src/parser.js @@ -392,7 +392,7 @@ class Parser { if (browsersCounter > 0) { const browserNames = Object.keys(browsers); - const matchingDefinition = browserNames.find(name => (this.isBrowser(name))); + const matchingDefinition = browserNames.find(name => (this.isBrowser(name, true))); if (matchingDefinition !== void 0) { return this.compareVersion(browsers[matchingDefinition]); @@ -402,8 +402,15 @@ class Parser { return undefined; } - isBrowser(browserName) { - return this.getBrowserName(true) === String(browserName).toLowerCase(); + isBrowser(browserName, loosely = false) { + const defaultBrowserName = this.getBrowserName(); + const possibleNames = [defaultBrowserName.toLowerCase()]; + + if (loosely) { + possibleNames.push(Utils.getBrowserAlias(defaultBrowserName).toLowerCase()); + } + + return possibleNames.indexOf(browserName.toLowerCase()) !== -1; } compareVersion(version) { diff --git a/src/utils.js b/src/utils.js index 8b12773..942c3db 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,5 @@ +import { BROWSER_ALIASES_MAP } from './constants.js'; + export default class Utils { /** * Get first matched item for a string @@ -187,4 +189,17 @@ export default class Utils { } return result; } + + /** + * Get short version/alias for a browser name + * + * @example + * getBrowserAlias('Microsoft Edge') // edge + * + * @param {string} browserName + * @return {string} + */ + static getBrowserAlias(browserName) { + return BROWSER_ALIASES_MAP[browserName]; + } } diff --git a/test/acceptance/useragentstrings.yml b/test/acceptance/useragentstrings.yml index 5c05906..d3bd9b0 100644 --- a/test/acceptance/useragentstrings.yml +++ b/test/acceptance/useragentstrings.yml @@ -673,6 +673,22 @@ vendor: "Nexus" engine: name: "Blink" + - + ua: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 YaBrowser/19.3.3.157.10 Mobile/15E148 Safari/605.1" + spec: + browser: + name: "Yandex Browser" + version: "19.3.3.157.10" + os: + name: "iOS" + version: "12.2" + platform: + type: "mobile" + vendor: "Apple" + model: "iPhone" + engine: + name: "WebKit" + version: "605.1.15" Safari: - ua: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2" diff --git a/test/unit/constants.js b/test/unit/constants.js new file mode 100644 index 0000000..a8b2be6 --- /dev/null +++ b/test/unit/constants.js @@ -0,0 +1,15 @@ +import test from 'ava'; +import { BROWSER_ALIASES_MAP } from '../../src/constants'; + +test('check duplicate aliases', (t) => { + const aliasesList = Object.keys(BROWSER_ALIASES_MAP).map(value => (BROWSER_ALIASES_MAP[value])); + let foundOnce, foundTwice; + + const duplicates = aliasesList.filter(item => { + foundOnce = aliasesList.indexOf(item); + foundTwice = aliasesList.indexOf(item, foundOnce + 1); + return +foundTwice !== -1; + }); + + t.deepEqual(duplicates, []); +}); diff --git a/test/unit/parser.js b/test/unit/parser.js index 17a020f..10ec0d4 100644 --- a/test/unit/parser.js +++ b/test/unit/parser.js @@ -5,6 +5,9 @@ import Parser from '../../src/parser'; const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1165'; const parser = new Parser(UA, true); +const EDGE_UA = 'Mozilla/5.0 (Linux; Android 8.0; Pixel XL Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.0 Mobile Safari/537.36 EdgA/41.1.35.1'; +const edgeParser = new Parser(EDGE_UA, true); + test('constructor', (t) => { t.truthy(parser instanceof Parser); }); @@ -145,6 +148,13 @@ test('Parser.satisfies for versionless UA strings', (t) => { }), void 0); }); +test('Parser.satisfies should consider aliases while handling browsers', (t) => { + t.is(edgeParser.satisfies({ 'Microsoft Edge': '=41.1.35.1' }), true); + t.is(edgeParser.satisfies({ 'microsoft edge': '=41.1.35.1' }), true); + t.is(edgeParser.satisfies({ 'edge': '=41.1.35.1' }), true); + t.is(edgeParser.satisfies({ 'Edge': '=41.1.35.1' }), true); +}); + test('Parser.is should pass', (t) => { t.is(parser.is('opera'), true); t.is(parser.is('desktop'), true); @@ -158,3 +168,19 @@ test('Parser.some should pass', (t) => { t.is(parser.some([]), false); t.is(parser.some(), false); }); + +test('Parser.isBrowser should pass when not loosely checking', (t) => { + t.is(edgeParser.isBrowser('Microsoft Edge', false), true); + t.is(edgeParser.isBrowser('microsoft edge', false), true); + t.is(edgeParser.isBrowser('mIcrosoft eDge', false), true); + t.is(edgeParser.isBrowser('edge', false), false); + t.is(edgeParser.isBrowser('Edge', false), false); +}); + +test('Parser.isBrowser should pass when loosely checking', (t) => { + t.is(edgeParser.isBrowser('Microsoft Edge', true), true); + t.is(edgeParser.isBrowser('microsoft edge', true), true); + t.is(edgeParser.isBrowser('mIcrosoft eDge', true), true); + t.is(edgeParser.isBrowser('edge', true), true); + t.is(edgeParser.isBrowser('Edge', true), true); +}); diff --git a/test/unit/utils.js b/test/unit/utils.js index 4d73cbc..ecbf85f 100644 --- a/test/unit/utils.js +++ b/test/unit/utils.js @@ -1,5 +1,6 @@ import test from 'ava'; import { + getBrowserAlias, getFirstMatch, getWindowsVersionName, compareVersions, @@ -50,3 +51,8 @@ test('compareVersions', (t) => { t.is(compareVersions(versionA, versionB, isLoose), result, `version ${versionA} should be ${matching} version ${versionB}`); }); }); + +test('getBrowserAlias', (t) => { + t.is(getBrowserAlias('Microsoft Edge'), 'edge'); + t.is(getBrowserAlias('Unexisting Browser'), void 0); +});