From a307533f74a31e6dd3d675c0b1945a46ea65a148 Mon Sep 17 00:00:00 2001 From: Will Soares Date: Sun, 17 Feb 2019 22:05:40 -0300 Subject: [PATCH 1/4] Add support for using short version for browser name in satisfies --- CONTRIBUTING.md | 11 ++++++++--- src/constants.js | 41 +++++++++++++++++++++++++++++++++++++++++ src/parser.js | 13 ++++++++++--- src/utils.js | 15 +++++++++++++++ test/unit/parser.js | 26 ++++++++++++++++++++++++++ test/unit/utils.js | 6 ++++++ 6 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/constants.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2652439..648ae69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,12 +12,17 @@ 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 camelcase style for names + - whenever possible drop the word `browser` from the original browser name + - remove all dashes from the original browser name + - always check for possible duplicates ## Testing diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..99b543e --- /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': 'amazonSilk', + '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': 'kMeleon', + Maxthon: 'maxthon', + 'Microsoft Edge': 'edge', + 'MZ Browser': 'mz', + 'NAVER Whale Browser': 'naver', + Opera: 'opera', + 'Opera Coast': 'operaCoast', + 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.js b/src/parser.js index daef7aa..eca1ed3 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(getBrowserAlias(defaultBrowserName).toLowerCase()); + } + + return possibleNames.indexOf(browserName.toLowerCase()) !== -1; } compareVersion(version) { diff --git a/src/utils.js b/src/utils.js index 8b12773..8b0a8a3 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,5 @@ +import { BROWSER_ALIASES_MAP } from './constants'; + 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/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); +}); From 064aa812fce716a1d0d02ef40647185bd1b54262 Mon Sep 17 00:00:00 2001 From: Will Soares Date: Mon, 25 Feb 2019 23:23:55 -0300 Subject: [PATCH 2/4] Use snake case for alias names --- CONTRIBUTING.md | 11 +++++++++-- src/constants.js | 20 ++++++++++---------- test/unit/constants.js | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 test/unit/constants.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 648ae69..7400adf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,10 +19,17 @@ See the list in `test/acceptance/useragentstrings.yml` with example user agents 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 camelcase style for names + - use snake_case style for names - whenever possible drop the word `browser` from the original browser name - - remove all dashes from the original browser name + - replace dashes with underscore + - avoid capital letters - 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` --> `sea_monkey` ## Testing diff --git a/src/constants.js b/src/constants.js index 99b543e..fe80944 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,10 +1,10 @@ // NOTE: this list must be up-to-date with browsers listed in // test/acceptance/useragentstrings.yml const BROWSER_ALIASES_MAP = { - 'Amazon Silk': 'amazonSilk', + 'Amazon Silk': 'amazon_silk', 'Android Browser': 'android', Bada: 'bada', - BlackBerry: 'blackBerry', + BlackBerry: 'black_berry', Chrome: 'chrome', Chromium: 'chromium', Epiphany: 'epiphany', @@ -13,27 +13,27 @@ const BROWSER_ALIASES_MAP = { Generic: 'generic', Googlebot: 'googlebot', 'Internet Explorer': 'ie', - 'K-Meleon': 'kMeleon', + 'K-Meleon': 'k_meleon', Maxthon: 'maxthon', 'Microsoft Edge': 'edge', 'MZ Browser': 'mz', 'NAVER Whale Browser': 'naver', Opera: 'opera', - 'Opera Coast': 'operaCoast', - PhantomJS: 'phantomJS', + 'Opera Coast': 'opera_coast', + PhantomJS: 'phantom_js', Puffin: 'puffin', - QupZilla: 'qupZilla', + QupZilla: 'qup_zilla', Safari: 'safari', Sailfish: 'sailfish', - SeaMonkey: 'seaMonkey', + SeaMonkey: 'sea_monkey', Sleipnir: 'sleipnir', Swing: 'swing', Tizen: 'tizen', 'UC Browser': 'uc', Vivaldi: 'vivaldi', - 'WebOS Browser': 'webOS', - WeChat: 'weChat', - 'Yandex Browser': 'yandex', + 'WebOS Browser': 'web_os', + WeChat: 'we_chat', + 'Yandex Browser': 'yandex' }; module.exports = { 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, []); +}); From b111862cce9a9ccb97a27ac353ae855664d5bd9d Mon Sep 17 00:00:00 2001 From: Will Soares Date: Sat, 9 Mar 2019 19:27:28 -0300 Subject: [PATCH 3/4] Update rules for creating browser aliases --- CONTRIBUTING.md | 7 +++---- src/constants.js | 12 ++++++------ src/parser.js | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7400adf..79b896a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,17 +19,16 @@ See the list in `test/acceptance/useragentstrings.yml` with example user agents 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 snake_case style for names + - 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 - - replace dashes with underscore - - avoid capital letters - 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` --> `sea_monkey` +`SeaMonkey` --> `seamonkey` ## Testing diff --git a/src/constants.js b/src/constants.js index fe80944..547ba29 100644 --- a/src/constants.js +++ b/src/constants.js @@ -4,7 +4,7 @@ const BROWSER_ALIASES_MAP = { 'Amazon Silk': 'amazon_silk', 'Android Browser': 'android', Bada: 'bada', - BlackBerry: 'black_berry', + BlackBerry: 'blackberry', Chrome: 'chrome', Chromium: 'chromium', Epiphany: 'epiphany', @@ -20,19 +20,19 @@ const BROWSER_ALIASES_MAP = { 'NAVER Whale Browser': 'naver', Opera: 'opera', 'Opera Coast': 'opera_coast', - PhantomJS: 'phantom_js', + PhantomJS: 'phantomjs', Puffin: 'puffin', - QupZilla: 'qup_zilla', + QupZilla: 'qupzilla', Safari: 'safari', Sailfish: 'sailfish', - SeaMonkey: 'sea_monkey', + SeaMonkey: 'seamonkey', Sleipnir: 'sleipnir', Swing: 'swing', Tizen: 'tizen', 'UC Browser': 'uc', Vivaldi: 'vivaldi', - 'WebOS Browser': 'web_os', - WeChat: 'we_chat', + 'WebOS Browser': 'webos', + WeChat: 'wechat', 'Yandex Browser': 'yandex' }; diff --git a/src/parser.js b/src/parser.js index eca1ed3..88706a8 100644 --- a/src/parser.js +++ b/src/parser.js @@ -407,7 +407,7 @@ class Parser { const possibleNames = [defaultBrowserName.toLowerCase()]; if (loosely) { - possibleNames.push(getBrowserAlias(defaultBrowserName).toLowerCase()); + possibleNames.push(Utils.getBrowserAlias(defaultBrowserName).toLowerCase()); } return possibleNames.indexOf(browserName.toLowerCase()) !== -1; From ace7a8899b0bb495b6a2bdc34abb9e4c383da36b Mon Sep 17 00:00:00 2001 From: Will Soares Date: Sat, 9 Mar 2019 19:29:34 -0300 Subject: [PATCH 4/4] Fix eslint errors --- src/constants.js | 2 +- src/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/constants.js b/src/constants.js index 547ba29..d0e084c 100644 --- a/src/constants.js +++ b/src/constants.js @@ -33,7 +33,7 @@ const BROWSER_ALIASES_MAP = { Vivaldi: 'vivaldi', 'WebOS Browser': 'webos', WeChat: 'wechat', - 'Yandex Browser': 'yandex' + 'Yandex Browser': 'yandex', }; module.exports = { diff --git a/src/utils.js b/src/utils.js index 8b0a8a3..942c3db 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,4 @@ -import { BROWSER_ALIASES_MAP } from './constants'; +import { BROWSER_ALIASES_MAP } from './constants.js'; export default class Utils { /**