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
with:
node-version: ${{ matrix.node-version }}
- name: npm install, build, and test
- name: npm ci, build, and test
run: |
npm install
npm ci
npm run lint
npm run build
npm test

View File

@ -1,5 +1,13 @@
# 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)
- [FIX] Add support for QQ Browser [#362]
- [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!
[![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
- [Overview](#overview)
@ -145,5 +145,35 @@ 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.
## 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
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;
/**
* 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 {
interface 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",
"version": "2.7.0",
"version": "2.8.0",
"description": "Lightweight browser detector",
"keywords": [
"browser",
@ -38,7 +38,7 @@
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"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",
"coveralls": "^3.0.6",
"docdash": "^1.1.1",
@ -48,8 +48,8 @@
"eslint-plugin-import": "^2.18.2",
"gh-pages": "^2.1.1",
"jsdoc": "^3.6.3",
"nyc": "^14.1.1",
"sinon": "^7.5.0",
"nyc": "^15.0.0",
"sinon": "^8.0.0",
"testem": "^3.0.0",
"webpack": "^4.41.0",
"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;

View File

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

View File

@ -531,6 +531,21 @@ const browsersList = [
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],
describe(ua) {

View File

@ -28,7 +28,7 @@ export default [
/* Windows */
{
test: [/windows/i],
test: [/windows /i],
describe(ua) {
const version = Utils.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, ua);
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 */
{
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 */
{
test: [/kftt build/i],

View File

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

View File

@ -210,6 +210,8 @@ export default class Utils {
return -1;
}
}
return undefined;
}
/**
@ -231,6 +233,54 @@ export default class Utils {
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
*
@ -250,10 +300,10 @@ export default class Utils {
* @example
* getBrowserAlias('edge') // Microsoft Edge
*
* @param {string} browserName
* @param {string} browserAlias
* @return {string}
*/
static getBrowserTypeByAlias(browserAlia) {
return BROWSER_MAP[browserAlia] || '';
static getBrowserTypeByAlias(browserAlias) {
return BROWSER_MAP[browserAlias] || '';
}
}

View File

@ -1823,6 +1823,22 @@
engine:
name: "Gecko"
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:
-
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:
name: "WebKit"
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:
-
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:
name: "WebKit"
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 {
getBrowserAlias,
getFirstMatch,
getSecondMatch,
matchAndReturnConst,
getWindowsVersionName,
getMacOSVersionName,
getAndroidVersionName,
getVersionPrecision,
compareVersions,
map,
find,
assign,
getBrowserAlias,
getBrowserTypeByAlias
} from '../../src/utils';
test('getFirstMatch', (t) => {
@ -13,6 +20,16 @@ test('getFirstMatch', (t) => {
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) => {
t.is(getWindowsVersionName('NT 5.0'), '2000');
t.is(getWindowsVersionName('XXX'), void 0);
@ -32,6 +49,11 @@ test('getAndroidVersionName', (t) => {
t.is(getAndroidVersionName('XXX'), void 0);
});
test('getVersionPrecision', (t) => {
const precision = getVersionPrecision("10.14.5");
t.is(precision, 3);
});
test('compareVersions', (t) => {
const comparisionsTasks = [
['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) => {
t.is(getBrowserAlias('Microsoft Edge'), 'edge');
t.is(getBrowserAlias('Unexisting Browser'), void 0);
});
test('getBrowserTypeByAlias', (t) => {
t.is(getBrowserTypeByAlias('edge'), 'Microsoft Edge');
t.is(getBrowserTypeByAlias(void 0), '');
});