diff --git a/README.md b/README.md index 9d51aead..66a6821b 100644 --- a/README.md +++ b/README.md @@ -522,6 +522,13 @@ Options: * `normalizers`: An array of names of normalizers below and functions that accept a browser and return the normalized versions, which are applied to resolved browsers in order. For instance, `['byEngine', 'toDesktop']`. + * `byEngine`: Normalize Chromium-based browsers to Chrome. For instance, + UC Browser, QQ Browser, Baidu browser for Android, and Samsung Internet + will return `and_chr` with the version of Chromium they are based on. + Note Edge and Opera is not normalized. Gecko-based browsers are + also normalized to Firefox, e.g., KaiOS Browser will return `and_ff`. + * `toDesktop`: Normalize mobile browsers to desktop browsers. + For instance, Browserslist will return `chrome 20` on `and_chr 20` For non-JS environment and debug purpose you can use CLI tool: diff --git a/index.js b/index.js index 0601f4f3..548912ac 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ var env = require('./node') // Will load browser.js in webpack var YEAR = 365.259641 * 24 * 60 * 60 * 1000 var ANDROID_EVERGREEN_FIRST = 37 +var ANDROID_CLASSIC_REGEX = /^(?:[2-4]\.|[34]$)/ var QUERY_OR = 1 var QUERY_AND = 2 @@ -265,7 +266,7 @@ function normalizeAndroidVersions (androidVersions, chromeVersions) { var firstEvergreen = ANDROID_EVERGREEN_FIRST var last = chromeVersions[chromeVersions.length - 1] return androidVersions - .filter(function (version) { return /^(?:[2-4]\.|[34]$)/.test(version) }) + .filter(function (version) { return ANDROID_CLASSIC_REGEX.test(version) }) .concat(chromeVersions.slice(firstEvergreen - last - 1)) } @@ -563,6 +564,38 @@ browserslist.desktopNames = { android: 'chrome' // has extra processing logic } +// Tools such as compat-table only provides compatibility data for +// popular browsers. Fallback to Chrome for Chromium-based browsers +// and Firefox for Gecko-based browsers. A number indicates `and_chr` +browserslist.normalizedVersions = { + // From Samsung Internet release notes at + // https://developer.samsung.com/internet/release-note.html, + // Chrome version page (chrome://version), and the user agent string + 'samsung 4': 44, + 'samsung 5': 51, + 'samsung 6': 56, + 'samsung 7': 59, + 'samsung 8': 63, + 'samsung 9': 67, + 'samsung 10': 71, + 'samsung 11': 75, + 'samsung 12': 79, + + // From the kernel version at https://plus.ucweb.com/download/ + // and the user agent string + 'and_uc 11': 40, + 'and_uc 12': 57, + + // From https://browser.qq.com/ and the user agent string + 'and_qq 10': 70, + + // From the user agent string + 'baidu 7': 48, + + // From https://github.com/kaiostech/gecko-b2g and the user agent string + 'kaios 2': 'and_ff 48' +} + // Aliases to work with joined versions like `ios_saf 7.0-7.1` browserslist.versionAliases = { } @@ -1161,6 +1194,26 @@ var QUERIES = [ ] var NORMALIZERS = { + byEngine: function (browser) { + var major = browser.split('.')[0] + var normalized = browserslist.normalizedVersions[major] + if (!normalized) { + return browser + } else if (typeof normalized === 'number') { + normalized = 'and_chr ' + normalized + } + return normalized + }, + toDesktop: function (browser) { + browser = browser.split(' ') + var name = browser[0] + var version = browser[1] + if (browserslist.desktopNames[name] && + !(name === 'android' && ANDROID_CLASSIC_REGEX.test(version))) { + name = browserslist.desktopNames[name] + } + return name + ' ' + version + } }; // Get and convert Can I Use data diff --git a/test/normalizer.test.js b/test/normalizer.test.js index 625e4a3e..b2a3f9b5 100644 --- a/test/normalizer.test.js +++ b/test/normalizer.test.js @@ -1,6 +1,7 @@ let browserslist = require('../') let originData = browserslist.data +let originNormalizedVersions = browserslist.normalizedVersions beforeEach(() => { browserslist.data = { @@ -25,10 +26,44 @@ beforeEach(() => { versions: ['83'] } } + + browserslist.normalizedVersions = { + 'samsung 4': 44, + 'kaios 2': 'and_ff 48' + } }) afterEach(() => { browserslist.data = originData + browserslist.normalizedVersions = originNormalizedVersions +}) + +it('normalizes mobile browsers to desktop browsers', () => { + let opts = { normalizers: ['toDesktop'] } + expect(browserslist('android 37', opts)).toEqual(['chrome 37']) + expect(browserslist('last 1 and_chr versions', opts)).toEqual(['chrome 83']) + expect(browserslist('samsung 4', opts)).toEqual(['samsung 4']) +}) + +it('does not normalize classic Android webview versions', () => { + let opts = { normalizers: ['toDesktop'] } + expect(browserslist('android 4.4-37', opts)).toEqual([ + 'android 4.4.3-4.4.4', 'android 4.4', 'chrome 37' + ]) +}) + +it('normalizes Chromium-based browsers to Chrome', () => { + let opts = { normalizers: ['byEngine'] } + expect(browserslist('samsung 4', opts)).toEqual(['and_chr 44']) + expect(browserslist('kaios 2.5', opts)).toEqual(['and_ff 48']) + expect(browserslist('and_chr 83', opts)).toEqual(['and_chr 83']) +}) + +it('should apply each normalizer in order', () => { + let opts = { normalizers: ['byEngine', 'toDesktop'] } + expect(browserslist('samsung 4', opts)).toEqual(['chrome 44']) + expect(browserslist('kaios 2.5', opts)).toEqual(['firefox 48']) + expect(browserslist('and_chr 83', opts)).toEqual(['chrome 83']) }) it('accepts a normalizer function', () => {