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

Merge branch '2.8.0' into production

This commit is contained in:
Denis Demchenko 2019-12-26 16:46:13 +02:00
commit 16843fd15f
15 changed files with 1416 additions and 433 deletions

View File

@ -17,9 +17,9 @@ jobs:
uses: actions/setup-node@v1 uses: actions/setup-node@v1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: npm install, build, and test - name: npm ci, build, and test
run: | run: |
npm install npm ci
npm run lint npm run lint
npm run build npm run build
npm test npm test

View File

@ -1,5 +1,13 @@
# Bowser Changelog # Bowser Changelog
### 2.8.0 (Dec 26, 2019)
- [ADD] Add polyfills for Array.find & Object.assign [#383]
- [ADD] Export constants with types.d.ts [#382]
- [FIX] Add support for WeChat on Windows [#381]
- [FIX] Fix detection of Firefox on iPad [#379]
- [FIX] Add detection of Electron [#375]
- [FIX] Updated dev-dependencies
### 2.7.0 (Oct 2, 2019) ### 2.7.0 (Oct 2, 2019)
- [FIX] Add support for QQ Browser [#362] - [FIX] Add support for QQ Browser [#362]
- [FIX] Add support for GSA [#364] - [FIX] Add support for GSA [#364]

View File

@ -6,7 +6,7 @@ A small, fast and rich-API browser/platform/engine detector for both browser and
Don't hesitate to support the project on Github or [OpenCollective](https://opencollective.com/bowser) if you like it ❤️ Also, contributors are always welcome! Don't hesitate to support the project on Github or [OpenCollective](https://opencollective.com/bowser) if you like it ❤️ Also, contributors are always welcome!
[![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) ![Downloads](https://img.shields.io/npm/dm/bowser) [![Financial Contributors on Open Collective](https://opencollective.com/bowser/all/badge.svg?label=financial+contributors)](https://opencollective.com/bowser) [![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) ![Downloads](https://img.shields.io/npm/dm/bowser)
# Contents # Contents
- [Overview](#overview) - [Overview](#overview)
@ -145,5 +145,35 @@ list of aliases can be found in [the file](src/constants.js).
## Similar Projects ## Similar Projects
* [Kong](https://github.com/BigBadBleuCheese/Kong) - A C# port of Bowser. * [Kong](https://github.com/BigBadBleuCheese/Kong) - A C# port of Bowser.
## Contributors
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/lancedikson/bowser/graphs/contributors"><img src="https://opencollective.com/bowser/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/bowser/contribute)]
#### Individuals
<a href="https://opencollective.com/bowser"><img src="https://opencollective.com/bowser/individuals.svg?width=890"></a>
#### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/bowser/contribute)]
<a href="https://opencollective.com/bowser/organization/0/website"><img src="https://opencollective.com/bowser/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/1/website"><img src="https://opencollective.com/bowser/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/2/website"><img src="https://opencollective.com/bowser/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/3/website"><img src="https://opencollective.com/bowser/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/4/website"><img src="https://opencollective.com/bowser/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/5/website"><img src="https://opencollective.com/bowser/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/6/website"><img src="https://opencollective.com/bowser/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/7/website"><img src="https://opencollective.com/bowser/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/8/website"><img src="https://opencollective.com/bowser/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/bowser/organization/9/website"><img src="https://opencollective.com/bowser/organization/9/avatar.svg"></a>
## License ## License
Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.

8
index.d.ts vendored
View File

@ -22,6 +22,14 @@ declare namespace Bowser {
function parse(UA: string): Parser.ParsedResult; function parse(UA: string): Parser.ParsedResult;
/**
* Constants exposed via bowser getters
*/
const BROWSER_MAP: Record<string, string>;
const ENGINE_MAP: Record<string, string>;
const OS_MAP: Record<string, string>;
const PLATFORMS_MAP: Record<string, string>;
namespace Parser { namespace Parser {
interface Parser { interface Parser {
constructor(UA: string, skipParsing?: boolean): Parser.Parser; constructor(UA: string, skipParsing?: boolean): Parser.Parser;

1509
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "bowser", "name": "bowser",
"version": "2.7.0", "version": "2.8.0",
"description": "Lightweight browser detector", "description": "Lightweight browser detector",
"keywords": [ "keywords": [
"browser", "browser",
@ -38,7 +38,7 @@
"babel-eslint": "^10.0.3", "babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"babel-plugin-add-module-exports": "^1.0.2", "babel-plugin-add-module-exports": "^1.0.2",
"babel-plugin-istanbul": "^5.2.0", "babel-plugin-istanbul": "^6.0.0",
"compression-webpack-plugin": "^3.0.0", "compression-webpack-plugin": "^3.0.0",
"coveralls": "^3.0.6", "coveralls": "^3.0.6",
"docdash": "^1.1.1", "docdash": "^1.1.1",
@ -48,8 +48,8 @@
"eslint-plugin-import": "^2.18.2", "eslint-plugin-import": "^2.18.2",
"gh-pages": "^2.1.1", "gh-pages": "^2.1.1",
"jsdoc": "^3.6.3", "jsdoc": "^3.6.3",
"nyc": "^14.1.1", "nyc": "^15.0.0",
"sinon": "^7.5.0", "sinon": "^8.0.0",
"testem": "^3.0.0", "testem": "^3.0.0",
"webpack": "^4.41.0", "webpack": "^4.41.0",
"webpack-bundle-analyzer": "^3.5.2", "webpack-bundle-analyzer": "^3.5.2",

View File

@ -74,4 +74,10 @@ class Bowser {
} }
} }
export {
BROWSER_MAP,
ENGINE_MAP,
OS_MAP,
PLATFORMS_MAP,
} from './constants.js';
export default Bowser; export default Bowser;

View File

@ -7,6 +7,7 @@ export const BROWSER_ALIASES_MAP = {
BlackBerry: 'blackberry', BlackBerry: 'blackberry',
Chrome: 'chrome', Chrome: 'chrome',
Chromium: 'chromium', Chromium: 'chromium',
Electron: 'electron',
Epiphany: 'epiphany', Epiphany: 'epiphany',
Firefox: 'firefox', Firefox: 'firefox',
Focus: 'focus', Focus: 'focus',
@ -48,6 +49,7 @@ export const BROWSER_MAP = {
blackberry: 'BlackBerry', blackberry: 'BlackBerry',
chrome: 'Chrome', chrome: 'Chrome',
chromium: 'Chromium', chromium: 'Chromium',
electron: 'Electron',
epiphany: 'Epiphany', epiphany: 'Epiphany',
firefox: 'Firefox', firefox: 'Firefox',
focus: 'Focus', focus: 'Focus',

View File

@ -531,6 +531,21 @@ const browsersList = [
return browser; return browser;
}, },
}, },
{
test: [/electron/i],
describe(ua) {
const browser = {
name: 'Electron',
};
const version = Utils.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{ {
test: [/chromium/i], test: [/chromium/i],
describe(ua) { describe(ua) {

View File

@ -28,7 +28,7 @@ export default [
/* Windows */ /* Windows */
{ {
test: [/windows/i], test: [/windows /i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, ua); const version = Utils.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, ua);
const versionName = Utils.getWindowsVersionName(version); const versionName = Utils.getWindowsVersionName(version);
@ -41,6 +41,18 @@ export default [
}, },
}, },
/* Firefox on iPad */
{
test: [/Macintosh(.*?) FxiOS(.*?) Version\//],
describe(ua) {
const version = Utils.getSecondMatch(/(Version\/)(\d[\d.]+)/, ua);
return {
name: OS_MAP.iOS,
version,
};
},
},
/* macOS */ /* macOS */
{ {
test: [/macintosh/i], test: [/macintosh/i],

View File

@ -57,6 +57,18 @@ export default [
}, },
}, },
/* Firefox on iPad */
{
test: [/Macintosh(.*?) FxiOS(.*?) Version\//],
describe() {
return {
type: PLATFORMS_MAP.tablet,
vendor: 'Apple',
model: 'iPad',
};
},
},
/* Amazon Kindle Fire */ /* Amazon Kindle Fire */
{ {
test: [/kftt build/i], test: [/kftt build/i],

View File

@ -82,7 +82,7 @@ class Parser {
parseBrowser() { parseBrowser() {
this.parsedResult.browser = {}; this.parsedResult.browser = {};
const browserDescriptor = browserParsersList.find((_browser) => { const browserDescriptor = Utils.find(browserParsersList, (_browser) => {
if (typeof _browser.test === 'function') { if (typeof _browser.test === 'function') {
return _browser.test(this); return _browser.test(this);
} }
@ -165,7 +165,7 @@ class Parser {
parseOS() { parseOS() {
this.parsedResult.os = {}; this.parsedResult.os = {};
const os = osParsersList.find((_os) => { const os = Utils.find(osParsersList, (_os) => {
if (typeof _os.test === 'function') { if (typeof _os.test === 'function') {
return _os.test(this); return _os.test(this);
} }
@ -241,7 +241,7 @@ class Parser {
parsePlatform() { parsePlatform() {
this.parsedResult.platform = {}; this.parsedResult.platform = {};
const platform = platformParsersList.find((_platform) => { const platform = Utils.find(platformParsersList, (_platform) => {
if (typeof _platform.test === 'function') { if (typeof _platform.test === 'function') {
return _platform.test(this); return _platform.test(this);
} }
@ -292,7 +292,7 @@ class Parser {
parseEngine() { parseEngine() {
this.parsedResult.engine = {}; this.parsedResult.engine = {};
const engine = enginesParsersList.find((_engine) => { const engine = Utils.find(enginesParsersList, (_engine) => {
if (typeof _engine.test === 'function') { if (typeof _engine.test === 'function') {
return _engine.test(this); return _engine.test(this);
} }
@ -328,7 +328,7 @@ class Parser {
* @return {ParsedResult} * @return {ParsedResult}
*/ */
getResult() { getResult() {
return Object.assign({}, this.parsedResult); return Utils.assign({}, this.parsedResult);
} }
/** /**
@ -370,7 +370,7 @@ class Parser {
if (platformsAndOSCounter > 0) { if (platformsAndOSCounter > 0) {
const platformsAndOSNames = Object.keys(platformsAndOSes); const platformsAndOSNames = Object.keys(platformsAndOSes);
const OSMatchingDefinition = platformsAndOSNames.find(name => (this.isOS(name))); const OSMatchingDefinition = Utils.find(platformsAndOSNames, name => (this.isOS(name)));
if (OSMatchingDefinition) { if (OSMatchingDefinition) {
const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]); const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]);
@ -380,7 +380,10 @@ class Parser {
} }
} }
const platformMatchingDefinition = platformsAndOSNames.find(name => (this.isPlatform(name))); const platformMatchingDefinition = Utils.find(
platformsAndOSNames,
name => (this.isPlatform(name)),
);
if (platformMatchingDefinition) { if (platformMatchingDefinition) {
const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]); const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]);
@ -392,7 +395,7 @@ class Parser {
if (browsersCounter > 0) { if (browsersCounter > 0) {
const browserNames = Object.keys(browsers); const browserNames = Object.keys(browsers);
const matchingDefinition = browserNames.find(name => (this.isBrowser(name, true))); const matchingDefinition = Utils.find(browserNames, name => (this.isBrowser(name, true)));
if (matchingDefinition !== void 0) { if (matchingDefinition !== void 0) {
return this.compareVersion(browsers[matchingDefinition]); return this.compareVersion(browsers[matchingDefinition]);

View File

@ -210,6 +210,8 @@ export default class Utils {
return -1; return -1;
} }
} }
return undefined;
} }
/** /**
@ -231,6 +233,54 @@ export default class Utils {
return result; return result;
} }
/**
* Array::find polyfill
*
* @param {Array} arr
* @param {Function} predicate
* @return {Array}
*/
static find(arr, predicate) {
let i;
let l;
if (Array.prototype.find) {
return Array.prototype.find.call(arr, predicate);
}
for (i = 0, l = arr.length; i < l; i += 1) {
const value = arr[i];
if (predicate(value, i)) {
return value;
}
}
return undefined;
}
/**
* Object::assign polyfill
*
* @param {Object} obj
* @param {Object} ...objs
* @return {Object}
*/
static assign(obj, ...assigners) {
const result = obj;
let i;
let l;
if (Object.assign) {
return Object.assign(obj, ...assigners);
}
for (i = 0, l = assigners.length; i < l; i += 1) {
const assigner = assigners[i];
if (typeof assigner === 'object' && assigner !== null) {
const keys = Object.keys(assigner);
keys.forEach((key) => {
result[key] = assigner[key];
});
}
}
return obj;
}
/** /**
* Get short version/alias for a browser name * Get short version/alias for a browser name
* *
@ -250,10 +300,10 @@ export default class Utils {
* @example * @example
* getBrowserAlias('edge') // Microsoft Edge * getBrowserAlias('edge') // Microsoft Edge
* *
* @param {string} browserName * @param {string} browserAlias
* @return {string} * @return {string}
*/ */
static getBrowserTypeByAlias(browserAlia) { static getBrowserTypeByAlias(browserAlias) {
return BROWSER_MAP[browserAlia] || ''; return BROWSER_MAP[browserAlias] || '';
} }
} }

View File

@ -1823,6 +1823,22 @@
engine: engine:
name: "Gecko" name: "Gecko"
version: "20100101" version: "20100101"
-
ua: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/21.0 Version/13.0.3 Safari/605.1.15"
spec:
browser:
name: "Firefox"
version: "21.0"
os:
name: "iOS"
version: "13.0.3"
platform:
type: "tablet"
vendor: "Apple"
model: "iPad"
engine:
name: "WebKit"
version: "605.1.15"
SeaMonkey: SeaMonkey:
- -
ua: "Mozilla/5.0 (Windows NT 5.2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 SeaMonkey/2.7.1" ua: "Mozilla/5.0 (Windows NT 5.2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 SeaMonkey/2.7.1"
@ -2505,6 +2521,22 @@
engine: engine:
name: "WebKit" name: "WebKit"
version: "537.51.1" version: "537.51.1"
-
ua: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat"
spec:
browser:
name: "WeChat"
version: "6.5.2.501"
os:
name: "macOS"
version: "10.15.1"
versionName: "Catalina"
platform:
type: "desktop"
vendor: "Apple"
engine:
name: "WebKit"
version: "605.1.15"
UC Browser: 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" 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"
@ -2908,3 +2940,59 @@
engine: engine:
name: "WebKit" name: "WebKit"
version: "605.1.15" version: "605.1.15"
Electron:
-
ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) my-app/1.0.0 Chrome/78.0.3904.113 Electron/7.1.2 Safari/537.36"
spec:
browser:
name: "Electron"
version: "7.1.2"
os:
name: "Windows"
version: "NT 10.0"
versionName: "10"
platform:
type: "desktop"
engine:
name: "Blink"
-
ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.146 Electron/6.1.5 Safari/537.36"
spec:
browser:
name: "Electron"
version: "6.1.5"
os:
name: "Windows"
version: "NT 10.0"
versionName: "10"
platform:
type: "desktop"
engine:
name: "Blink"
-
ua: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.113 Electron/7.1.2 Safari/537.36"
spec:
browser:
name: "Electron"
version: "7.1.2"
os:
name: "macOS"
version: "10.15.1"
versionName: "Catalina"
platform:
type: "desktop"
vendor: 'Apple'
engine:
name: "Blink"
-
ua: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.113 Electron/7.1.2 Safari/537.36"
spec:
browser:
name: "Electron"
version: "7.1.2"
os:
name: "Linux"
platform:
type: "desktop"
engine:
name: "Blink"

View File

@ -1,11 +1,18 @@
import test from 'ava'; import test from 'ava';
import { import {
getBrowserAlias,
getFirstMatch, getFirstMatch,
getSecondMatch,
matchAndReturnConst,
getWindowsVersionName, getWindowsVersionName,
getMacOSVersionName, getMacOSVersionName,
getAndroidVersionName, getAndroidVersionName,
getVersionPrecision,
compareVersions, compareVersions,
map,
find,
assign,
getBrowserAlias,
getBrowserTypeByAlias
} from '../../src/utils'; } from '../../src/utils';
test('getFirstMatch', (t) => { test('getFirstMatch', (t) => {
@ -13,6 +20,16 @@ test('getFirstMatch', (t) => {
t.is(matchedVersion, '11.11.11'); t.is(matchedVersion, '11.11.11');
}); });
test('getSecondMatch', (t) => {
const matchedVersion = getSecondMatch(/version\/(\S+).*version\/(\S+)/i, 'Chrome Version/11.11.11 Chrome Version/22.22.22');
t.is(matchedVersion, '22.22.22');
});
test('matchAndReturnConst', (t) => {
const _const = matchAndReturnConst(/version/i, 'version', "_const");
t.is(_const, '_const');
});
test('getWindowsVersionName', (t) => { test('getWindowsVersionName', (t) => {
t.is(getWindowsVersionName('NT 5.0'), '2000'); t.is(getWindowsVersionName('NT 5.0'), '2000');
t.is(getWindowsVersionName('XXX'), void 0); t.is(getWindowsVersionName('XXX'), void 0);
@ -32,6 +49,11 @@ test('getAndroidVersionName', (t) => {
t.is(getAndroidVersionName('XXX'), void 0); t.is(getAndroidVersionName('XXX'), void 0);
}); });
test('getVersionPrecision', (t) => {
const precision = getVersionPrecision("10.14.5");
t.is(precision, 3);
});
test('compareVersions', (t) => { test('compareVersions', (t) => {
const comparisionsTasks = [ const comparisionsTasks = [
['9.0', '10', -1], ['9.0', '10', -1],
@ -68,7 +90,51 @@ test('compareVersions', (t) => {
}); });
}); });
test('map', (t) => {
const result = map([1,2], (value) => value+2);
t.is(result[0], 3);
t.is(result[1], 4);
const original = Array.prototype.map;
delete Array.prototype.map;
const polyfillResult = map([1,2], (value) => value+2);
Array.prototype.map = original;
t.is(polyfillResult[0], 3);
t.is(polyfillResult[1], 4);
});
test('find', (t) => {
const result = find([1,2], (value) => value==2);
t.is(result, 2);
const original = Array.prototype.find;
delete Array.prototype.find;
const polyfillResultFound = find([1,2], (value) => value==2);
const polyfillResultNotFound = find([1,2], (value) => value==3);
Array.prototype.find = original;
t.is(polyfillResultFound, 2);
t.is(polyfillResultNotFound, undefined);
});
test('assign', (t) => {
const result = assign({}, { a: 1 }, { b: 1 }, { b: 2, c: 3 });
t.is(result['a'], 1);
t.is(result['b'], 2);
t.is(result['c'], 3);
const original = Object.assign;
delete Object.assign;
const polyfillResult = assign({}, { a: 1 }, { b: 1 }, null, { b: 2, c: 3 });
Object.assign = original;
t.is(polyfillResult['a'], 1);
t.is(polyfillResult['b'], 2);
t.is(polyfillResult['c'], 3);
});
test('getBrowserAlias', (t) => { test('getBrowserAlias', (t) => {
t.is(getBrowserAlias('Microsoft Edge'), 'edge'); t.is(getBrowserAlias('Microsoft Edge'), 'edge');
t.is(getBrowserAlias('Unexisting Browser'), void 0); t.is(getBrowserAlias('Unexisting Browser'), void 0);
}); });
test('getBrowserTypeByAlias', (t) => {
t.is(getBrowserTypeByAlias('edge'), 'Microsoft Edge');
t.is(getBrowserTypeByAlias(void 0), '');
});