1
0
mirror of https://github.com/lancedikson/bowser synced 2026-01-22 16:50:24 +00:00

Compare commits

..

No commits in common. "master" and "2.0.0-beta.1" have entirely different histories.

56 changed files with 23720 additions and 22440 deletions

View File

@ -1,8 +1,7 @@
{ {
"presets": [["@babel/preset-env", { "presets": [["env", {
"useBuiltIns": "entry", "useBuiltIns": true,
"modules": "cjs", "modules": "umd",
"loose": true,
"targets": { "targets": {
"ie": "8", "ie": "8",
"browsers": ">2%" "browsers": ">2%"
@ -14,7 +13,7 @@
"env": { "env": {
"test": { "test": {
"plugins": [ "istanbul" ], "plugins": [ "istanbul" ],
"presets": [["@babel/preset-env", { "targets": { "node": "current" } }]] "presets": [["env", { "targets": { "node": "current" } }]]
} }
} }
} }

View File

@ -1 +1 @@
repo_token: Ba2bS7pOlSLZWuESBnff8qxDjIS8Mg1Z0

View File

@ -3,7 +3,6 @@ root = true
[*] [*]
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true
[{*.js,*.md}] [{*.js,*.md}]
charset = utf-8 charset = utf-8

View File

@ -1,14 +1,6 @@
parser: babel-eslint
extends: airbnb-base extends: airbnb-base
rules: rules:
no-underscore-dangle: 0 no-underscore-dangle: 0
no-void: 0 no-void: 0
import/extensions:
- 'error'
- 'ignorePackages'
- {js: 'always'}
import/prefer-default-export: 1
plugins: plugins:
- ava - ava
- import

View File

@ -1,42 +0,0 @@
# Contributing
We're always open to pull requests or code reviews. Everyone can become a permanent contributor. Just ping @lancedikson in the issues or on Twitter ❤️
## Branches
The project runs Git-flow, where the `master` branch is for development and `production` is for production.
In a nutshell, if you are proposing a new feature that adds totally new functionality to `bowser`, it's better to branch from `master` and make a PR pointing back to `master` as well.
If it's a small hot-fix, an improvement to the docs, or added support for a new browser/OS/platform/etc, then it's better to branch from `production` and make a PR pointing back to `production`.
Following these simple rules will really help maintain the repo! Thanks ❤️
## 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. 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
If you'd like to contribute a change to `bowser`, modify the files in `src/`, and run the following (you'll need `node` + `npm` installed):
``` sh
$ npm install
$ npm run build #build
$ npm test #run tests
$ npm run lint #check lint rules
```

2
.github/FUNDING.yml vendored
View File

@ -1,2 +0,0 @@
github: lancedikson
open_collective: lancedikson

View File

@ -1,129 +0,0 @@
# Copilot Instructions for Bowser
## Project Overview
Bowser is a small, fast, and rich-API browser/platform/engine detector for both browser and Node.js environments. It's designed to parse User-Agent strings and provide detailed information about browsers, operating systems, platforms, and rendering engines.
## Architecture
### Core Components
- **`src/bowser.js`**: Main entry point and public API. Provides static methods `getParser()` and `parse()`.
- **`src/parser.js`**: Core parsing engine that orchestrates all parsers and returns structured results.
- **`src/parser-browsers.js`**: Browser detection logic using regex patterns.
- **`src/parser-os.js`**: Operating system detection logic.
- **`src/parser-platforms.js`**: Platform type detection (desktop, tablet, mobile).
- **`src/parser-engines.js`**: Rendering engine detection (WebKit, Blink, Gecko, etc.).
- **`src/constants.js`**: Centralized constants including browser aliases and mappings.
- **`src/utils.js`**: Utility functions for string matching and manipulation.
### Build Output
- **`es5.js`**: ES5 transpiled version (default export).
- **`bundled.js`**: ES5 version with babel-polyfill included.
## Development Workflow
### Setup
```bash
npm install
```
### Key Commands
- **Build**: `npm run build` - Compiles source files using Webpack and Babel.
- **Test**: `npm test` - Runs unit and acceptance tests using AVA.
- **Lint**: `npm run lint:check` - Checks code style using ESLint.
- **Lint Fix**: `npm run lint:fix` - Auto-fixes linting issues.
- **Watch Mode**: `npm run watch` - Builds on file changes.
- **Test Watch**: `npm run test:watch` - Runs tests on file changes.
### Testing
- Tests are located in `test/acceptance/` and `test/unit/`.
- Acceptance tests use real User-Agent strings from `test/acceptance/useragentstrings.yml`.
- Always update `useragentstrings.yml` when adding browser support.
- Test framework: AVA with Babel integration.
## Coding Standards
### Style Guide
- **ESLint Config**: Based on Airbnb Base style guide.
- **Parser**: Uses `babel-eslint`.
- **Exceptions**:
- Underscore-dangle allowed for private properties.
- `no-void` disabled.
- ES6 imports must include `.js` extension.
### Naming Conventions
- **Browser Aliases**: Use lowercase letters, replace spaces/dashes with underscores, drop "browser" suffix.
- Examples: `Opera Coast``opera_coast`, `UC Browser``uc`, `SeaMonkey``seamonkey`.
- **Private Properties**: Prefix with underscore (e.g., `_ua`).
- **Constants**: Use `UPPER_SNAKE_CASE` for constant maps and aliases.
### Code Patterns
- Use ES6 modules with explicit `.js` extensions.
- Prefer static methods in Bowser class.
- Use class-based structure for Parser.
- Regex patterns should be well-documented and tested.
- Keep parsers modular and focused on single responsibility.
## Adding Browser Support
When adding support for a new browser:
1. Add regex pattern to `src/parser-browsers.js`.
2. Add browser name to `BROWSER_ALIASES_MAP` in `src/constants.js`.
3. Add corresponding entry to `BROWSER_MAP`.
4. Add test cases to `test/acceptance/useragentstrings.yml`.
5. Run tests to verify: `npm test`.
6. Check for duplicates before adding aliases.
## Branching Strategy
- **`master`**: Development branch.
- **`production`**: Production branch.
- **New Features**: Branch from `master`, PR back to `master`.
- **Hot-fixes/Browser Support**: Branch from `production`, PR back to `production`.
## Important Files
- **`index.d.ts`**: TypeScript definitions.
- **`.babelrc`**: Babel configuration for ES5 transpilation.
- **`webpack.config.js`**: Build configuration.
- **`.eslintrc.yml`**: Linting rules.
- **`package.json`**: Dependencies and scripts.
## API Design Principles
- Keep the API simple and intuitive.
- Bowser class should be stateless and provide factory methods.
- Parser class handles instance-specific logic.
- Results should be structured and predictable.
- Support both immediate parsing and lazy parsing.
## Performance Considerations
- Parsers use lazy evaluation where possible.
- Regex patterns are optimized for common browsers first.
- Optional `skipParsing` parameter for delayed parsing.
- Minimal bundle size is a priority (~4.8kB gzipped).
## Documentation
- Use JSDoc comments for all public APIs.
- Document parameters, return types, and provide examples.
- Update README.md for API changes.
- Generate docs with: `npm run generate-docs`.
## Common Pitfalls
- Always check `BROWSER_ALIASES_MAP` for existing aliases before adding new ones.
- User-Agent strings can be complex; test edge cases thoroughly.
- Remember to update both the alias map and the reverse map in constants.
- Browser versions should be treated as strings, not numbers.
- Keep regex patterns readable with comments explaining their purpose.

View File

@ -1,19 +0,0 @@
name-template: 'v$RESOLVED_VERSION 🌈'
tag-template: 'v$RESOLVED_VERSION'
version-resolver:
major:
labels:
- major
minor:
labels:
- minor
patch:
labels:
- patch
default: patch
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&'
template: |
## Changes
$CHANGES

View File

@ -1,20 +0,0 @@
name: 📝 Draft or update next release
concurrency: draft_or_update_next_release
on:
push:
branches:
- master
workflow_dispatch:
jobs:
prepare-deployment:
name: 📝 Draft or update next release
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,38 +0,0 @@
name: "Merge to master"
on:
push:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.16.3]
steps:
- name: Get branch name (merge)
if: github.event_name != 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/} | tr / -)" >> $GITHUB_ENV
- name: Get branch name (pull request)
if: github.event_name == 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF} | tr / -)" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm i -g nyc@15
- run: npm ci
- run: npm run build
- run: nyc npm test && nyc report --reporter=text-lcov | ./node_modules/coveralls/bin/coveralls.js
env:
COVERALLS_SERVICE_NAME: GithubActions
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
COVERALLS_GIT_BRANCH: ${{ env.BRANCH_NAME }}

View File

@ -1,63 +0,0 @@
name: Release
on:
# This job runs when a new release is published
release:
types: [published]
# Manual trigger with version input
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g., 2.12.1)"
required: true
type: string
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 12.16.3
registry-url: "https://registry.npmjs.org"
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package.json') }}
# Store the release version (from release tag or manual input)
- name: Set release version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "RELEASE_VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
echo "Manual release triggered for version: ${{ github.event.inputs.version }}"
else
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
echo "Release triggered from tag: ${GITHUB_REF#refs/*/}"
fi
- run: npm ci
- run: npm version $RELEASE_VERSION --no-git-tag-version
- run: npm run build
- name: Publish to npm with retry
run: |
max_attempts=5
attempt=1
while [ $attempt -le $max_attempts ]; do
echo "Attempt $attempt of $max_attempts..."
if npm publish --access public; then
echo "Successfully published!"
break
else
if [ $attempt -eq $max_attempts ]; then
echo "Failed to publish after $max_attempts attempts"
exit 1
fi
echo "Publish failed, waiting before retry..."
sleep_time=$((attempt * 30))
echo "Waiting ${sleep_time} seconds before retry..."
sleep $sleep_time
attempt=$((attempt + 1))
fi
done
env:
NODE_AUTH_TOKEN: ${{ secrets.BOWSER_NPM_PUBLISH_TOKEN }}

View File

@ -1,44 +0,0 @@
name: "Pull Request"
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [12.16.3]
name: Node ${{ matrix.node }}
steps:
- name: "Checkout latest code"
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run tests
run: npm run test
lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up node
uses: actions/setup-node@v4
with:
node-version: "16"
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint:check

4
.gitignore vendored
View File

@ -3,5 +3,5 @@ node_modules/
.nyc_output .nyc_output
coverage coverage
dist dist
bundled.js* bundled.js
es5.js* es5.js

View File

@ -3,8 +3,3 @@ test
coverage coverage
**/.* **/.*
node_modules node_modules
.github
docs
*.gz
jsdoc.json
webpack.config.js

8
.nycrc
View File

@ -1,10 +1,4 @@
{ {
"sourceMap": false, "sourceMap": false,
"instrument": false, "instrument": false
"include": [
"src/**/*.js"
],
"exclude": [
"*.js"
]
} }

4
.travis.yml Normal file
View File

@ -0,0 +1,4 @@
language: node_js
after_success: npm run coverage
node_js:
- "8.4.0"

View File

@ -1,112 +1,5 @@
# Bowser Changelog # Bowser Changelog
### 2.11.0 (Sep 12, 2020)
- [ADD] Added support for aliases in `Parser#is` method (#437)
- [ADD] Added more typings (#438, #427)
- [ADD] Added support for MIUI Browser (#436)
### 2.10.0 (Jul 9, 2020)
- [FIX] Fix for Firefox detection on iOS 13 [#415]
- [FIX] Fixes for typings.d.ts [#409]
- [FIX] Updated development dependencies
### 2.9.0 (Jan 28, 2020)
- [ADD] Export more methods and constants via .d.ts [#388], [#390]
### 2.8.1 (Dec 26, 2019)
- [FIX] Reverted [#382] as it broke build
### 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]
- [FIX] Updated dependencies
### 2.6.0 (Sep 6, 2019)
- [ADD] Define "module" export in package.json [#354]
- [FIX] Fix Tablet PC detection [#334]
### 2.5.4 (Sep 2, 2019)
- [FIX] Exclude docs from the npm package [#349]
### 2.5.3 (Aug 4, 2019)
- [FIX] Add MacOS names support [#338]
- [FIX] Point typings.d.ts from package.json [#341]
- [FIX] Upgrade dependencies
### 2.5.2 (July 17, 2019)
- [FIX] Fixes the bug undefined method because of failed build (#335)
### 2.5.1 (July 17, 2019)
- [FIX] Fixes the bug with a custom Error class (#335)
- [FIX] Fixes the settings for Babel to reduce the bundle size (#259)
### 2.5.0 (July 16, 2019)
- [ADD] Add constant output so that users can quickly get all types (#325)
- [FIX] Add support for Roku OS (#332)
- [FIX] Update devDependencies
- [FIX] Fix docs, README and added funding information
### 2.4.0 (May 3, 2019)
- [FIX] Update regexp for generic browsers (#310)
- [FIX] Fix issues with module.exports (#318)
- [FIX] Update devDependencies (#316, #321, #322)
- [FIX] Fix docs (#320)
### 2.3.0 (April 14, 2019)
- [ADD] Add support for Blink-based MS Edge (#311)
- [ADD] Add more types for TS (#289)
- [FIX] Update dev-dependencies
- [FIX] Update docs
### 2.2.1 (April 12, 2019)
- [ADD] Add an alias for Samsung Internet
- [FIX] Fix browser name detection for browsers without an alias (#313)
### 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
### 2.1.1 (March 6, 2019)
- [ADD] Add detection of PlayStation 4 (#291)
- [ADD] Deploy docs on GH Pages (#293)
- [FIX] Fix files extensions for importing (#294)
- [FIX] Fix docs (#295)
### 2.1.0 (January 24, 2019)
- [ADD] Add new `Parser.getEngineName()` method (#288)
- [ADD] Add detection of ChromeOS (#287)
- [FIX] Fix README
### 2.0.0 (January 19, 2019)
- [ADD] Support a non strict equality in `Parser.satisfies()` (#275)
- [ADD] Add Android versions names (#276)
- [ADD] Add a typings file (#277)
- [ADD] Added support for Googlebot recognition (#278)
- [FIX] Update building tools, avoid security issues
### 2.0.0-beta.3 (September 15, 2018)
- [FIX] Fix Chrome Mobile detection (#253)
- [FIX] Use built bowser for CI (#252)
- [FIX] Update babel-plugin-add-module-exports (#251)
### 2.0.0-beta.2 (September 9, 2018)
- [FIX] Fix failing comparing version through `Parser.satisfies` (#243)
- [FIX] Fix travis testing, include eslint into CI testing
- [FIX] Add support for Maxthon desktop browser (#246)
- [FIX] Add support for Swing browser (#248)
- [DOCS] Regenerate docs
### 2.0.0-beta.1 (August 18, 2018) ### 2.0.0-beta.1 (August 18, 2018)
- [ADD] Add loose version comparison to `Parser.compareVersion()` and `Parser.satisfies()` - [ADD] Add loose version comparison to `Parser.compareVersion()` and `Parser.satisfies()`
- [CHORE] Add CONTRIBUTING.md - [CHORE] Add CONTRIBUTING.md
@ -177,7 +70,7 @@
### 1.5.0 (October 31, 2016) ### 1.5.0 (October 31, 2016)
- [ADD] Throw an error when `minVersion` map has not a string as a version and fix readme (#165) - [ADD] Throw an error when `minVersion` map has not a string as a version and fix readme (#165)
- [FIX] Fix truly detection of Windows Phones (#167) - [FIX] Fix truly detection of Windows Phones (#167)
### 1.4.6 (September 19, 2016) ### 1.4.6 (September 19, 2016)
- [FIX] Fix mobile Opera's version detection on Android - [FIX] Fix mobile Opera's version detection on Android
@ -215,4 +108,4 @@
- [FEATURE] Add `bowser.check` method - [FEATURE] Add `bowser.check` method
- [DOC] Changelog started - [DOC] Changelog started
- [DOC] Add API section to README - [DOC] Add API section to README
- [FIX] Fix detection of browser type (A/C/X) for Chromium - [FIX] Fix detection of browser type (A/C/X) for Chromium

7
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,7 @@
# Contributing
The project runs Git-flow, where the `master` branch is the production one and the `develop` is the developing one.
In a nutshell, if you're about to propose a new feature with adding new functionality to bowser, it's better to branch from `develop` and make a PR pointing to `develop` as well.
If it's a small hotfix, fix a typo in the docs or you've added support for a new browser/OS/platform/etc, then it's better to branch from `master` and make a PR pointing to `master` as well.
Following these simple rules will help to maintain the repo a lot! Thanks ❤️

116
README.md
View File

@ -1,42 +1,35 @@
## Bowser ## Bowser
A small, fast and rich-API browser/platform/engine detector for both browser and node. A Browser detector. Because sometimes, there is no other way, and not even good modern browsers always provide good feature detection mechanisms.
- **Small.** Use plain ES5-version which is ~4.8kB gzipped.
- **Optimized.** Use only those parsers you need — it doesn't do useless work.
- **Multi-platform.** It's browser- and node-ready, so you can use it in any environment.
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/)
[![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/bowser-js/bowser.svg?branch=master)](https://travis-ci.org/bowser-js/bowser/) [![Greenkeeper badge](https://badges.greenkeeper.io/bowser-js/bowser.svg)](https://greenkeeper.io/) [![Coverage Status](https://coveralls.io/repos/github/bowser-js/bowser/badge.svg?branch=master)](https://coveralls.io/github/bowser-js/bowser?branch=master) ![Downloads](https://img.shields.io/npm/dm/bowser)
# Contents # Contents
- [Overview](#overview) - [Overview](#overview)
- [Use cases](#use-cases) - [Use cases](#use-cases)
- [Advanced usage](#advanced-usage)
- [How can I help?](#contributing)
# Overview # Overview
The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers. Check it out on this page: https://bowser-js.github.io/bowser-online/. The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers.
### ⚠️ Version 2.0 breaking changes ⚠️ _Please, note that this is an alpha version. Check out the [1.x](https://github.com/lancedikson/bowser/tree/v1.x) branch for a stable version._
Version 2.0 has drastically changed the API. All available methods are on the [docs page](https://bowser-js.github.io/bowser/docs/). **Changes of the 2.0**
The upcoming 2.0 version has drastically changed API. All available methods can be found in the `docs` folder from now on and on a webpage soon.
_For legacy code, check out the [1.x](https://github.com/bowser-js/bowser/tree/v1.x) branch and install it through `npm install bowser@1.9.4`._
# Use cases # Use cases
First of all, require the library. This is a UMD Module, so it will work for AMD, TypeScript, ES6, and CommonJS module systems. First of all, require the library:
```javascript ```javascript
const Bowser = require("bowser"); // CommonJS const bowser = require('bowser');
import * as Bowser from "bowser"; // TypeScript
import Bowser from "bowser"; // ES6 (and TypeScript with --esModuleInterop enabled)
``` ```
By default, the exported version is the *ES5 transpiled version*, which **do not** include any polyfills. By default, `require('bowser')` requires the *ES5 version of files*, which
**do not** include any polyfills.
In case you don't use your own `babel-polyfill` you may need to have pre-built bundle with all needed polyfills. In case if you don't use your own `babel-polyfill` you may need to have pre-built bundle with all needed polyfills.
So, for you it's suitable to require bowser like this: `require('bowser/bundled')`. So, for you it's suitable to require bowser like this: `require('bowser/bundled')`.
As the result, you get a ES5 version of bowser with `babel-polyfill` bundled together. As the result, you get a ES5 version of bowser with `babel-polyfill` bundled together.
@ -44,10 +37,10 @@ You may need to use the source files, so they will be available in the package a
## Browser props detection ## Browser props detection
Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to do it with Bowser: Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to make it with Bowser:
```javascript ```javascript
const browser = Bowser.getParser(window.navigator.userAgent); const browser = bowser.getParser(window.navigator.userAgent);
console.log(`The current browser name is "${browser.getBrowserName()}"`); console.log(`The current browser name is "${browser.getBrowserName()}"`);
// The current browser name is "Internet Explorer" // The current browser name is "Internet Explorer"
@ -56,21 +49,20 @@ console.log(`The current browser name is "${browser.getBrowserName()}"`);
or or
```javascript ```javascript
const browser = Bowser.getParser(window.navigator.userAgent); const impression = new Impression();
console.log(browser.getBrowser());
// outputs const browser = bowser.getParser(window.navigator.userAgent);
{ const browserInfo = browser.getBrowser();
name: "Internet Explorer" impression.brName = browserInfo.name;
version: "11.0" impression.brVer = browserInfo.version;
}
``` ```
or or
```javascript ```javascript
console.log(Bowser.parse(window.navigator.userAgent)); const browser = bowser.getParser(window.navigator.userAgent);
impression.userTechData = browser.parse();
console.log(impression.userTechData);
// outputs // outputs
{ {
browser: { browser: {
@ -99,7 +91,7 @@ You could want to filter some particular browsers to provide any special support
It could look like this: It could look like this:
```javascript ```javascript
const browser = Bowser.getParser(window.navigator.userAgent); const browser = bowser.getParser(window.navigator.userAgent);
const isValidBrowser = browser.satisfies({ const isValidBrowser = browser.satisfies({
// declare browsers per OS // declare browsers per OS
windows: { windows: {
@ -111,20 +103,20 @@ const isValidBrowser = browser.satisfies({
// per platform (mobile, desktop or tablet) // per platform (mobile, desktop or tablet)
mobile: { mobile: {
safari: '>=9', safari: '>9',
'android browser': '>3.10' 'android browser': '>3.10'
}, },
// or in general // or in general
chrome: "~20.1.1432", chrome: ">20.1.1432",
firefox: ">31", firefox: ">31",
opera: ">=22", opera: ">22"
// also supports equality operator // also supports equality operator
chrome: "=20.1.1432", // will match particular build only chrome: "=20.1.1432", // will match particular build only
// and loose-equality operator // and loose-equality operator
chrome: "~20", // will match any 20.* sub-version chrome: "~20" // will match any 20.* sub-version
chrome: "~20.1" // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1) chrome: "~20.1" // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1)
}); });
``` ```
@ -134,44 +126,22 @@ 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. More of API and possibilities you will find in the `docs` folder.
### Browser names for `.satisfies()` # Contributing
If you'd like to contribute a change to bowser, modify the files in `src/`, then run the following (you'll need node + npm installed):
By default you are supposed to use the full browser name for `.satisfies`. ``` sh
But, there's a short way to define a browser using short aliases. The full $ npm install
list of aliases can be found in [the file](src/constants.js). $ npm test
```
## Similar Projects ### Adding 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.
### 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 ### License
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](.github/CONTRIBUTING.md)].
<a href="https://github.com/bowser-js/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. Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.

File diff suppressed because it is too large Load Diff

View File

@ -1,234 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>BowserUAIsNotAStringError - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
<div class="navicon"></div>
</label>
<label for="nav-trigger" class="overlay"></label>
<nav >
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="BowserUAIsNotAStringError.html">BowserUAIsNotAStringError</a></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getEngineName">getEngineName</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#isBrowser">isBrowser</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#getAndroidVersionName">getAndroidVersionName</a></li><li><a href="global.html#getBrowserAlias">getBrowserAlias</a></li><li><a href="global.html#getBrowserTypeByAlias">getBrowserTypeByAlias</a></li><li><a href="global.html#getFirstMatch">getFirstMatch</a></li><li><a href="global.html#getSecondMatch">getSecondMatch</a></li><li><a href="global.html#getVersionPrecision">getVersionPrecision</a></li><li><a href="global.html#map">map</a></li><li><a href="global.html#matchAndReturnConst">matchAndReturnConst</a></li></ul>
</nav>
<div id="main">
<h1 class="page-title">BowserUAIsNotAStringError</h1>
<section>
<header>
<h2>
BowserUAIsNotAStringError
</h2>
</header>
<article>
<div class="container-overview">
<h4 class="name" id="BowserUAIsNotAStringError"><span class="type-signature"></span>new BowserUAIsNotAStringError<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="bowser.js.html">bowser.js</a>, <a href="bowser.js.html#line20">line 20</a>
</li></ul></dd>
</dl>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
</td>
<td class="description last"></td>
</tr>
</tbody>
</table>
</div>
</article>
</section>
</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Tue Jul 16 2019 22:20:27 GMT+0300 (Eastern European Summer Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,49 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8">
<meta charset="utf-8"> <title>bowser.js - Documentation</title>
<title>bowser.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<script src="scripts/prettify/prettify.js"></script> <!--[if lt IE 9]>
<script src="scripts/prettify/lang-css.js"></script> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<!--[if lt IE 9]> <![endif]-->
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <link type="text/css" rel="stylesheet" href="styles/prettify.css">
<![endif]--> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<link type="text/css" rel="stylesheet" href="styles/prettify.css"> </head>
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <body>
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <input type="checkbox" id="nav-trigger" class="nav-trigger" />
</head> <label for="nav-trigger" class="navicon-button x">
<body> <div class="navicon"></div>
</label>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x"> <label for="nav-trigger" class="overlay"></label>
<div class="navicon"></div>
</label> <nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3><a href="global.html">Global</a></h3>
<label for="nav-trigger" class="overlay"></label> </nav>
<nav > <div id="main">
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getEngineName">getEngineName</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#isBrowser">isBrowser</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#assign">assign</a></li><li><a href="global.html#find">find</a></li><li><a href="global.html#getAndroidVersionName">getAndroidVersionName</a></li><li><a href="global.html#getBrowserAlias">getBrowserAlias</a></li><li><a href="global.html#getBrowserTypeByAlias">getBrowserTypeByAlias</a></li><li><a href="global.html#getFirstMatch">getFirstMatch</a></li><li><a href="global.html#getMacOSVersionName">getMacOSVersionName</a></li><li><a href="global.html#getSecondMatch">getSecondMatch</a></li><li><a href="global.html#getVersionPrecision">getVersionPrecision</a></li><li><a href="global.html#map">map</a></li><li><a href="global.html#matchAndReturnConst">matchAndReturnConst</a></li></ul> <h1 class="page-title">bowser.js</h1>
</nav>
<div id="main">
<h1 class="page-title">bowser.js</h1>
<section>
<article>
<section>
<article>
<pre class="prettyprint source linenums"><code>/*! <pre class="prettyprint source linenums"><code>/*!
* Bowser - a browser detector * Bowser - a browser detector
* https://github.com/lancedikson/bowser * https://github.com/lancedikson/bowser
* MIT License | (c) Dustin Diaz 2012-2015 * MIT License | (c) Dustin Diaz 2012-2015
* MIT License | (c) Denis Demchenko 2015-2019 * MIT License | (c) Denis Demchenko 2015-2017
*/ */
import Parser from './parser.js'; import Parser from './parser';
import {
BROWSER_MAP,
ENGINE_MAP,
OS_MAP,
PLATFORMS_MAP,
} from './constants.js';
/** /**
* Bowser class. * Bowser class.
@ -62,24 +51,19 @@ import {
* It's supposed to work with collections of {@link Parser} instances * It's supposed to work with collections of {@link Parser} instances
* rather then solve one-instance problems. * rather then solve one-instance problems.
* All the one-instance stuff is located in Parser class. * All the one-instance stuff is located in Parser class.
*
* @class
* @classdesc Bowser is a static object, that provides an API to the Parsers
* @hideconstructor
*/ */
class Bowser { class Bowser {
/** /**
* Creates a {@link Parser} instance * Creates a {@link module:parser:Parser} instance
* *
* @param {String} UA UserAgent string * @param {String} UA UserAgent string
* @param {Boolean} [skipParsing=false] Will make the Parser postpone parsing until you ask it * @param {Boolean} [skipParsing=false] same as skipParsing for {@link Parser}
* explicitly. Same as `skipParsing` for {@link Parser}.
* @returns {Parser} * @returns {Parser}
* @throws {Error} when UA is not a String * @throws {Error} when UA is not a String
* *
* @example * @example
* const parser = Bowser.getParser(window.navigator.userAgent); * const bowser = new Bowser(window.navigator.userAgent);
* const result = parser.getResult(); * bowser.getResult()
*/ */
static getParser(UA, skipParsing = false) { static getParser(UA, skipParsing = false) {
if (typeof UA !== 'string') { if (typeof UA !== 'string') {
@ -93,54 +77,29 @@ class Bowser {
* *
* @param UA * @param UA
* @return {ParsedResult} * @return {ParsedResult}
*
* @example
* const result = Bowser.parse(window.navigator.userAgent);
*/ */
static parse(UA) { static parse(UA) {
return (new Parser(UA)).getResult(); return (new Parser(UA)).getResult();
} }
static get BROWSER_MAP() {
return BROWSER_MAP;
}
static get ENGINE_MAP() {
return ENGINE_MAP;
}
static get OS_MAP() {
return OS_MAP;
}
static get PLATFORMS_MAP() {
return PLATFORMS_MAP;
}
} }
export default Bowser; export default Bowser;
</code></pre> </code></pre>
</article> </article>
</section> </section>
</div>
</div> <br class="clear">
<br class="clear"> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
<footer> </footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Sat Sep 12 2020 11:21:13 GMT+0300 (Eastern European Summer Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> <script>prettyPrint();</script>
<script src="scripts/linenumber.js"></script>
<script>prettyPrint();</script> </body>
<script src="scripts/polyfill.js"></script> </html>
<script src="scripts/linenumber.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,116 +1,84 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8">
<meta charset="utf-8"> <title>Home - Documentation</title>
<title>Home - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<script src="scripts/prettify/prettify.js"></script> <!--[if lt IE 9]>
<script src="scripts/prettify/lang-css.js"></script> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<!--[if lt IE 9]> <![endif]-->
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <link type="text/css" rel="stylesheet" href="styles/prettify.css">
<![endif]--> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<link type="text/css" rel="stylesheet" href="styles/prettify.css"> </head>
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <body>
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <input type="checkbox" id="nav-trigger" class="nav-trigger" />
</head> <label for="nav-trigger" class="navicon-button x">
<body> <div class="navicon"></div>
</label>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x"> <label for="nav-trigger" class="overlay"></label>
<div class="navicon"></div>
</label> <nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3><a href="global.html">Global</a></h3>
<label for="nav-trigger" class="overlay"></label> </nav>
<nav > <div id="main">
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getEngineName">getEngineName</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#isBrowser">isBrowser</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#assign">assign</a></li><li><a href="global.html#find">find</a></li><li><a href="global.html#getAndroidVersionName">getAndroidVersionName</a></li><li><a href="global.html#getBrowserAlias">getBrowserAlias</a></li><li><a href="global.html#getBrowserTypeByAlias">getBrowserTypeByAlias</a></li><li><a href="global.html#getFirstMatch">getFirstMatch</a></li><li><a href="global.html#getMacOSVersionName">getMacOSVersionName</a></li><li><a href="global.html#getSecondMatch">getSecondMatch</a></li><li><a href="global.html#getVersionPrecision">getVersionPrecision</a></li><li><a href="global.html#map">map</a></li><li><a href="global.html#matchAndReturnConst">matchAndReturnConst</a></li></ul>
</nav>
<div id="main">
<section class="package">
<h3> </h3>
</section>
<section class="readme">
<article><h2>Bowser</h2><p>A Browser detector. Because sometimes, there is no other way, and not even good modern browsers always provide good feature detection mechanisms.</p>
<p><a href="https://travis-ci.org/lancedikson/bowser/"><img src="https://travis-ci.org/lancedikson/bowser.svg?branch=master" alt="Build Status"></a></p>
<h1>Contents</h1><ul>
<section class="readme">
<article><h2>Bowser</h2>
<p>A small, fast and rich-API browser/platform/engine detector for both browser and node.</p>
<ul>
<li><strong>Small.</strong> Use plain ES5-version which is ~4.8kB gzipped.</li>
<li><strong>Optimized.</strong> Use only those parsers you need — it doesn't do useless work.</li>
<li><strong>Multi-platform.</strong> It's browser- and node-ready, so you can use it in any environment.</li>
</ul>
<p>Don't hesitate to support the project on Github or <a href="https://opencollective.com/bowser">OpenCollective</a> if you like it ❤️ Also, contributors are always welcome!</p>
<p><a href="https://opencollective.com/bowser"><img src="https://opencollective.com/bowser/all/badge.svg?label=financial+contributors" alt="Financial Contributors on Open Collective"></a> <a href="https://travis-ci.org/lancedikson/bowser/"><img src="https://travis-ci.org/lancedikson/bowser.svg?branch=master" alt="Build Status"></a> <a href="https://greenkeeper.io/"><img src="https://badges.greenkeeper.io/lancedikson/bowser.svg" alt="Greenkeeper badge"></a> <a href="https://coveralls.io/github/lancedikson/bowser?branch=master"><img src="https://coveralls.io/repos/github/lancedikson/bowser/badge.svg?branch=master" alt="Coverage Status"></a> <img src="https://img.shields.io/npm/dm/bowser" alt="Downloads"></p>
<h1>Contents</h1>
<ul>
<li><a href="#overview">Overview</a></li> <li><a href="#overview">Overview</a></li>
<li><a href="#use-cases">Use cases</a></li> <li><a href="#use-cases">Use cases</a></li>
<li><a href="#advanced-usage">Advanced usage</a></li> <li><a href="#advanced-usage">Advanced usage</a></li>
<li><a href="#contributing">How can I help?</a></li> <li><a href="#contributing">How can I help?</a></li>
</ul> </ul>
<h1>Overview</h1> <h1>Overview</h1><p>The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers.</p>
<p>The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers. Check it out on this page: https://bowser-js.github.io/bowser-online/.</p> <p><em>Please, note that this is an alpha version. Check out the <a href="https://github.com/lancedikson/bowser/tree/v1.x">1.x</a> branch for a stable version.</em></p>
<h3>⚠️ Version 2.0 breaking changes ⚠️</h3> <p><strong>Changes of the 2.0</strong>
<p>Version 2.0 has drastically changed the API. All available methods are on the <a href="https://lancedikson.github.io/bowser/docs">docs page</a>.</p> The upcoming 2.0 version has drastically changed API. All available methods can be found in the <code>docs</code> folder from now on and on a webpage soon.</p>
<p><em>For legacy code, check out the <a href="https://github.com/lancedikson/bowser/tree/v1.x">1.x</a> branch and install it through <code>npm install bowser@1.9.4</code>.</em></p> <h1>Use cases</h1><p>First of all, require the library:</p>
<h1>Use cases</h1> <pre class="prettyprint source lang-javascript"><code>const bowser = require('bowser');</code></pre><p>By default, <code>require('bowser')</code> requires the <em>ES5 version of files</em>, which
<p>First of all, require the library. This is a UMD Module, so it will work for AMD, TypeScript, ES6, and CommonJS module systems.</p> <strong>do not</strong> include any polyfills.</p>
<pre class="prettyprint source lang-javascript"><code>const Bowser = require(&quot;bowser&quot;); // CommonJS <p>In case if you don't use your own <code>babel-polyfill</code> you may need to have pre-built bundle with all needed polyfills.
import * as Bowser from &quot;bowser&quot;; // TypeScript
import Bowser from &quot;bowser&quot;; // ES6 (and TypeScript with --esModuleInterop enabled)
</code></pre>
<p>By default, the exported version is the <em>ES5 transpiled version</em>, which <strong>do not</strong> include any polyfills.</p>
<p>In case you don't use your own <code>babel-polyfill</code> you may need to have pre-built bundle with all needed polyfills.
So, for you it's suitable to require bowser like this: <code>require('bowser/bundled')</code>. So, for you it's suitable to require bowser like this: <code>require('bowser/bundled')</code>.
As the result, you get a ES5 version of bowser with <code>babel-polyfill</code> bundled together.</p> As the result, you get a ES5 version of bowser with <code>babel-polyfill</code> bundled together.</p>
<p>You may need to use the source files, so they will be available in the package as well.</p> <p>You may need to use the source files, so they will be available in the package as well.</p>
<h2>Browser props detection</h2> <h2>Browser props detection</h2><p>Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to make it with Bowser:</p>
<p>Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to do it with Bowser:</p> <pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
<pre class="prettyprint source lang-javascript"><code>const browser = Bowser.getParser(window.navigator.userAgent);
console.log(`The current browser name is &quot;${browser.getBrowserName()}&quot;`); console.log(`The current browser name is &quot;${browser.getBrowserName()}&quot;`);
// The current browser name is &quot;Internet Explorer&quot; // The current browser name is &quot;Internet Explorer&quot;</code></pre><p>or</p>
</code></pre> <pre class="prettyprint source lang-javascript"><code>const impression = new Impression();
<p>or</p>
<pre class="prettyprint source lang-javascript"><code>const browser = Bowser.getParser(window.navigator.userAgent);
console.log(browser.getBrowser());
// outputs
{
name: &quot;Internet Explorer&quot;
version: &quot;11.0&quot;
}
</code></pre>
<p>or</p>
<pre class="prettyprint source lang-javascript"><code>console.log(Bowser.parse(window.navigator.userAgent));
const browser = bowser.getParser(window.navigator.userAgent);
const browserInfo = browser.getBrowser();
impression.brName = browserInfo.name;
impression.brVer = browserInfo.version;</code></pre><p>or</p>
<pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
impression.userTechData = browser.parse();
console.log(impression.userTechData);
// outputs // outputs
{ {
browser: { browser: {
@ -129,12 +97,9 @@ console.log(browser.getBrowser());
name: &quot;Trident&quot; name: &quot;Trident&quot;
version: &quot;7.0&quot; version: &quot;7.0&quot;
} }
} }</code></pre><h2>Filtering browsers</h2><p>You could want to filter some particular browsers to provide any special support for them or make any workarounds.
</code></pre>
<h2>Filtering browsers</h2>
<p>You could want to filter some particular browsers to provide any special support for them or make any workarounds.
It could look like this:</p> It could look like this:</p>
<pre class="prettyprint source lang-javascript"><code>const browser = Bowser.getParser(window.navigator.userAgent); <pre class="prettyprint source lang-javascript"><code>const browser = bowser.getParser(window.navigator.userAgent);
const isValidBrowser = browser.satisfies({ const isValidBrowser = browser.satisfies({
// declare browsers per OS // declare browsers per OS
windows: { windows: {
@ -146,78 +111,49 @@ const isValidBrowser = browser.satisfies({
// per platform (mobile, desktop or tablet) // per platform (mobile, desktop or tablet)
mobile: { mobile: {
safari: '>=9', safari: '>9',
'android browser': '>3.10' 'android browser': '>3.10'
}, },
// or in general // or in general
chrome: &quot;~20.1.1432&quot;, chrome: &quot;>20.1.1432&quot;,
firefox: &quot;>31&quot;, firefox: &quot;>31&quot;,
opera: &quot;>=22&quot;, opera: &quot;>22&quot;
// also supports equality operator // also supports equality operator
chrome: &quot;=20.1.1432&quot;, // will match particular build only chrome: &quot;=20.1.1432&quot;, // will match particular build only
// and loose-equality operator // and loose-equality operator
chrome: &quot;~20&quot;, // will match any 20.* sub-version chrome: &quot;~20&quot; // will match any 20.* sub-version
chrome: &quot;~20.1&quot; // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1) chrome: &quot;~20.1&quot; // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1)
}); });</code></pre><p>Settings for any particular OS or platform has more priority and redefines settings of standalone browsers.
</code></pre>
<p>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.</p> Thus, you can define OS or platform specific rules and they will have more priority in the end.</p>
<p>More of API and possibilities you will find in the <code>docs</code> folder.</p> <p>More of API and possibilities you will find in the <code>docs</code> folder.</p>
<h3>Browser names for <code>.satisfies()</code></h3> <h1>Contributing</h1><p>If you'd like to contribute a change to bowser, modify the files in <code>src/</code>, then run the following (you'll need node + npm installed):</p>
<p>By default you are supposed to use the full browser name for <code>.satisfies</code>. <pre class="prettyprint source lang-sh"><code>$ npm install
But, there's a short way to define a browser using short aliases. The full $ npm test</code></pre><h3>Adding tests</h3><p>See the list in <code>test/acceptance/useragentstrings.yml</code> with example user agents and their expected bowser object.</p>
list of aliases can be found in <a href="src/constants.js">the file</a>.</p> <p>Whenever you add support for new browsers or notice a bug / mismatch, please update the list and
<h2>Similar Projects</h2> check if all tests are still passing.</p>
<ul> <h3>Similar Projects</h3><ul>
<li><a href="https://github.com/BigBadBleuCheese/Kong">Kong</a> - A C# port of Bowser.</li> <li><a href="https://github.com/BigBadBleuCheese/Kong">Kong</a> - A C# port of Bowser.</li>
</ul> </ul>
<h2>Contributors</h2> <h3>License</h3><p>Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.</p></article>
<h3>Code Contributors</h3> </section>
<p>This project exists thanks to all the people who contribute. [<a href="CONTRIBUTING.md">Contribute</a>].
<a href="https://github.com/lancedikson/bowser/graphs/contributors"><img src="https://opencollective.com/bowser/contributors.svg?width=890&button=false" /></a></p>
<h3>Financial Contributors</h3>
<p>Become a financial contributor and help us sustain our community. [<a href="https://opencollective.com/bowser/contribute">Contribute</a>]</p>
<h4>Individuals</h4>
<p><a href="https://opencollective.com/bowser"><img src="https://opencollective.com/bowser/individuals.svg?width=890"></a></p>
<h4>Organizations</h4> </div>
<p>Support this project with your organization. Your logo will show up here with a link to your website. [<a href="https://opencollective.com/bowser/contribute">Contribute</a>]</p>
<p><a href="https://opencollective.com/bowser/organization/0/website"><img src="https://opencollective.com/bowser/organization/0/avatar.svg"></a> <br class="clear">
<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> <footer>
<a href="https://opencollective.com/bowser/organization/3/website"><img src="https://opencollective.com/bowser/organization/3/avatar.svg"></a> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
<a href="https://opencollective.com/bowser/organization/4/website"><img src="https://opencollective.com/bowser/organization/4/avatar.svg"></a> </footer>
<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> <script>prettyPrint();</script>
<a href="https://opencollective.com/bowser/organization/7/website"><img src="https://opencollective.com/bowser/organization/7/avatar.svg"></a> <script src="scripts/linenumber.js"></script>
<a href="https://opencollective.com/bowser/organization/8/website"><img src="https://opencollective.com/bowser/organization/8/avatar.svg"></a> </body>
<a href="https://opencollective.com/bowser/organization/9/website"><img src="https://opencollective.com/bowser/organization/9/avatar.svg"></a></p>
<h2>License</h2>
<p>Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.</p></article>
</section>
</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Sat Sep 12 2020 11:21:13 GMT+0300 (Eastern European Summer Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>
</body>
</html> </html>

View File

@ -1,52 +1,47 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8">
<meta charset="utf-8"> <title>parser.js - Documentation</title>
<title>parser.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<script src="scripts/prettify/prettify.js"></script> <!--[if lt IE 9]>
<script src="scripts/prettify/lang-css.js"></script> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<!--[if lt IE 9]> <![endif]-->
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <link type="text/css" rel="stylesheet" href="styles/prettify.css">
<![endif]--> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<link type="text/css" rel="stylesheet" href="styles/prettify.css"> </head>
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <body>
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <input type="checkbox" id="nav-trigger" class="nav-trigger" />
</head> <label for="nav-trigger" class="navicon-button x">
<body> <div class="navicon"></div>
</label>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x"> <label for="nav-trigger" class="overlay"></label>
<div class="navicon"></div>
</label> <nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3><a href="global.html">Global</a></h3>
<label for="nav-trigger" class="overlay"></label> </nav>
<nav > <div id="main">
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getEngineName">getEngineName</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#isBrowser">isBrowser</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#assign">assign</a></li><li><a href="global.html#find">find</a></li><li><a href="global.html#getAndroidVersionName">getAndroidVersionName</a></li><li><a href="global.html#getBrowserAlias">getBrowserAlias</a></li><li><a href="global.html#getBrowserTypeByAlias">getBrowserTypeByAlias</a></li><li><a href="global.html#getFirstMatch">getFirstMatch</a></li><li><a href="global.html#getMacOSVersionName">getMacOSVersionName</a></li><li><a href="global.html#getSecondMatch">getSecondMatch</a></li><li><a href="global.html#getVersionPrecision">getVersionPrecision</a></li><li><a href="global.html#map">map</a></li><li><a href="global.html#matchAndReturnConst">matchAndReturnConst</a></li></ul> <h1 class="page-title">parser.js</h1>
</nav>
<div id="main">
<h1 class="page-title">parser.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>import browserParsersList from './parser-browsers';
import osParsersList from './parser-os';
import platformParsersList from './parser-platforms';
<section> import enginesParsersList from './parser-engines';
<article> import { compareVersions } from './utils';
<pre class="prettyprint source linenums"><code>import browserParsersList from './parser-browsers.js';
import osParsersList from './parser-os.js';
import platformParsersList from './parser-platforms.js';
import enginesParsersList from './parser-engines.js';
import Utils from './utils.js';
/** /**
* The main class that arranges the whole parsing process. * The main class that arranges the whole parsing process.
@ -126,7 +121,7 @@ class Parser {
parseBrowser() { parseBrowser() {
this.parsedResult.browser = {}; this.parsedResult.browser = {};
const browserDescriptor = Utils.find(browserParsersList, (_browser) => { const browserDescriptor = browserParsersList.find((_browser) => {
if (typeof _browser.test === 'function') { if (typeof _browser.test === 'function') {
return _browser.test(this); return _browser.test(this);
} }
@ -209,7 +204,7 @@ class Parser {
parseOS() { parseOS() {
this.parsedResult.os = {}; this.parsedResult.os = {};
const os = Utils.find(osParsersList, (_os) => { const os = osParsersList.find((_os) => {
if (typeof _os.test === 'function') { if (typeof _os.test === 'function') {
return _os.test(this); return _os.test(this);
} }
@ -285,7 +280,7 @@ class Parser {
parsePlatform() { parsePlatform() {
this.parsedResult.platform = {}; this.parsedResult.platform = {};
const platform = Utils.find(platformParsersList, (_platform) => { const platform = platformParsersList.find((_platform) => {
if (typeof _platform.test === 'function') { if (typeof _platform.test === 'function') {
return _platform.test(this); return _platform.test(this);
} }
@ -316,19 +311,6 @@ class Parser {
return this.parseEngine(); return this.parseEngine();
} }
/**
* Get engines's name
* @return {String} Engines's name or an empty string
*
* @public
*/
getEngineName(toLowerCase) {
if (toLowerCase) {
return String(this.getEngine().name).toLowerCase() || '';
}
return this.getEngine().name || '';
}
/** /**
* Get parsed platform * Get parsed platform
* @return {{}} * @return {{}}
@ -336,7 +318,7 @@ class Parser {
parseEngine() { parseEngine() {
this.parsedResult.engine = {}; this.parsedResult.engine = {};
const engine = Utils.find(enginesParsersList, (_engine) => { const engine = enginesParsersList.find((_engine) => {
if (typeof _engine.test === 'function') { if (typeof _engine.test === 'function') {
return _engine.test(this); return _engine.test(this);
} }
@ -357,7 +339,6 @@ class Parser {
/** /**
* Parse full information about the browser * Parse full information about the browser
* @returns {Parser}
*/ */
parse() { parse() {
this.parseBrowser(); this.parseBrowser();
@ -373,7 +354,8 @@ class Parser {
* @return {ParsedResult} * @return {ParsedResult}
*/ */
getResult() { getResult() {
return Utils.assign({}, this.parsedResult); /* TODO: Make this function pure, return a new object instead of the reference */
return this.parsedResult;
} }
/** /**
@ -387,12 +369,12 @@ class Parser {
* Returns `undefined` when the browser is no described in the checkTree object. * Returns `undefined` when the browser is no described in the checkTree object.
* *
* @example * @example
* const browser = Bowser.getParser(window.navigator.userAgent); * const browser = new Bowser(UA);
* if (browser.satisfies({chrome: '>118.01.1322' })) * if (browser.check({chrome: '>118.01.1322' }))
* // or with os * // or with os
* if (browser.satisfies({windows: { chrome: '>118.01.1322' } })) * if (browser.check({windows: { chrome: '>118.01.1322' } }))
* // or with platforms * // or with platforms
* if (browser.satisfies({desktop: { chrome: '>118.01.1322' } })) * if (browser.check({desktop: { chrome: '>118.01.1322' } }))
*/ */
satisfies(checkTree) { satisfies(checkTree) {
const platformsAndOSes = {}; const platformsAndOSes = {};
@ -415,7 +397,7 @@ class Parser {
if (platformsAndOSCounter > 0) { if (platformsAndOSCounter > 0) {
const platformsAndOSNames = Object.keys(platformsAndOSes); const platformsAndOSNames = Object.keys(platformsAndOSes);
const OSMatchingDefinition = Utils.find(platformsAndOSNames, name => (this.isOS(name))); const OSMatchingDefinition = platformsAndOSNames.find(name => (this.isOS(name)));
if (OSMatchingDefinition) { if (OSMatchingDefinition) {
const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]); const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]);
@ -425,10 +407,7 @@ class Parser {
} }
} }
const platformMatchingDefinition = Utils.find( const platformMatchingDefinition = platformsAndOSNames.find(name => (this.isPlatform(name)));
platformsAndOSNames,
name => (this.isPlatform(name)),
);
if (platformMatchingDefinition) { if (platformMatchingDefinition) {
const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]); const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]);
@ -440,7 +419,7 @@ class Parser {
if (browsersCounter > 0) { if (browsersCounter > 0) {
const browserNames = Object.keys(browsers); const browserNames = Object.keys(browsers);
const matchingDefinition = Utils.find(browserNames, name => (this.isBrowser(name, true))); const matchingDefinition = browserNames.find(name => (this.isBrowser(name)));
if (matchingDefinition !== void 0) { if (matchingDefinition !== void 0) {
return this.compareVersion(browsers[matchingDefinition]); return this.compareVersion(browsers[matchingDefinition]);
@ -450,47 +429,21 @@ class Parser {
return undefined; return undefined;
} }
/** isBrowser(browserName) {
* Check if the browser name equals the passed string return this.getBrowserName(true) === String(browserName).toLowerCase();
* @param browserName The string to compare with the browser name
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {boolean}
*/
isBrowser(browserName, includingAlias = false) {
const defaultBrowserName = this.getBrowserName().toLowerCase();
let browserNameLower = browserName.toLowerCase();
const alias = Utils.getBrowserTypeByAlias(browserNameLower);
if (includingAlias &amp;&amp; alias) {
browserNameLower = alias.toLowerCase();
}
return browserNameLower === defaultBrowserName;
} }
compareVersion(version) { compareVersion(version) {
let expectedResults = [0]; let expectedResult = 0;
let comparableVersion = version; let comparableVersion = version;
let isLoose = false; let isLoose = false;
const currentBrowserVersion = this.getBrowserVersion(); if (version[0] === '>') {
expectedResult = 1;
if (typeof currentBrowserVersion !== 'string') { comparableVersion = version.substr(1);
return void 0; } else if (version[0] === '&lt;') {
} expectedResult = -1;
if (version[0] === '>' || version[0] === '&lt;') {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
if (version[1] === '=') {
isLoose = true;
comparableVersion = version.substr(2);
} else {
expectedResults = [];
}
if (version[0] === '>') {
expectedResults.push(1);
} else {
expectedResults.push(-1);
}
} else if (version[0] === '=') { } else if (version[0] === '=') {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} else if (version[0] === '~') { } else if (version[0] === '~') {
@ -498,9 +451,7 @@ class Parser {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} }
return expectedResults.indexOf( return compareVersions(this.getBrowserVersion(), comparableVersion, isLoose) === expectedResult;
Utils.compareVersions(currentBrowserVersion, comparableVersion, isLoose),
) > -1;
} }
isOS(osName) { isOS(osName) {
@ -511,24 +462,18 @@ class Parser {
return this.getPlatformType(true) === String(platformType).toLowerCase(); return this.getPlatformType(true) === String(platformType).toLowerCase();
} }
isEngine(engineName) {
return this.getEngineName(true) === String(engineName).toLowerCase();
}
/** /**
* Is anything? Check if the browser is called "anything", * Is anything? Check if the browser is called "anything",
* the OS called "anything" or the platform called "anything" * the OS called "anything" or the platform called "anything"
* @param {String} anything * @param {String} anything
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {Boolean} * @returns {Boolean}
*/ */
is(anything, includingAlias = false) { is(anything) {
return this.isBrowser(anything, includingAlias) || this.isOS(anything) return this.isBrowser(anything) || this.isOS(anything) || this.isPlatform(anything);
|| this.isPlatform(anything);
} }
/** /**
* Check if any of the given values satisfies this.is(anything) * Check if any of the given values satifies this.is(anything)
* @param {String[]} anythings * @param {String[]} anythings
* @returns {Boolean} * @returns {Boolean}
*/ */
@ -538,28 +483,22 @@ class Parser {
} }
export default Parser; export default Parser;
</code></pre> </code></pre>
</article> </article>
</section> </section>
</div>
</div> <br class="clear">
<br class="clear"> <footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
<footer> </footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Sat Sep 12 2020 11:21:13 GMT+0300 (Eastern European Summer Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer> <script>prettyPrint();</script>
<script src="scripts/linenumber.js"></script>
<script>prettyPrint();</script> </body>
<script src="scripts/polyfill.js"></script> </html>
<script src="scripts/linenumber.js"></script>
</body>
</html>

View File

@ -1,20 +0,0 @@
function hideAllButCurrent(){
//by default all submenut items are hidden
//but we need to rehide them for search
document.querySelectorAll("nav > ul > li > ul li").forEach(function(parent) {
parent.style.display = "none";
});
//only current page (if it exists) should be opened
var file = window.location.pathname.split("/").pop().replace(/\.html/, '');
document.querySelectorAll("nav > ul > li > a").forEach(function(parent) {
var href = parent.attributes.href.value.replace(/\.html/, '');
if (file === href) {
parent.parentNode.querySelectorAll("ul li").forEach(function(elem) {
elem.style.display = "block";
});
}
});
}
hideAllButCurrent();

File diff suppressed because one or more lines are too long

View File

@ -1,25 +1,25 @@
/*global document */ /*global document */
(function() { (function() {
var source = document.getElementsByClassName('prettyprint source linenums'); var source = document.getElementsByClassName('prettyprint source linenums');
var i = 0; var i = 0;
var lineNumber = 0; var lineNumber = 0;
var lineId; var lineId;
var lines; var lines;
var totalLines; var totalLines;
var anchorHash; var anchorHash;
if (source && source[0]) { if (source && source[0]) {
anchorHash = document.location.hash.substring(1); anchorHash = document.location.hash.substring(1);
lines = source[0].getElementsByTagName('li'); lines = source[0].getElementsByTagName('li');
totalLines = lines.length; totalLines = lines.length;
for (; i < totalLines; i++) { for (; i < totalLines; i++) {
lineNumber++; lineNumber++;
lineId = 'line' + lineNumber; lineId = 'line' + lineNumber;
lines[i].id = lineId; lines[i].id = lineId;
if (lineId === anchorHash) { if (lineId === anchorHash) {
lines[i].className += ' selected'; lines[i].className += ' selected';
} }
} }
} }
})(); })();

View File

@ -1,12 +0,0 @@
function scrollToNavItem() {
var path = window.location.href.split('/').pop().replace(/\.html/, '');
document.querySelectorAll('nav a').forEach(function(link) {
var href = link.attributes.href.value.replace(/\.html/, '');
if (path === href) {
link.scrollIntoView({block: 'center'});
return;
}
})
}
scrollToNavItem();

View File

@ -1,4 +0,0 @@
//IE Fix, src: https://www.reddit.com/r/programminghorror/comments/6abmcr/nodelist_lacks_foreach_in_internet_explorer/
if (typeof(NodeList.prototype.forEach)!==typeof(alert)){
NodeList.prototype.forEach=Array.prototype.forEach;
}

View File

@ -1,202 +1,202 @@
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004
http://www.apache.org/licenses/ http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions. 1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, "License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document. and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by "Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License. the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all "Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition, control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the "control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity. outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity "You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License. exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, "Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation including but not limited to software source code, documentation
source, and configuration files. source, and configuration files.
"Object" form shall mean any form resulting from mechanical "Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation, not limited to compiled object code, generated documentation,
and conversions to other media types. and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or "Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work copyright notice that is included in or attached to the work
(an example is provided in the Appendix below). (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object "Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of, separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof. the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including "Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted" the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution." designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity "Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work. subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of 2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual, this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of, copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form. Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of 3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual, this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made, (except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work, use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s) Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate granted to You under this License for that Work shall terminate
as of the date such litigation is filed. as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the 4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You modifications, and in Source or Object form, provided that You
meet the following conditions: meet the following conditions:
(a) You must give any other recipients of the Work or (a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices (b) You must cause any modified files to carry prominent notices
stating that You changed the files; and stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works (c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work, attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of excluding those notices that do not pertain to any part of
the Derivative Works; and the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its (d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or, documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed that such additional attribution notices cannot be construed
as modifying the License. as modifying the License.
You may add Your own copyright statement to Your modifications and You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use, for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License. the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, 5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions. this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions. with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade 6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor, names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file. origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or 7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS, Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License. risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, 8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise, whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill, Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages. has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing 9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer, the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity, and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify, of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability. of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work. APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]" boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright [yyyy] [name of copyright owner] Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.

View File

@ -1,2 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);

View File

@ -1,28 +1,28 @@
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c< [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&& f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r= (j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length, {b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b=== t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), "string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value", for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m= m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue= a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b= hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m, !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit", 250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})(); PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

View File

@ -1,83 +0,0 @@
var searchAttr = 'data-search-mode';
function contains(a,m){
return (a.textContent || a.innerText || "").toUpperCase().indexOf(m) !== -1;
};
//on search
document.getElementById("nav-search").addEventListener("keyup", function(event) {
var search = this.value.toUpperCase();
if (!search) {
//no search, show all results
document.documentElement.removeAttribute(searchAttr);
document.querySelectorAll("nav > ul > li:not(.level-hide)").forEach(function(elem) {
elem.style.display = "block";
});
if (typeof hideAllButCurrent === "function"){
//let's do what ever collapse wants to do
hideAllButCurrent();
} else {
//menu by default should be opened
document.querySelectorAll("nav > ul > li > ul li").forEach(function(elem) {
elem.style.display = "block";
});
}
} else {
//we are searching
document.documentElement.setAttribute(searchAttr, '');
//show all parents
document.querySelectorAll("nav > ul > li").forEach(function(elem) {
elem.style.display = "block";
});
//hide all results
document.querySelectorAll("nav > ul > li > ul li").forEach(function(elem) {
elem.style.display = "none";
});
//show results matching filter
document.querySelectorAll("nav > ul > li > ul a").forEach(function(elem) {
if (!contains(elem.parentNode, search)) {
return;
}
elem.parentNode.style.display = "block";
});
//hide parents without children
document.querySelectorAll("nav > ul > li").forEach(function(parent) {
var countSearchA = 0;
parent.querySelectorAll("a").forEach(function(elem) {
if (contains(elem, search)) {
countSearchA++;
}
});
var countUl = 0;
var countUlVisible = 0;
parent.querySelectorAll("ul").forEach(function(ulP) {
// count all elements that match the search
if (contains(ulP, search)) {
countUl++;
}
// count all visible elements
var children = ulP.children
for (i=0; i<children.length; i++) {
var elem = children[i];
if (elem.style.display != "none") {
countUlVisible++;
}
}
});
if (countSearchA == 0 && countUl === 0){
//has no child at all and does not contain text
parent.style.display = "none";
} else if(countSearchA == 0 && countUlVisible == 0){
//has no visible child and does not contain text
parent.style.display = "none";
}
});
}
});

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +1,79 @@
.pln { .pln {
color: #ddd; color: #ddd;
} }
/* string content */ /* string content */
.str { .str {
color: #61ce3c; color: #61ce3c;
} }
/* a keyword */ /* a keyword */
.kwd { .kwd {
color: #fbde2d; color: #fbde2d;
} }
/* a comment */ /* a comment */
.com { .com {
color: #aeaeae; color: #aeaeae;
} }
/* a type name */ /* a type name */
.typ { .typ {
color: #8da6ce; color: #8da6ce;
} }
/* a literal value */ /* a literal value */
.lit { .lit {
color: #fbde2d; color: #fbde2d;
} }
/* punctuation */ /* punctuation */
.pun { .pun {
color: #ddd; color: #ddd;
} }
/* lisp open bracket */ /* lisp open bracket */
.opn { .opn {
color: #000000; color: #000000;
} }
/* lisp close bracket */ /* lisp close bracket */
.clo { .clo {
color: #000000; color: #000000;
} }
/* a markup tag name */ /* a markup tag name */
.tag { .tag {
color: #8da6ce; color: #8da6ce;
} }
/* a markup attribute name */ /* a markup attribute name */
.atn { .atn {
color: #fbde2d; color: #fbde2d;
} }
/* a markup attribute value */ /* a markup attribute value */
.atv { .atv {
color: #ddd; color: #ddd;
} }
/* a declaration */ /* a declaration */
.dec { .dec {
color: #EF5050; color: #EF5050;
} }
/* a variable name */ /* a variable name */
.var { .var {
color: #c82829; color: #c82829;
} }
/* a function name */ /* a function name */
.fun { .fun {
color: #4271ae; color: #4271ae;
} }
/* Specify class=linenums on a pre to get line numbering */ /* Specify class=linenums on a pre to get line numbering */
ol.linenums { ol.linenums {
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
} }

View File

@ -1,50 +1,43 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8">
<meta charset="utf-8"> <title>utils.js - Documentation</title>
<title>utils.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<script src="scripts/prettify/prettify.js"></script> <!--[if lt IE 9]>
<script src="scripts/prettify/lang-css.js"></script> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<!--[if lt IE 9]> <![endif]-->
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <link type="text/css" rel="stylesheet" href="styles/prettify.css">
<![endif]--> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<link type="text/css" rel="stylesheet" href="styles/prettify.css"> </head>
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <body>
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <input type="checkbox" id="nav-trigger" class="nav-trigger" />
</head> <label for="nav-trigger" class="navicon-button x">
<body> <div class="navicon"></div>
</label>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x"> <label for="nav-trigger" class="overlay"></label>
<div class="navicon"></div>
</label> <nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3><a href="global.html">Global</a></h3>
<label for="nav-trigger" class="overlay"></label> </nav>
<nav > <div id="main">
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Bowser.html">Bowser</a><ul class='methods'><li data-type='method'><a href="Bowser.html#.getParser">getParser</a></li><li data-type='method'><a href="Bowser.html#.parse">parse</a></li></ul></li><li><a href="Parser.html">Parser</a><ul class='methods'><li data-type='method'><a href="Parser.html#getBrowser">getBrowser</a></li><li data-type='method'><a href="Parser.html#getBrowserName">getBrowserName</a></li><li data-type='method'><a href="Parser.html#getBrowserVersion">getBrowserVersion</a></li><li data-type='method'><a href="Parser.html#getEngine">getEngine</a></li><li data-type='method'><a href="Parser.html#getEngineName">getEngineName</a></li><li data-type='method'><a href="Parser.html#getOS">getOS</a></li><li data-type='method'><a href="Parser.html#getOSName">getOSName</a></li><li data-type='method'><a href="Parser.html#getOSVersion">getOSVersion</a></li><li data-type='method'><a href="Parser.html#getPlatform">getPlatform</a></li><li data-type='method'><a href="Parser.html#getPlatformType">getPlatformType</a></li><li data-type='method'><a href="Parser.html#getResult">getResult</a></li><li data-type='method'><a href="Parser.html#getUA">getUA</a></li><li data-type='method'><a href="Parser.html#is">is</a></li><li data-type='method'><a href="Parser.html#isBrowser">isBrowser</a></li><li data-type='method'><a href="Parser.html#parse">parse</a></li><li data-type='method'><a href="Parser.html#parseBrowser">parseBrowser</a></li><li data-type='method'><a href="Parser.html#parseEngine">parseEngine</a></li><li data-type='method'><a href="Parser.html#parseOS">parseOS</a></li><li data-type='method'><a href="Parser.html#parsePlatform">parsePlatform</a></li><li data-type='method'><a href="Parser.html#satisfies">satisfies</a></li><li data-type='method'><a href="Parser.html#some">some</a></li><li data-type='method'><a href="Parser.html#test">test</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#assign">assign</a></li><li><a href="global.html#find">find</a></li><li><a href="global.html#getAndroidVersionName">getAndroidVersionName</a></li><li><a href="global.html#getBrowserAlias">getBrowserAlias</a></li><li><a href="global.html#getBrowserTypeByAlias">getBrowserTypeByAlias</a></li><li><a href="global.html#getFirstMatch">getFirstMatch</a></li><li><a href="global.html#getMacOSVersionName">getMacOSVersionName</a></li><li><a href="global.html#getSecondMatch">getSecondMatch</a></li><li><a href="global.html#getVersionPrecision">getVersionPrecision</a></li><li><a href="global.html#map">map</a></li><li><a href="global.html#matchAndReturnConst">matchAndReturnConst</a></li></ul> <h1 class="page-title">utils.js</h1>
</nav>
<div id="main">
<h1 class="page-title">utils.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>class Utils {
<section>
<article>
<pre class="prettyprint source linenums"><code>import { BROWSER_MAP, BROWSER_ALIASES_MAP } from './constants.js';
export default class Utils {
/** /**
* Get first matched item for a string * Get first matched item for a string
* @param {RegExp} regexp * @param {RegExp} regexp
@ -97,109 +90,6 @@ export default class Utils {
} }
} }
/**
* Get macOS version name
* 10.5 - Leopard
* 10.6 - Snow Leopard
* 10.7 - Lion
* 10.8 - Mountain Lion
* 10.9 - Mavericks
* 10.10 - Yosemite
* 10.11 - El Capitan
* 10.12 - Sierra
* 10.13 - High Sierra
* 10.14 - Mojave
* 10.15 - Catalina
* 11 - Big Sur
* 12 - Monterey
* 13 - Ventura
* 14 - Sonoma
* 15 - Sequoia
*
* @example
* getMacOSVersionName("10.14") // 'Mojave'
*
* @param {string} version
* @return {string} versionName
*/
static getMacOSVersionName(version) {
const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);
v.push(0);
const major = v[0];
const minor = v[1];
if (major === 10) {
switch (minor) {
case 5: return 'Leopard';
case 6: return 'Snow Leopard';
case 7: return 'Lion';
case 8: return 'Mountain Lion';
case 9: return 'Mavericks';
case 10: return 'Yosemite';
case 11: return 'El Capitan';
case 12: return 'Sierra';
case 13: return 'High Sierra';
case 14: return 'Mojave';
case 15: return 'Catalina';
default: return undefined;
}
}
switch (major) {
case 11: return 'Big Sur';
case 12: return 'Monterey';
case 13: return 'Ventura';
case 14: return 'Sonoma';
case 15: return 'Sequoia';
default: return undefined;
}
}
/**
* Get Android version name
* 1.5 - Cupcake
* 1.6 - Donut
* 2.0 - Eclair
* 2.1 - Eclair
* 2.2 - Froyo
* 2.x - Gingerbread
* 3.x - Honeycomb
* 4.0 - Ice Cream Sandwich
* 4.1 - Jelly Bean
* 4.4 - KitKat
* 5.x - Lollipop
* 6.x - Marshmallow
* 7.x - Nougat
* 8.x - Oreo
* 9.x - Pie
*
* @example
* getAndroidVersionName("7.0") // 'Nougat'
*
* @param {string} version
* @return {string} versionName
*/
static getAndroidVersionName(version) {
const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);
v.push(0);
if (v[0] === 1 &amp;&amp; v[1] &lt; 5) return undefined;
if (v[0] === 1 &amp;&amp; v[1] &lt; 6) return 'Cupcake';
if (v[0] === 1 &amp;&amp; v[1] >= 6) return 'Donut';
if (v[0] === 2 &amp;&amp; v[1] &lt; 2) return 'Eclair';
if (v[0] === 2 &amp;&amp; v[1] === 2) return 'Froyo';
if (v[0] === 2 &amp;&amp; v[1] > 2) return 'Gingerbread';
if (v[0] === 3) return 'Honeycomb';
if (v[0] === 4 &amp;&amp; v[1] &lt; 1) return 'Ice Cream Sandwich';
if (v[0] === 4 &amp;&amp; v[1] &lt; 4) return 'Jelly Bean';
if (v[0] === 4 &amp;&amp; v[1] >= 4) return 'KitKat';
if (v[0] === 5) return 'Lollipop';
if (v[0] === 6) return 'Marshmallow';
if (v[0] === 7) return 'Nougat';
if (v[0] === 8) return 'Oreo';
if (v[0] === 9) return 'Pie';
return undefined;
}
/** /**
* Get version precisions count * Get version precisions count
* *
@ -259,21 +149,16 @@ export default class Utils {
// 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true)
if (chunks[0][precision] > chunks[1][precision]) { if (chunks[0][precision] > chunks[1][precision]) {
return 1; return 1;
} } else if (chunks[0][precision] === chunks[1][precision]) {
if (chunks[0][precision] === chunks[1][precision]) {
if (precision === lastPrecision) { if (precision === lastPrecision) {
// all version chunks are same // all version chunks are same
return 0; return 0;
} }
} else {
precision -= 1;
} else if (chunks[0][precision] &lt; chunks[1][precision]) {
return -1; return -1;
} }
precision -= 1;
} }
return undefined;
} }
/** /**
@ -294,103 +179,25 @@ 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 &lt; 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 &lt; l; i += 1) {
const assigner = assigners[i];
if (typeof assigner === 'object' &amp;&amp; assigner !== null) {
const keys = Object.keys(assigner);
keys.forEach((key) => {
result[key] = assigner[key];
});
}
}
return obj;
}
/**
* 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];
}
/**
* Get short version/alias for a browser name
*
* @example
* getBrowserAlias('edge') // Microsoft Edge
*
* @param {string} browserAlias
* @return {string}
*/
static getBrowserTypeByAlias(browserAlias) {
return BROWSER_MAP[browserAlias] || '';
}
} }
</code></pre>
</article>
</section>
module.exports = Utils;
</code></pre>
</article>
</section>
</div>
<br class="clear">
</div>
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Sat Sep 12 2020 11:21:13 GMT+0300 (Eastern European Summer Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. <br class="clear">
</footer>
<footer>
<script>prettyPrint();</script> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat Aug 18 2018 14:14:47 GMT+0300 (EEST) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
<script src="scripts/polyfill.js"></script> </footer>
<script src="scripts/linenumber.js"></script>
<script>prettyPrint();</script>
<script src="scripts/linenumber.js"></script>
</body>
</body> </html>
</html>

315
index.d.ts vendored
View File

@ -1,315 +0,0 @@
// Type definitions for Bowser v2
// Project: https://github.com/bowser-js/bowser
// Definitions by: Alexander P. Cerutti <https://github.com/alexandercerutti>,
export = Bowser;
export as namespace Bowser;
declare namespace Bowser {
/**
* Creates a Parser instance
* @param {string} UA - User agent string
* @param {boolean} skipParsing
*/
function getParser(UA: string, skipParsing?: boolean): Parser.Parser;
/**
* Creates a Parser instance and runs Parser.getResult immediately
* @param UA - User agent string
* @returns {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 {
interface Parser {
constructor(UA: string, skipParsing?: boolean): Parser.Parser;
/**
* Check if the version is equals the browser version
* @param version The string to compare with the browser version
* @returns {boolean}
*/
compareVersion(version: string): boolean;
/**
* Get parsed browser object
* @return {BrowserDetails} Browser's details
*/
getBrowser(): BrowserDetails;
/**
* Get browser's name
* @param {Boolean} [toLowerCase] return lower-cased value
* @return {String} Browser's name or an empty string
*/
getBrowserName(toLowerCase?: boolean): string;
/**
* Get browser's version
* @return {String} version of browser
*/
getBrowserVersion(): string | undefined;
/**
* Get OS
* @return {OSDetails} - OS Details
*
* @example
* this.getOS(); // {
* // name: 'macOS',
* // version: '10.11.12',
* // }
*/
getOS(): OSDetails;
/**
* Get OS name
* @param {Boolean} [toLowerCase] return lower-cased value
* @return {String} name of the OS macOS, Windows, Linux, etc.
*/
getOSName(toLowerCase?: boolean): string;
/**
* Get OS version
* @return {String} full version with dots ('10.11.12', '5.6', etc)
*/
getOSVersion(): string;
/**
* Get parsed platform
* @returns {PlatformDetails}
*/
getPlatform(): PlatformDetails;
/**
* Get platform name
* @param {boolean} toLowerCase
*/
getPlatformType(toLowerCase?: boolean): string;
/**
* Get parsed engine
* @returns {EngineDetails}
*/
getEngine(): EngineDetails;
/**
* Get parsed engine's name
* @returns {String} Engine's name or an empty string
*/
getEngineName(): string;
/**
* Get parsed result
* @return {ParsedResult}
*/
getResult(): ParsedResult;
/**
* Get UserAgent string of current Parser instance
* @return {String} User-Agent String of the current <Parser> object
*/
getUA(): string;
/**
* Is anything? Check if the browser is called "anything",
* the OS called "anything" or the platform called "anything"
* @param {String} anything
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {Boolean}
*/
is(anything: any, includingAlias?: boolean): boolean;
/**
* Check if the browser name equals the passed string
* @param browserName The string to compare with the browser name
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {boolean}
*/
isBrowser(browserName: string, includingAlias?: boolean): boolean;
/**
* Check if the engine name equals the passed string
* @param engineName The string to compare with the engine name
* @returns {boolean}
*/
isEngine(engineName: string): boolean;
/**
* Check if the OS name equals the passed string
* @param OSName The string to compare with the OS name
* @returns {boolean}
*/
isOS(OSName: string): boolean;
/**
* Check if the platform name equals the passed string
* @param platformName The string to compare with the platform name
* @returns {boolean}
*/
isPlatform(platformName: string): boolean;
/**
* Parse full information about the browser
* @returns {Parser.Parser}
*/
parse(): Parser.Parser;
/**
* Get parsed browser object
* @returns {BrowserDetails}
*/
parseBrowser(): BrowserDetails;
/**
* Get parsed engine
* @returns {EngineDetails}
*/
parseEngine(): EngineDetails;
/**
* Parse OS and save it to this.parsedResult.os
* @returns {OSDetails}
*/
parseOS(): OSDetails;
/**
* Get parsed platform
* @returns {PlatformDetails}
*/
parsePlatform(): PlatformDetails;
/**
* Check if parsed browser matches certain conditions
*
* @param {checkTree} checkTree It's one or two layered object,
* which can include a platform or an OS on the first layer
* and should have browsers specs on the bottom-laying layer
*
* @returns {Boolean|undefined} Whether the browser satisfies the set conditions or not.
* Returns `undefined` when the browser is no described in the checkTree object.
*
* @example
* const browser = new Bowser(UA);
* if (browser.check({chrome: '>118.01.1322' }))
* // or with os
* if (browser.check({windows: { chrome: '>118.01.1322' } }))
* // or with platforms
* if (browser.check({desktop: { chrome: '>118.01.1322' } }))
*/
satisfies(checkTree: checkTree): boolean | undefined;
/**
* Check if the browser name equals the passed string
* @param {string} browserName The string to compare with the browser name
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {boolean}
*/
isBrowser(browserName: string, includingAlias?: boolean): boolean;
/**
* Check if the engine name equals the passed string
* @param {string} engineName The string to compare with the engine name
* @returns {boolean}
*/
isEngine(engineName: string): boolean;
/**
* Check if the platform type equals the passed string
* @param {string} platformType The string to compare with the platform type
* @returns {boolean}
*/
isPlatform(platformType: string): boolean;
/**
* Check if the OS name equals the passed string
* @param {string} osName The string to compare with the OS name
* @returns {boolean}
*/
isOS(osName: string): boolean;
/**
* Check if any of the given values satisfies `.is(anything)`
* @param {string[]} anythings
* @returns {boolean} true if at least one condition is satisfied, false otherwise.
*/
some(anythings: string[]): boolean | undefined;
/**
* Test a UA string for a regexp
* @param regex
* @returns {boolean} true if the regex matches the UA, false otherwise.
*/
test(regex: RegExp): boolean;
}
interface ParsedResult {
browser: BrowserDetails;
os: OSDetails;
platform: PlatformDetails;
engine: EngineDetails;
}
interface Details {
name?: string;
version?: string;
}
interface OSDetails extends Details {
versionName?: string;
}
interface PlatformDetails {
type?: string;
vendor?: string;
model?: string;
}
type BrowserDetails = Details;
type EngineDetails = Details;
interface checkTree {
[key: string]: any;
}
}
}

26396
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
{ {
"name": "bowser", "name": "bowser",
"version": "2.0.0-beta.1",
"description": "Lightweight browser detector", "description": "Lightweight browser detector",
"keywords": [ "keywords": [
"browser", "browser",
@ -11,77 +12,63 @@
"ender", "ender",
"sniff" "sniff"
], ],
"homepage": "https://github.com/bowser-js/bowser", "homepage": "https://github.com/lancedikson/bowser",
"author": "Dustin Diaz <dustin@dustindiaz.com> (http://dustindiaz.com)", "author": "Dustin Diaz <dustin@dustindiaz.com> (http://dustindiaz.com)",
"contributors": [ "contributors": [
{ {
"name": "Denis Demchenko", "name": "Denis Demchenko",
"url": "http://twitter.com/lancedikson" "url": "http://twitter.com/lancedikson"
},
{
"name": "Naor Peled",
"url": "https://github.com/naorpeled"
} }
], ],
"main": "es5.js", "main": "es5.js",
"browser": "es5.js",
"module": "src/bowser.js",
"types": "index.d.ts",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/bowser-js/bowser.git" "url": "git+https://github.com/lancedikson/bowser.git"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.11.6", "ava": "^0.25.0",
"@babel/core": "^7.8.0", "babel-cli": "^6.26.0",
"@babel/polyfill": "^7.8.3", "babel-core": "^6.26.3",
"@babel/preset-env": "^7.8.2", "babel-loader": "^7.1.5",
"@babel/register": "^7.8.3", "babel-plugin-add-module-exports": "^0.3.1",
"ava": "^3.0.0", "babel-plugin-istanbul": "^4.1.6",
"babel-eslint": "^10.0.3", "babel-polyfill": "^6.26.0",
"babel-loader": "^8.0.6", "babel-preset-env": "^1.7.0",
"babel-plugin-add-module-exports": "^1.0.2", "babel-register": "^6.26.0",
"babel-plugin-istanbul": "^6.0.0", "coveralls": "^3.0.2",
"compression-webpack-plugin": "^4.0.0", "docdash": "^0.4.0",
"coveralls": "^3.0.6", "eslint": "^4.19.1",
"docdash": "^1.1.1", "eslint-config-airbnb-base": "^12.1.0",
"eslint": "^6.5.1", "eslint-plugin-ava": "^4.5.1",
"eslint-config-airbnb-base": "^13.2.0", "eslint-plugin-import": "^2.13.0",
"eslint-plugin-ava": "^10.0.0", "jsdoc": "^3.5.5",
"eslint-plugin-import": "^2.18.2", "nyc": "^12.0.2",
"gh-pages": "^3.0.0", "sinon": "^2.4.1",
"jsdoc": "^3.6.3", "testem": "^1.18.5",
"nyc": "^15.0.0", "webpack": "^4.15.1",
"sinon": "^9.0.0", "webpack-cli": "^3.0.8",
"testem": "^3.0.0",
"webpack": "^4.41.0",
"webpack-bundle-analyzer": "^3.5.2",
"webpack-cli": "^3.3.9",
"yamljs": "^0.3.0" "yamljs": "^0.3.0"
}, },
"ava": { "ava": {
"require": [ "require": [
"@babel/register" "babel-register"
] ],
"babel": "inherit"
}, },
"bugs": { "bugs": {
"url": "https://github.com/bowser-js/bowser/issues" "url": "https://github.com/lancedikson/bowser/issues"
}, },
"directories": { "directories": {
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"build": "webpack --config webpack.config.js", "build": "webpack --config webpack.config.js",
"generate-and-deploy-docs": "npm run generate-docs && gh-pages --dist docs --dest docs", "prepublish": "npm run build",
"watch": "webpack --watch --config webpack.config.js", "lint": "eslint ./src --fix",
"prepublishOnly": "npm run build",
"lint:check": "eslint ./src",
"lint:fix": "eslint --fix ./src",
"testem": "testem", "testem": "testem",
"test": "nyc --reporter=html --reporter=text ava", "test": "eslint ./src & nyc --reporter=html --reporter=text ava",
"test:watch": "ava --watch",
"coverage": "nyc report --reporter=text-lcov | coveralls", "coverage": "nyc report --reporter=text-lcov | coveralls",
"generate-docs": "jsdoc -c jsdoc.json" "docs": "jsdoc -c jsdoc.json"
}, },
"license": "MIT" "license": "MIT"
} }

View File

@ -1,16 +1,10 @@
/*! /*!
* Bowser - a browser detector * Bowser - a browser detector
* https://github.com/bowser-js/bowser * https://github.com/lancedikson/bowser
* MIT License | (c) Dustin Diaz 2012-2015 * MIT License | (c) Dustin Diaz 2012-2015
* MIT License | (c) Denis Demchenko 2015-2019 * MIT License | (c) Denis Demchenko 2015-2017
*/ */
import Parser from './parser.js'; import Parser from './parser';
import {
BROWSER_MAP,
ENGINE_MAP,
OS_MAP,
PLATFORMS_MAP,
} from './constants.js';
/** /**
* Bowser class. * Bowser class.
@ -18,24 +12,19 @@ import {
* It's supposed to work with collections of {@link Parser} instances * It's supposed to work with collections of {@link Parser} instances
* rather then solve one-instance problems. * rather then solve one-instance problems.
* All the one-instance stuff is located in Parser class. * All the one-instance stuff is located in Parser class.
*
* @class
* @classdesc Bowser is a static object, that provides an API to the Parsers
* @hideconstructor
*/ */
class Bowser { class Bowser {
/** /**
* Creates a {@link Parser} instance * Creates a {@link module:parser:Parser} instance
* *
* @param {String} UA UserAgent string * @param {String} UA UserAgent string
* @param {Boolean} [skipParsing=false] Will make the Parser postpone parsing until you ask it * @param {Boolean} [skipParsing=false] same as skipParsing for {@link Parser}
* explicitly. Same as `skipParsing` for {@link Parser}.
* @returns {Parser} * @returns {Parser}
* @throws {Error} when UA is not a String * @throws {Error} when UA is not a String
* *
* @example * @example
* const parser = Bowser.getParser(window.navigator.userAgent); * const bowser = new Bowser(window.navigator.userAgent);
* const result = parser.getResult(); * bowser.getResult()
*/ */
static getParser(UA, skipParsing = false) { static getParser(UA, skipParsing = false) {
if (typeof UA !== 'string') { if (typeof UA !== 'string') {
@ -49,29 +38,10 @@ class Bowser {
* *
* @param UA * @param UA
* @return {ParsedResult} * @return {ParsedResult}
*
* @example
* const result = Bowser.parse(window.navigator.userAgent);
*/ */
static parse(UA) { static parse(UA) {
return (new Parser(UA)).getResult(); return (new Parser(UA)).getResult();
} }
static get BROWSER_MAP() {
return BROWSER_MAP;
}
static get ENGINE_MAP() {
return ENGINE_MAP;
}
static get OS_MAP() {
return OS_MAP;
}
static get PLATFORMS_MAP() {
return PLATFORMS_MAP;
}
} }
export default Bowser; export default Bowser;

View File

@ -1,169 +0,0 @@
// NOTE: this list must be up-to-date with browsers listed in
// test/acceptance/useragentstrings.yml
export const BROWSER_ALIASES_MAP = {
AmazonBot: 'amazonbot',
'Amazon Silk': 'amazon_silk',
'Android Browser': 'android',
BaiduSpider: 'baiduspider',
Bada: 'bada',
BingCrawler: 'bingcrawler',
BlackBerry: 'blackberry',
'ChatGPT-User': 'chatgpt_user',
Chrome: 'chrome',
ClaudeBot: 'claudebot',
Chromium: 'chromium',
Diffbot: 'diffbot',
DuckDuckBot: 'duckduckbot',
Electron: 'electron',
Epiphany: 'epiphany',
FacebookExternalHit: 'facebookexternalhit',
Firefox: 'firefox',
Focus: 'focus',
Generic: 'generic',
'Google Search': 'google_search',
Googlebot: 'googlebot',
GPTBot: 'gptbot',
'Internet Explorer': 'ie',
InternetArchiveCrawler: 'internetarchivecrawler',
'K-Meleon': 'k_meleon',
LibreWolf: 'librewolf',
Maxthon: 'maxthon',
'Meta-ExternalAds': 'meta_externalads',
'Meta-ExternalAgent': 'meta_externalagent',
'Meta-ExternalFetcher': 'meta_externalfetcher',
'Meta-WebIndexer': 'meta_webindexer',
'Microsoft Edge': 'edge',
'MZ Browser': 'mz',
'NAVER Whale Browser': 'naver',
'OAI-SearchBot': 'oai_searchbot',
Omgilibot: 'omgilibot',
Opera: 'opera',
'Opera Coast': 'opera_coast',
'Pale Moon': 'pale_moon',
PerplexityBot: 'perplexitybot',
'Perplexity-User': 'perplexity_user',
PhantomJS: 'phantomjs',
PingdomBot: 'pingdombot',
Puffin: 'puffin',
QQ: 'qq',
QQLite: 'qqlite',
QupZilla: 'qupzilla',
Roku: 'roku',
Safari: 'safari',
Sailfish: 'sailfish',
'Samsung Internet for Android': 'samsung_internet',
SeaMonkey: 'seamonkey',
Sleipnir: 'sleipnir',
'Sogou Browser': 'sogou',
Swing: 'swing',
Tizen: 'tizen',
'UC Browser': 'uc',
Vivaldi: 'vivaldi',
'WebOS Browser': 'webos',
WeChat: 'wechat',
YahooSlurp: 'yahooslurp',
'Yandex Browser': 'yandex',
YandexBot: 'yandexbot',
YouBot: 'youbot',
};
export const BROWSER_MAP = {
amazonbot: 'AmazonBot',
amazon_silk: 'Amazon Silk',
android: 'Android Browser',
baiduspider: 'BaiduSpider',
bada: 'Bada',
bingcrawler: 'BingCrawler',
blackberry: 'BlackBerry',
chatgpt_user: 'ChatGPT-User',
chrome: 'Chrome',
claudebot: 'ClaudeBot',
chromium: 'Chromium',
diffbot: 'Diffbot',
duckduckbot: 'DuckDuckBot',
edge: 'Microsoft Edge',
electron: 'Electron',
epiphany: 'Epiphany',
facebookexternalhit: 'FacebookExternalHit',
firefox: 'Firefox',
focus: 'Focus',
generic: 'Generic',
google_search: 'Google Search',
googlebot: 'Googlebot',
gptbot: 'GPTBot',
ie: 'Internet Explorer',
internetarchivecrawler: 'InternetArchiveCrawler',
k_meleon: 'K-Meleon',
librewolf: 'LibreWolf',
maxthon: 'Maxthon',
meta_externalads: 'Meta-ExternalAds',
meta_externalagent: 'Meta-ExternalAgent',
meta_externalfetcher: 'Meta-ExternalFetcher',
meta_webindexer: 'Meta-WebIndexer',
mz: 'MZ Browser',
naver: 'NAVER Whale Browser',
oai_searchbot: 'OAI-SearchBot',
omgilibot: 'Omgilibot',
opera: 'Opera',
opera_coast: 'Opera Coast',
pale_moon: 'Pale Moon',
perplexitybot: 'PerplexityBot',
perplexity_user: 'Perplexity-User',
phantomjs: 'PhantomJS',
pingdombot: 'PingdomBot',
puffin: 'Puffin',
qq: 'QQ Browser',
qqlite: 'QQ Browser Lite',
qupzilla: 'QupZilla',
roku: 'Roku',
safari: 'Safari',
sailfish: 'Sailfish',
samsung_internet: 'Samsung Internet for Android',
seamonkey: 'SeaMonkey',
sleipnir: 'Sleipnir',
sogou: 'Sogou Browser',
swing: 'Swing',
tizen: 'Tizen',
uc: 'UC Browser',
vivaldi: 'Vivaldi',
webos: 'WebOS Browser',
wechat: 'WeChat',
yahooslurp: 'YahooSlurp',
yandex: 'Yandex Browser',
yandexbot: 'YandexBot',
youbot: 'YouBot',
};
export const PLATFORMS_MAP = {
bot: 'bot',
desktop: 'desktop',
mobile: 'mobile',
tablet: 'tablet',
tv: 'tv',
};
export const OS_MAP = {
Android: 'Android',
Bada: 'Bada',
BlackBerry: 'BlackBerry',
ChromeOS: 'Chrome OS',
HarmonyOS: 'HarmonyOS',
iOS: 'iOS',
Linux: 'Linux',
MacOS: 'macOS',
PlayStation4: 'PlayStation 4',
Roku: 'Roku',
Tizen: 'Tizen',
WebOS: 'WebOS',
Windows: 'Windows',
WindowsPhone: 'Windows Phone',
};
export const ENGINE_MAP = {
Blink: 'Blink',
EdgeHTML: 'EdgeHTML',
Gecko: 'Gecko',
Presto: 'Presto',
Trident: 'Trident',
WebKit: 'WebKit',
};

View File

@ -23,374 +23,14 @@
* return true/false to get the Parser know if this browser descriptor matches the UA or not. * return true/false to get the Parser know if this browser descriptor matches the UA or not.
*/ */
import Utils from './utils.js'; import {
getFirstMatch,
getSecondMatch,
} from './utils';
const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i; const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i;
const browsersList = [ const browsersList = [
/* GPTBot */
{
test: [/gptbot/i],
describe(ua) {
const browser = {
name: 'GPTBot',
};
const version = Utils.getFirstMatch(/gptbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* ChatGPT-User */
{
test: [/chatgpt-user/i],
describe(ua) {
const browser = {
name: 'ChatGPT-User',
};
const version = Utils.getFirstMatch(/chatgpt-user\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* OAI-SearchBot */
{
test: [/oai-searchbot/i],
describe(ua) {
const browser = {
name: 'OAI-SearchBot',
};
const version = Utils.getFirstMatch(/oai-searchbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* ClaudeBot */
{
test: [/claudebot/i, /claude-web/i, /claude-user/i, /claude-searchbot/i],
describe(ua) {
const browser = {
name: 'ClaudeBot',
};
const version = Utils.getFirstMatch(/(?:claudebot|claude-web|claude-user|claude-searchbot)\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Omgilibot */
{
test: [/omgilibot/i, /webzio-extended/i],
describe(ua) {
const browser = {
name: 'Omgilibot',
};
const version = Utils.getFirstMatch(/(?:omgilibot|webzio-extended)\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Diffbot */
{
test: [/diffbot/i],
describe(ua) {
const browser = {
name: 'Diffbot',
};
const version = Utils.getFirstMatch(/diffbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* PerplexityBot */
{
test: [/perplexitybot/i],
describe(ua) {
const browser = {
name: 'PerplexityBot',
};
const version = Utils.getFirstMatch(/perplexitybot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Perplexity-User */
{
test: [/perplexity-user/i],
describe(ua) {
const browser = {
name: 'Perplexity-User',
};
const version = Utils.getFirstMatch(/perplexity-user\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* YouBot */
{
test: [/youbot/i],
describe(ua) {
const browser = {
name: 'YouBot',
};
const version = Utils.getFirstMatch(/youbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Meta-WebIndexer */
{
test: [/meta-webindexer/i],
describe(ua) {
const browser = {
name: 'Meta-WebIndexer',
};
const version = Utils.getFirstMatch(/meta-webindexer\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Meta-ExternalAds */
{
test: [/meta-externalads/i],
describe(ua) {
const browser = {
name: 'Meta-ExternalAds',
};
const version = Utils.getFirstMatch(/meta-externalads\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Meta-ExternalAgent */
{
test: [/meta-externalagent/i],
describe(ua) {
const browser = {
name: 'Meta-ExternalAgent',
};
const version = Utils.getFirstMatch(/meta-externalagent\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Meta-ExternalFetcher */
{
test: [/meta-externalfetcher/i],
describe(ua) {
const browser = {
name: 'Meta-ExternalFetcher',
};
const version = Utils.getFirstMatch(/meta-externalfetcher\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Googlebot */
{
test: [/googlebot/i],
describe(ua) {
const browser = {
name: 'Googlebot',
};
const version = Utils.getFirstMatch(/googlebot\/(\d+(\.\d+))/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* AmazonBot */
{
test: [/amazonbot/i],
describe(ua) {
const browser = {
name: 'AmazonBot',
};
const version = Utils.getFirstMatch(/amazonbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* BingCrawler */
{
test: [/bingbot/i],
describe(ua) {
const browser = {
name: 'BingCrawler',
};
const version = Utils.getFirstMatch(/bingbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* BaiduSpider */
{
test: [/baiduspider/i],
describe(ua) {
const browser = {
name: 'BaiduSpider',
};
const version = Utils.getFirstMatch(/baiduspider\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* DuckDuckBot */
{
test: [/duckduckbot/i],
describe(ua) {
const browser = {
name: 'DuckDuckBot',
};
const version = Utils.getFirstMatch(/duckduckbot\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* InternetArchiveCrawler */
{
test: [/ia_archiver/i],
describe(ua) {
const browser = {
name: 'InternetArchiveCrawler',
};
const version = Utils.getFirstMatch(/ia_archiver\/(\d+(\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* FacebookExternalHit */
{
test: [/facebookexternalhit/i, /facebookcatalog/i],
describe() {
return {
name: 'FacebookExternalHit',
};
},
},
/* YahooSlurp */
{
test: [/yahoo!?[\s/]*slurp/i],
describe() {
return {
name: 'YahooSlurp',
};
},
},
/* YandexBot */
{
test: [/yandexbot/i, /yandexmobilebot/i],
describe() {
return {
name: 'YandexBot',
};
},
},
/* PingdomBot */
{
test: [/pingdom/i],
describe() {
return {
name: 'PingdomBot',
};
},
},
/* Opera < 13.0 */ /* Opera < 13.0 */
{ {
test: [/opera/i], test: [/opera/i],
@ -398,7 +38,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Opera', name: 'Opera',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -410,12 +50,12 @@ const browsersList = [
/* Opera > 13.0 */ /* Opera > 13.0 */
{ {
test: [/opr\/|opios/i], test: [/opr|opios/i],
describe(ua) { describe(ua) {
const browser = { const browser = {
name: 'Opera', name: 'Opera',
}; };
const version = Utils.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(/(?:opr|opios)[\s/](\S+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -430,7 +70,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Samsung Internet for Android', name: 'Samsung Internet for Android',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -445,22 +85,7 @@ const browsersList = [
const browser = { const browser = {
name: 'NAVER Whale Browser', name: 'NAVER Whale Browser',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/PaleMoon/i],
describe(ua) {
const browser = {
name: 'Pale Moon',
};
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:PaleMoon)[\s/](\d+(?:\.\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -475,7 +100,7 @@ const browsersList = [
const browser = { const browser = {
name: 'MZ Browser', name: 'MZ Browser',
}; };
const version = Utils.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -490,22 +115,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Focus', name: 'Focus',
}; };
const version = Utils.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/swing/i],
describe(ua) {
const browser = {
name: 'Swing',
};
const version = Utils.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -520,22 +130,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Opera Coast', name: 'Opera Coast',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/opt\/\d+(?:.?_?\d+)+/i],
describe(ua) {
const browser = {
name: 'Opera Touch',
};
const version = Utils.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -550,7 +145,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Yandex Browser', name: 'Yandex Browser',
}; };
const version = Utils.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -565,7 +160,7 @@ const browsersList = [
const browser = { const browser = {
name: 'UC Browser', name: 'UC Browser',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -575,12 +170,12 @@ const browsersList = [
}, },
}, },
{ {
test: [/Maxthon|mxios/i], test: [/mxios/i],
describe(ua) { describe(ua) {
const browser = { const browser = {
name: 'Maxthon', name: 'Maxthon',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:mxios)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -595,7 +190,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Epiphany', name: 'Epiphany',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -610,7 +205,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Puffin', name: 'Puffin',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -625,7 +220,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Sleipnir', name: 'Sleipnir',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -640,37 +235,7 @@ const browsersList = [
const browser = { const browser = {
name: 'K-Meleon', name: 'K-Meleon',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/micromessenger/i],
describe(ua) {
const browser = {
name: 'WeChat',
};
const version = Utils.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/qqbrowser/i],
describe(ua) {
const browser = {
name: (/qqbrowserlite/i).test(ua) ? 'QQ Browser Lite' : 'QQ Browser',
};
const version = Utils.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -685,23 +250,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Internet Explorer', name: 'Internet Explorer',
}; };
const version = Utils.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/\sedg\//i],
describe(ua) {
const browser = {
name: 'Microsoft Edge',
};
const version = Utils.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -717,7 +266,7 @@ const browsersList = [
name: 'Microsoft Edge', name: 'Microsoft Edge',
}; };
const version = Utils.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i, ua); const version = getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -732,7 +281,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Vivaldi', name: 'Vivaldi',
}; };
const version = Utils.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -747,7 +296,7 @@ const browsersList = [
const browser = { const browser = {
name: 'SeaMonkey', name: 'SeaMonkey',
}; };
const version = Utils.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -763,7 +312,7 @@ const browsersList = [
name: 'Sailfish', name: 'Sailfish',
}; };
const version = Utils.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i, ua); const version = getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -778,7 +327,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Amazon Silk', name: 'Amazon Silk',
}; };
const version = Utils.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -793,7 +342,7 @@ const browsersList = [
const browser = { const browser = {
name: 'PhantomJS', name: 'PhantomJS',
}; };
const version = Utils.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -808,7 +357,7 @@ const browsersList = [
const browser = { const browser = {
name: 'SlimerJS', name: 'SlimerJS',
}; };
const version = Utils.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -823,7 +372,7 @@ const browsersList = [
const browser = { const browser = {
name: 'BlackBerry', name: 'BlackBerry',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -838,7 +387,7 @@ const browsersList = [
const browser = { const browser = {
name: 'WebOS Browser', name: 'WebOS Browser',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(commonVersionIdentifier, ua) || getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -853,7 +402,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Bada', name: 'Bada',
}; };
const version = Utils.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -868,7 +417,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Tizen', name: 'Tizen',
}; };
const version = Utils.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -883,22 +432,7 @@ const browsersList = [
const browser = { const browser = {
name: 'QupZilla', name: 'QupZilla',
}; };
const version = Utils.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/librewolf/i],
describe(ua) {
const browser = {
name: 'LibreWolf',
};
const version = Utils.getFirstMatch(/(?:librewolf)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -913,55 +447,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Firefox', name: 'Firefox',
}; };
const version = Utils.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) {
browser.version = version;
}
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: [/sogoumobilebrowser/i, /metasr/i, /se 2\.[x]/i],
describe(ua) {
const browser = {
name: 'Sogou Browser',
};
const sogouMobileVersion = Utils.getFirstMatch(/(?:sogoumobilebrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
const chromiumVersion = Utils.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua);
const seVersion = Utils.getFirstMatch(/se ([\d.]+)x/i, ua);
const version = sogouMobileVersion || chromiumVersion || seVersion;
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/MiuiBrowser/i],
describe(ua) {
const browser = {
name: 'Miui',
};
const version = Utils.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -976,7 +462,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Chromium', name: 'Chromium',
}; };
const version = Utils.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -991,22 +477,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Chrome', name: 'Chrome',
}; };
const version = Utils.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
{
test: [/GSA/i],
describe(ua) {
const browser = {
name: 'Google Search',
};
const version = Utils.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -1027,24 +498,7 @@ const browsersList = [
const browser = { const browser = {
name: 'Android Browser', name: 'Android Browser',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* PlayStation 4 */
{
test: [/playstation 4/i],
describe(ua) {
const browser = {
name: 'PlayStation 4',
};
const version = Utils.getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -1061,7 +515,24 @@ const browsersList = [
const browser = { const browser = {
name: 'Safari', name: 'Safari',
}; };
const version = Utils.getFirstMatch(commonVersionIdentifier, ua); const version = getFirstMatch(commonVersionIdentifier, ua);
if (version) {
browser.version = version;
}
return browser;
},
},
/* Googlebot */
{
test: [/googlebot/i],
describe(ua) {
const browser = {
name: 'Googlebot',
};
const version = getFirstMatch(/googlebot\/(\d+(\.\d+))/i, ua) || getFirstMatch(commonVersionIdentifier, ua);
if (version) { if (version) {
browser.version = version; browser.version = version;
@ -1075,17 +546,9 @@ const browsersList = [
{ {
test: [/.*/i], test: [/.*/i],
describe(ua) { describe(ua) {
/* Here we try to make sure that there are explicit details about the device
* in order to decide what regexp exactly we want to apply
* (as there is a specific decision based on that conclusion)
*/
const regexpWithoutDeviceSpec = /^(.*)\/(.*) /;
const regexpWithDeviceSpec = /^(.*)\/(.*)[ \t]\((.*)/;
const hasDeviceSpec = ua.search('\\(') !== -1;
const regexp = hasDeviceSpec ? regexpWithDeviceSpec : regexpWithoutDeviceSpec;
return { return {
name: Utils.getFirstMatch(regexp, ua), name: getFirstMatch(/^(.*)\/(.*) /, ua),
version: Utils.getSecondMatch(regexp, ua), version: getSecondMatch(/^(.*)\/(.*) /, ua),
}; };
}, },
}, },

View File

@ -1,5 +1,4 @@
import Utils from './utils.js'; import { getFirstMatch } from './utils';
import { ENGINE_MAP } from './constants.js';
/* /*
* More specific goes first * More specific goes first
@ -11,20 +10,9 @@ export default [
return parser.getBrowserName(true) === 'microsoft edge'; return parser.getBrowserName(true) === 'microsoft edge';
}, },
describe(ua) { describe(ua) {
const isBlinkBased = /\sedg\//i.test(ua); const version = getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i, ua);
// return blink if it's blink-based one
if (isBlinkBased) {
return {
name: ENGINE_MAP.Blink,
};
}
// otherwise match the version and return EdgeHTML
const version = Utils.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i, ua);
return { return {
name: ENGINE_MAP.EdgeHTML, name: 'EdgeHTML',
version, version,
}; };
}, },
@ -35,10 +23,10 @@ export default [
test: [/trident/i], test: [/trident/i],
describe(ua) { describe(ua) {
const engine = { const engine = {
name: ENGINE_MAP.Trident, name: 'Trident',
}; };
const version = Utils.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
engine.version = version; engine.version = version;
@ -55,10 +43,10 @@ export default [
}, },
describe(ua) { describe(ua) {
const engine = { const engine = {
name: ENGINE_MAP.Presto, name: 'Presto',
}; };
const version = Utils.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
engine.version = version; engine.version = version;
@ -77,10 +65,10 @@ export default [
}, },
describe(ua) { describe(ua) {
const engine = { const engine = {
name: ENGINE_MAP.Gecko, name: 'Gecko',
}; };
const version = Utils.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
engine.version = version; engine.version = version;
@ -95,7 +83,7 @@ export default [
test: [/(apple)?webkit\/537\.36/i], test: [/(apple)?webkit\/537\.36/i],
describe() { describe() {
return { return {
name: ENGINE_MAP.Blink, name: 'Blink',
}; };
}, },
}, },
@ -105,10 +93,10 @@ export default [
test: [/(apple)?webkit/i], test: [/(apple)?webkit/i],
describe(ua) { describe(ua) {
const engine = { const engine = {
name: ENGINE_MAP.WebKit, name: 'WebKit',
}; };
const version = Utils.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i, ua); const version = getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i, ua);
if (version) { if (version) {
engine.version = version; engine.version = version;

View File

@ -1,26 +1,16 @@
import Utils from './utils.js'; import {
import { OS_MAP } from './constants.js'; getFirstMatch,
getWindowsVersionName,
} from './utils';
export default [ export default [
/* Roku */
{
test: [/Roku\/DVP/],
describe(ua) {
const version = Utils.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i, ua);
return {
name: OS_MAP.Roku,
version,
};
},
},
/* Windows Phone */ /* Windows Phone */
{ {
test: [/windows phone/i], test: [/windows phone/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i, ua); const version = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i, ua);
return { return {
name: OS_MAP.WindowsPhone, name: 'Windows Phone',
version, version,
}; };
}, },
@ -28,49 +18,28 @@ 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 = getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, ua);
const versionName = Utils.getWindowsVersionName(version); const versionName = getWindowsVersionName(version);
return { return {
name: OS_MAP.Windows, name: 'Windows',
version, version,
versionName, versionName,
}; };
}, },
}, },
/* Firefox on iPad */
{
test: [/Macintosh(.*?) FxiOS(.*?)\//],
describe(ua) {
const result = {
name: OS_MAP.iOS,
};
const version = Utils.getSecondMatch(/(Version\/)(\d[\d.]+)/, ua);
if (version) {
result.version = version;
}
return result;
},
},
/* macOS */ /* macOS */
{ {
test: [/macintosh/i], test: [/macintosh/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i, ua).replace(/[_\s]/g, '.'); const version = getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i, ua).replace(/[_\s]/g, '.');
const versionName = Utils.getMacOSVersionName(version); return {
name: 'macOS',
const os = {
name: OS_MAP.MacOS,
version, version,
}; };
if (versionName) {
os.versionName = versionName;
}
return os;
}, },
}, },
@ -78,22 +47,10 @@ export default [
{ {
test: [/(ipod|iphone|ipad)/i], test: [/(ipod|iphone|ipad)/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i, ua).replace(/[_\s]/g, '.'); const version = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i, ua).replace(/[_\s]/g, '.');
return { return {
name: OS_MAP.iOS, name: 'iOS',
version,
};
},
},
/* HarmonyOS */
{
test: [/OpenHarmony/i],
describe(ua) {
const version = Utils.getFirstMatch(/OpenHarmony\s+(\d+(\.\d+)*)/i, ua);
return {
name: OS_MAP.HarmonyOS,
version, version,
}; };
}, },
@ -107,16 +64,11 @@ export default [
return notLikeAndroid && butAndroid; return notLikeAndroid && butAndroid;
}, },
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i, ua); const version = getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i, ua);
const versionName = Utils.getAndroidVersionName(version); return {
const os = { name: 'Android',
name: OS_MAP.Android,
version, version,
}; };
if (versionName) {
os.versionName = versionName;
}
return os;
}, },
}, },
@ -124,9 +76,9 @@ export default [
{ {
test: [/(web|hpw)[o0]s/i], test: [/(web|hpw)[o0]s/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i, ua); const version = getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i, ua);
const os = { const os = {
name: OS_MAP.WebOS, name: 'WebOS',
}; };
if (version && version.length) { if (version && version.length) {
@ -140,12 +92,12 @@ export default [
{ {
test: [/blackberry|\bbb\d+/i, /rim\stablet/i], test: [/blackberry|\bbb\d+/i, /rim\stablet/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i, ua) const version = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i, ua)
|| Utils.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i, ua) || getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i, ua)
|| Utils.getFirstMatch(/\bbb(\d+)/i, ua); || getFirstMatch(/\bbb(\d+)/i, ua);
return { return {
name: OS_MAP.BlackBerry, name: 'BlackBerry',
version, version,
}; };
}, },
@ -155,10 +107,10 @@ export default [
{ {
test: [/bada/i], test: [/bada/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/bada\/(\d+(\.\d+)*)/i, ua); const version = getFirstMatch(/bada\/(\d+(\.\d+)*)/i, ua);
return { return {
name: OS_MAP.Bada, name: 'Bada',
version, version,
}; };
}, },
@ -168,10 +120,10 @@ export default [
{ {
test: [/tizen/i], test: [/tizen/i],
describe(ua) { describe(ua) {
const version = Utils.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i, ua); const version = getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i, ua);
return { return {
name: OS_MAP.Tizen, name: 'Tizen',
version, version,
}; };
}, },
@ -182,29 +134,7 @@ export default [
test: [/linux/i], test: [/linux/i],
describe() { describe() {
return { return {
name: OS_MAP.Linux, name: 'Linux',
};
},
},
/* Chrome OS */
{
test: [/CrOS/],
describe() {
return {
name: OS_MAP.ChromeOS,
};
},
},
/* Playstation 4 */
{
test: [/PlayStation 4/],
describe(ua) {
const version = Utils.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i, ua);
return {
name: OS_MAP.PlayStation4,
version,
}; };
}, },
}, },

View File

@ -1,5 +1,10 @@
import Utils from './utils.js'; import { getFirstMatch } from './utils';
import { PLATFORMS_MAP } from './constants.js';
const TYPES_LABELS = {
tablet: 'tablet',
mobile: 'mobile',
desktop: 'desktop',
};
/* /*
* Tablets go first since usually they have more specific * Tablets go first since usually they have more specific
@ -7,281 +12,12 @@ import { PLATFORMS_MAP } from './constants.js';
*/ */
export default [ export default [
/* Googlebot */
{
test: [/googlebot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Google',
};
},
},
/* AmazonBot */
{
test: [/amazonbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Amazon',
};
},
},
/* GPTBot */
{
test: [/gptbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'OpenAI',
};
},
},
/* ChatGPT-User */
{
test: [/chatgpt-user/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'OpenAI',
};
},
},
/* OAI-SearchBot */
{
test: [/oai-searchbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'OpenAI',
};
},
},
/* Baidu */
{
test: [/baiduspider/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Baidu',
};
},
},
/* Bingbot */
{
test: [/bingbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Bing',
};
},
},
/* DuckDuckBot */
{
test: [/duckduckbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'DuckDuckGo',
};
},
},
/* ClaudeBot */
{
test: [/claudebot/i, /claude-web/i, /claude-user/i, /claude-searchbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Anthropic',
};
},
},
/* Omgilibot */
{
test: [/omgilibot/i, /webzio-extended/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Webz.io',
};
},
},
/* Diffbot */
{
test: [/diffbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Diffbot',
};
},
},
/* PerplexityBot */
{
test: [/perplexitybot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Perplexity AI',
};
},
},
/* Perplexity-User */
{
test: [/perplexity-user/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Perplexity AI',
};
},
},
/* YouBot */
{
test: [/youbot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'You.com',
};
},
},
/* Internet Archive Crawler */
{
test: [/ia_archiver/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Internet Archive',
};
},
},
/* Meta-WebIndexer */
{
test: [/meta-webindexer/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Meta',
};
},
},
/* Meta-ExternalAds */
{
test: [/meta-externalads/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Meta',
};
},
},
/* Meta-ExternalAgent */
{
test: [/meta-externalagent/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Meta',
};
},
},
/* Meta-ExternalFetcher */
{
test: [/meta-externalfetcher/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Meta',
};
},
},
/* Meta Web Crawler */
{
test: [/facebookexternalhit/i, /facebookcatalog/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Meta',
};
},
},
/* Yahoo! Slurp */
{
test: [/yahoo/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Yahoo',
};
},
},
/* Yandex */
{
test: [/yandexbot/i, /yandexmobilebot/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Yandex',
};
},
},
/* Pingdom */
{
test: [/pingdom/i],
describe() {
return {
type: PLATFORMS_MAP.bot,
vendor: 'Pingdom',
};
},
},
/* Huawei */
{
test: [/huawei/i],
describe(ua) {
const model = Utils.getFirstMatch(/(can-l01)/i, ua) && 'Nova';
const platform = {
type: PLATFORMS_MAP.mobile,
vendor: 'Huawei',
};
if (model) {
platform.model = model;
}
return platform;
},
},
/* Nexus Tablet */ /* Nexus Tablet */
{ {
test: [/nexus\s*(?:7|8|9|10).*/i], test: [/nexus\s*(?:7|8|9|10).*/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.tablet, type: TYPES_LABELS.tablet,
vendor: 'Nexus', vendor: 'Nexus',
}; };
}, },
@ -292,19 +28,7 @@ export default [
test: [/ipad/i], test: [/ipad/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.tablet, type: TYPES_LABELS.tablet,
vendor: 'Apple',
model: 'iPad',
};
},
},
/* Firefox on iPad */
{
test: [/Macintosh(.*?) FxiOS(.*?)\//],
describe() {
return {
type: PLATFORMS_MAP.tablet,
vendor: 'Apple', vendor: 'Apple',
model: 'iPad', model: 'iPad',
}; };
@ -316,7 +40,7 @@ export default [
test: [/kftt build/i], test: [/kftt build/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.tablet, type: TYPES_LABELS.tablet,
vendor: 'Amazon', vendor: 'Amazon',
model: 'Kindle Fire HD 7', model: 'Kindle Fire HD 7',
}; };
@ -328,7 +52,7 @@ export default [
test: [/silk/i], test: [/silk/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.tablet, type: TYPES_LABELS.tablet,
vendor: 'Amazon', vendor: 'Amazon',
}; };
}, },
@ -336,10 +60,10 @@ export default [
/* Tablet */ /* Tablet */
{ {
test: [/tablet(?! pc)/i], test: [/tablet/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.tablet, type: TYPES_LABELS.tablet,
}; };
}, },
}, },
@ -352,9 +76,9 @@ export default [
return iDevice && !likeIDevice; return iDevice && !likeIDevice;
}, },
describe(ua) { describe(ua) {
const model = Utils.getFirstMatch(/(ipod|iphone)/i, ua); const model = getFirstMatch(/(ipod|iphone)/i, ua);
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
vendor: 'Apple', vendor: 'Apple',
model, model,
}; };
@ -366,34 +90,18 @@ export default [
test: [/nexus\s*[0-6].*/i, /galaxy nexus/i], test: [/nexus\s*[0-6].*/i, /galaxy nexus/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
vendor: 'Nexus', vendor: 'Nexus',
}; };
}, },
}, },
/* Nokia */
{
test: [/Nokia/i],
describe(ua) {
const model = Utils.getFirstMatch(/Nokia\s+([0-9]+(\.[0-9]+)?)/i, ua);
const platform = {
type: PLATFORMS_MAP.mobile,
vendor: 'Nokia',
};
if (model) {
platform.model = model;
}
return platform;
},
},
/* Mobile */ /* Mobile */
{ {
test: [/[^-]mobi/i], test: [/[^-]mobi/i],
describe() { describe() {
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
}; };
}, },
}, },
@ -405,7 +113,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
vendor: 'BlackBerry', vendor: 'BlackBerry',
}; };
}, },
@ -418,7 +126,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
}; };
}, },
}, },
@ -430,7 +138,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
vendor: 'Microsoft', vendor: 'Microsoft',
}; };
}, },
@ -444,7 +152,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.tablet, type: TYPES_LABELS.tablet,
}; };
}, },
}, },
@ -456,7 +164,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.mobile, type: TYPES_LABELS.mobile,
}; };
}, },
}, },
@ -468,7 +176,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.desktop, type: TYPES_LABELS.desktop,
vendor: 'Apple', vendor: 'Apple',
}; };
}, },
@ -481,7 +189,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.desktop, type: TYPES_LABELS.desktop,
}; };
}, },
}, },
@ -493,31 +201,7 @@ export default [
}, },
describe() { describe() {
return { return {
type: PLATFORMS_MAP.desktop, type: TYPES_LABELS.desktop,
};
},
},
/* PlayStation 4 */
{
test(parser) {
return parser.getOSName(true) === 'playstation 4';
},
describe() {
return {
type: PLATFORMS_MAP.tv,
};
},
},
/* Roku */
{
test(parser) {
return parser.getOSName(true) === 'roku';
},
describe() {
return {
type: PLATFORMS_MAP.tv,
}; };
}, },
}, },

View File

@ -1,8 +1,8 @@
import browserParsersList from './parser-browsers.js'; import browserParsersList from './parser-browsers';
import osParsersList from './parser-os.js'; import osParsersList from './parser-os';
import platformParsersList from './parser-platforms.js'; import platformParsersList from './parser-platforms';
import enginesParsersList from './parser-engines.js'; import enginesParsersList from './parser-engines';
import Utils from './utils.js'; import { compareVersions } from './utils';
/** /**
* The main class that arranges the whole parsing process. * The main class that arranges the whole parsing process.
@ -82,12 +82,12 @@ class Parser {
parseBrowser() { parseBrowser() {
this.parsedResult.browser = {}; this.parsedResult.browser = {};
const browserDescriptor = Utils.find(browserParsersList, (_browser) => { const browserDescriptor = browserParsersList.find((_browser) => {
if (typeof _browser.test === 'function') { if (typeof _browser.test === 'function') {
return _browser.test(this); return _browser.test(this);
} }
if (Array.isArray(_browser.test)) { if (_browser.test instanceof Array) {
return _browser.test.some(condition => this.test(condition)); return _browser.test.some(condition => this.test(condition));
} }
@ -165,12 +165,12 @@ class Parser {
parseOS() { parseOS() {
this.parsedResult.os = {}; this.parsedResult.os = {};
const os = Utils.find(osParsersList, (_os) => { const os = osParsersList.find((_os) => {
if (typeof _os.test === 'function') { if (typeof _os.test === 'function') {
return _os.test(this); return _os.test(this);
} }
if (Array.isArray(_os.test)) { if (_os.test instanceof Array) {
return _os.test.some(condition => this.test(condition)); return _os.test.some(condition => this.test(condition));
} }
@ -241,12 +241,12 @@ class Parser {
parsePlatform() { parsePlatform() {
this.parsedResult.platform = {}; this.parsedResult.platform = {};
const platform = Utils.find(platformParsersList, (_platform) => { const platform = platformParsersList.find((_platform) => {
if (typeof _platform.test === 'function') { if (typeof _platform.test === 'function') {
return _platform.test(this); return _platform.test(this);
} }
if (Array.isArray(_platform.test)) { if (_platform.test instanceof Array) {
return _platform.test.some(condition => this.test(condition)); return _platform.test.some(condition => this.test(condition));
} }
@ -272,19 +272,6 @@ class Parser {
return this.parseEngine(); return this.parseEngine();
} }
/**
* Get engines's name
* @return {String} Engines's name or an empty string
*
* @public
*/
getEngineName(toLowerCase) {
if (toLowerCase) {
return String(this.getEngine().name).toLowerCase() || '';
}
return this.getEngine().name || '';
}
/** /**
* Get parsed platform * Get parsed platform
* @return {{}} * @return {{}}
@ -292,12 +279,12 @@ class Parser {
parseEngine() { parseEngine() {
this.parsedResult.engine = {}; this.parsedResult.engine = {};
const engine = Utils.find(enginesParsersList, (_engine) => { const engine = enginesParsersList.find((_engine) => {
if (typeof _engine.test === 'function') { if (typeof _engine.test === 'function') {
return _engine.test(this); return _engine.test(this);
} }
if (Array.isArray(_engine.test)) { if (_engine.test instanceof Array) {
return _engine.test.some(condition => this.test(condition)); return _engine.test.some(condition => this.test(condition));
} }
@ -313,7 +300,6 @@ class Parser {
/** /**
* Parse full information about the browser * Parse full information about the browser
* @returns {Parser}
*/ */
parse() { parse() {
this.parseBrowser(); this.parseBrowser();
@ -329,7 +315,8 @@ class Parser {
* @return {ParsedResult} * @return {ParsedResult}
*/ */
getResult() { getResult() {
return Utils.assign({}, this.parsedResult); /* TODO: Make this function pure, return a new object instead of the reference */
return this.parsedResult;
} }
/** /**
@ -343,12 +330,12 @@ class Parser {
* Returns `undefined` when the browser is no described in the checkTree object. * Returns `undefined` when the browser is no described in the checkTree object.
* *
* @example * @example
* const browser = Bowser.getParser(window.navigator.userAgent); * const browser = new Bowser(UA);
* if (browser.satisfies({chrome: '>118.01.1322' })) * if (browser.check({chrome: '>118.01.1322' }))
* // or with os * // or with os
* if (browser.satisfies({windows: { chrome: '>118.01.1322' } })) * if (browser.check({windows: { chrome: '>118.01.1322' } }))
* // or with platforms * // or with platforms
* if (browser.satisfies({desktop: { chrome: '>118.01.1322' } })) * if (browser.check({desktop: { chrome: '>118.01.1322' } }))
*/ */
satisfies(checkTree) { satisfies(checkTree) {
const platformsAndOSes = {}; const platformsAndOSes = {};
@ -371,7 +358,7 @@ class Parser {
if (platformsAndOSCounter > 0) { if (platformsAndOSCounter > 0) {
const platformsAndOSNames = Object.keys(platformsAndOSes); const platformsAndOSNames = Object.keys(platformsAndOSes);
const OSMatchingDefinition = Utils.find(platformsAndOSNames, name => (this.isOS(name))); const OSMatchingDefinition = platformsAndOSNames.find(name => (this.isOS(name)));
if (OSMatchingDefinition) { if (OSMatchingDefinition) {
const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]); const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]);
@ -381,10 +368,7 @@ class Parser {
} }
} }
const platformMatchingDefinition = Utils.find( const platformMatchingDefinition = platformsAndOSNames.find(name => (this.isPlatform(name)));
platformsAndOSNames,
name => (this.isPlatform(name)),
);
if (platformMatchingDefinition) { if (platformMatchingDefinition) {
const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]); const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]);
@ -396,7 +380,7 @@ class Parser {
if (browsersCounter > 0) { if (browsersCounter > 0) {
const browserNames = Object.keys(browsers); const browserNames = Object.keys(browsers);
const matchingDefinition = Utils.find(browserNames, name => (this.isBrowser(name, true))); const matchingDefinition = browserNames.find(name => (this.isBrowser(name)));
if (matchingDefinition !== void 0) { if (matchingDefinition !== void 0) {
return this.compareVersion(browsers[matchingDefinition]); return this.compareVersion(browsers[matchingDefinition]);
@ -406,47 +390,21 @@ class Parser {
return undefined; return undefined;
} }
/** isBrowser(browserName) {
* Check if the browser name equals the passed string return this.getBrowserName(true) === String(browserName).toLowerCase();
* @param {string} browserName The string to compare with the browser name
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {boolean}
*/
isBrowser(browserName, includingAlias = false) {
const defaultBrowserName = this.getBrowserName().toLowerCase();
let browserNameLower = browserName.toLowerCase();
const alias = Utils.getBrowserTypeByAlias(browserNameLower);
if (includingAlias && alias) {
browserNameLower = alias.toLowerCase();
}
return browserNameLower === defaultBrowserName;
} }
compareVersion(version) { compareVersion(version) {
let expectedResults = [0]; let expectedResult = 0;
let comparableVersion = version; let comparableVersion = version;
let isLoose = false; let isLoose = false;
const currentBrowserVersion = this.getBrowserVersion(); if (version[0] === '>') {
expectedResult = 1;
if (typeof currentBrowserVersion !== 'string') { comparableVersion = version.substr(1);
return void 0; } else if (version[0] === '<') {
} expectedResult = -1;
if (version[0] === '>' || version[0] === '<') {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
if (version[1] === '=') {
isLoose = true;
comparableVersion = version.substr(2);
} else {
expectedResults = [];
}
if (version[0] === '>') {
expectedResults.push(1);
} else {
expectedResults.push(-1);
}
} else if (version[0] === '=') { } else if (version[0] === '=') {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} else if (version[0] === '~') { } else if (version[0] === '~') {
@ -454,52 +412,29 @@ class Parser {
comparableVersion = version.substr(1); comparableVersion = version.substr(1);
} }
return expectedResults.indexOf( return compareVersions(this.getBrowserVersion(), comparableVersion, isLoose) === expectedResult;
Utils.compareVersions(currentBrowserVersion, comparableVersion, isLoose),
) > -1;
} }
/**
* Check if the OS name equals the passed string
* @param {string} osName The string to compare with the OS name
* @returns {boolean}
*/
isOS(osName) { isOS(osName) {
return this.getOSName(true) === String(osName).toLowerCase(); return this.getOSName(true) === String(osName).toLowerCase();
} }
/**
* Check if the platform type equals the passed string
* @param {string} platformType The string to compare with the platform type
* @returns {boolean}
*/
isPlatform(platformType) { isPlatform(platformType) {
return this.getPlatformType(true) === String(platformType).toLowerCase(); return this.getPlatformType(true) === String(platformType).toLowerCase();
} }
/**
* Check if the engine name equals the passed string
* @param {string} engineName The string to compare with the engine name
* @returns {boolean}
*/
isEngine(engineName) {
return this.getEngineName(true) === String(engineName).toLowerCase();
}
/** /**
* Is anything? Check if the browser is called "anything", * Is anything? Check if the browser is called "anything",
* the OS called "anything" or the platform called "anything" * the OS called "anything" or the platform called "anything"
* @param {String} anything * @param {String} anything
* @param [includingAlias=false] The flag showing whether alias will be included into comparison
* @returns {Boolean} * @returns {Boolean}
*/ */
is(anything, includingAlias = false) { is(anything) {
return this.isBrowser(anything, includingAlias) || this.isOS(anything) return this.isBrowser(anything) || this.isOS(anything) || this.isPlatform(anything);
|| this.isPlatform(anything);
} }
/** /**
* Check if any of the given values satisfies this.is(anything) * Check if any of the given values satifies this.is(anything)
* @param {String[]} anythings * @param {String[]} anythings
* @returns {Boolean} * @returns {Boolean}
*/ */

View File

@ -1,6 +1,4 @@
import { BROWSER_MAP, BROWSER_ALIASES_MAP } from './constants.js'; class Utils {
export default class Utils {
/** /**
* Get first matched item for a string * Get first matched item for a string
* @param {RegExp} regexp * @param {RegExp} regexp
@ -53,109 +51,6 @@ export default class Utils {
} }
} }
/**
* Get macOS version name
* 10.5 - Leopard
* 10.6 - Snow Leopard
* 10.7 - Lion
* 10.8 - Mountain Lion
* 10.9 - Mavericks
* 10.10 - Yosemite
* 10.11 - El Capitan
* 10.12 - Sierra
* 10.13 - High Sierra
* 10.14 - Mojave
* 10.15 - Catalina
* 11 - Big Sur
* 12 - Monterey
* 13 - Ventura
* 14 - Sonoma
* 15 - Sequoia
*
* @example
* getMacOSVersionName("10.14") // 'Mojave'
*
* @param {string} version
* @return {string} versionName
*/
static getMacOSVersionName(version) {
const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);
v.push(0);
const major = v[0];
const minor = v[1];
if (major === 10) {
switch (minor) {
case 5: return 'Leopard';
case 6: return 'Snow Leopard';
case 7: return 'Lion';
case 8: return 'Mountain Lion';
case 9: return 'Mavericks';
case 10: return 'Yosemite';
case 11: return 'El Capitan';
case 12: return 'Sierra';
case 13: return 'High Sierra';
case 14: return 'Mojave';
case 15: return 'Catalina';
default: return undefined;
}
}
switch (major) {
case 11: return 'Big Sur';
case 12: return 'Monterey';
case 13: return 'Ventura';
case 14: return 'Sonoma';
case 15: return 'Sequoia';
default: return undefined;
}
}
/**
* Get Android version name
* 1.5 - Cupcake
* 1.6 - Donut
* 2.0 - Eclair
* 2.1 - Eclair
* 2.2 - Froyo
* 2.x - Gingerbread
* 3.x - Honeycomb
* 4.0 - Ice Cream Sandwich
* 4.1 - Jelly Bean
* 4.4 - KitKat
* 5.x - Lollipop
* 6.x - Marshmallow
* 7.x - Nougat
* 8.x - Oreo
* 9.x - Pie
*
* @example
* getAndroidVersionName("7.0") // 'Nougat'
*
* @param {string} version
* @return {string} versionName
*/
static getAndroidVersionName(version) {
const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);
v.push(0);
if (v[0] === 1 && v[1] < 5) return undefined;
if (v[0] === 1 && v[1] < 6) return 'Cupcake';
if (v[0] === 1 && v[1] >= 6) return 'Donut';
if (v[0] === 2 && v[1] < 2) return 'Eclair';
if (v[0] === 2 && v[1] === 2) return 'Froyo';
if (v[0] === 2 && v[1] > 2) return 'Gingerbread';
if (v[0] === 3) return 'Honeycomb';
if (v[0] === 4 && v[1] < 1) return 'Ice Cream Sandwich';
if (v[0] === 4 && v[1] < 4) return 'Jelly Bean';
if (v[0] === 4 && v[1] >= 4) return 'KitKat';
if (v[0] === 5) return 'Lollipop';
if (v[0] === 6) return 'Marshmallow';
if (v[0] === 7) return 'Nougat';
if (v[0] === 8) return 'Oreo';
if (v[0] === 9) return 'Pie';
return undefined;
}
/** /**
* Get version precisions count * Get version precisions count
* *
@ -215,21 +110,16 @@ export default class Utils {
// 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true)
if (chunks[0][precision] > chunks[1][precision]) { if (chunks[0][precision] > chunks[1][precision]) {
return 1; return 1;
} } else if (chunks[0][precision] === chunks[1][precision]) {
if (chunks[0][precision] === chunks[1][precision]) {
if (precision === lastPrecision) { if (precision === lastPrecision) {
// all version chunks are same // all version chunks are same
return 0; return 0;
} }
} else {
precision -= 1;
} else if (chunks[0][precision] < chunks[1][precision]) {
return -1; return -1;
} }
precision -= 1;
} }
return undefined;
} }
/** /**
@ -250,78 +140,6 @@ 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
*
* @example
* getBrowserAlias('Microsoft Edge') // edge
*
* @param {string} browserName
* @return {string}
*/
static getBrowserAlias(browserName) {
return BROWSER_ALIASES_MAP[browserName];
}
/**
* Get browser name for a short version/alias
*
* @example
* getBrowserTypeByAlias('edge') // Microsoft Edge
*
* @param {string} browserAlias
* @return {string}
*/
static getBrowserTypeByAlias(browserAlias) {
return BROWSER_MAP[browserAlias] || '';
}
} }
module.exports = Utils;

View File

@ -2,19 +2,16 @@ import test from 'ava';
import yaml from 'yamljs'; import yaml from 'yamljs';
import path from 'path'; import path from 'path';
import Bowser from '../../src/bowser'; import Bowser from '../../src/bowser';
import BowserBuild from '../../es5';
const listOfUA = yaml.load(path.join(__dirname, 'useragentstrings.yml')); const listOfUA = yaml.load(path.join(__dirname, 'useragentstrings.yml'));
const browserNames = Object.keys(listOfUA); const browserNames = Object.keys(listOfUA);
browserNames.forEach((browserName) => { browserNames.forEach((browserName) => {
listOfUA[browserName].forEach((browser, index) => { listOfUA[browserName].forEach((browser) => {
test(`Test ${browserName} ${index}`, (t) => { test('Check all the test browsers', (t) => {
const parsed = Bowser.parse(browser.ua); const parsed = Bowser.parse(browser.ua);
const parsedBuild = BowserBuild.parse(browser.ua);
t.deepEqual(parsed, browser.spec, `${browser.ua}`); t.deepEqual(parsed, browser.spec, `${browser.ua}`);
t.deepEqual(parsedBuild, browser.spec, `${browser.ua}`);
t.is(parsed.browser.name, browserName, `${browser.ua}`); t.is(parsed.browser.name, browserName, `${browser.ua}`);
}); });
}); });

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
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, []);
});

View File

@ -1,17 +1,10 @@
import test from 'ava'; import test from 'ava';
import sinon from 'sinon'; import sinon from 'sinon';
import Parser from '../../src/parser'; import Parser from '../../src/parser';
import Bowser from '../../src/bowser';
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 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 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);
const FOCUS_UA = 'Mozilla/5.0 (Linux; Android 7.1.1) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Focus/1.2.1 Chrome/59.0.3071.125';
const focusParser = new Parser(FOCUS_UA, true);
test('constructor', (t) => { test('constructor', (t) => {
t.truthy(parser instanceof Parser); t.truthy(parser instanceof Parser);
}); });
@ -60,43 +53,20 @@ test('Parser.getOSVersion returns a correct result', (t) => {
t.is(parser.getOSVersion(), '10.12.4'); t.is(parser.getOSVersion(), '10.12.4');
}); });
test('Parser.parseEngine is being called when getEngine() called', (t) => {
const spy = sinon.spy(parser, 'parseEngine');
parser.getEngine();
t.truthy(spy.called);
parser.parseEngine.restore();
});
test('Parser.getEngineName gives a name of the engine', (t) => {
t.is(parser.getEngineName(), 'Blink');
});
test('Parser.getEngineName gives a lower-cased name of the engine', (t) => {
t.is(parser.getEngineName(true), 'blink');
});
test('Skip parsing shouldn\'t parse', (t) => { test('Skip parsing shouldn\'t parse', (t) => {
t.deepEqual((new Parser(UA, true)).getResult(), {}); t.deepEqual((new Parser(UA, true)).getResult(), {});
}); });
test('Parser.satisfies should make simple comparisons', (t) => { test('Parser.check should make simple comparisons', (t) => {
// also covers Parser.compareVersion() method // also covers Parser.compareVersion() method
t.is(parser.satisfies({ opera: '>42' }), true); t.is(parser.satisfies({ opera: '>42' }), true);
t.is(parser.satisfies({ opera: '<44' }), true); t.is(parser.satisfies({ opera: '<44' }), true);
t.is(parser.satisfies({ opera: '=43.0.2442.1165' }), true); t.is(parser.satisfies({ opera: '=43.0.2442.1165' }), true);
t.is(parser.satisfies({ opera: '~43.0' }), true); t.is(parser.satisfies({ opera: '~43.0' }), true);
t.is(parser.satisfies({ opera: '>=43' }), true);
t.is(parser.satisfies({ opera: '<=43' }), true);
t.is(parser.satisfies({ opera: '>=43.0' }), true);
t.is(parser.satisfies({ opera: '>=43.0.2442.1165' }), true);
t.is(parser.satisfies({ opera: '<=43.0.2442.1165' }), true);
t.is(parser.satisfies({ opera: '>=43.0.2443' }), false);
t.is(parser.satisfies({ opera: '<=43.0.2443' }), true);
t.is(parser.satisfies({ opera: '>=43.0.2441' }), true);
t.is(parser.satisfies({ opera: '~43' }), true); t.is(parser.satisfies({ opera: '~43' }), true);
}); });
test('Parser.satisfies should make complex comparison', (t) => { test('Parser.check should make complex comparison', (t) => {
t.is(parser.satisfies({ t.is(parser.satisfies({
macos: { macos: {
safari: '>11', safari: '>11',
@ -108,7 +78,7 @@ test('Parser.satisfies should make complex comparison', (t) => {
}), true); }), true);
}); });
test('Parser.satisfies should respect platform and OS specific declarations', (t) => { test('Parser.check should respect platform and OS specific declarations', (t) => {
t.is(parser.satisfies({ t.is(parser.satisfies({
macos: { macos: {
opera: '>45', opera: '>45',
@ -144,57 +114,12 @@ test('Parser.satisfies should respect platform and OS specific declarations', (t
}), void 0); }), void 0);
}); });
test('Parser.satisfies for versionless UA strings', (t) => {
const _parser = new Parser('Mozilla/5.0 (iPhone; CPU iPhone OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15G77 [FBAN/FBIOS;FBDV/iPhone7,2;FBMD/iPhone;FBSN/iOS;FBSV/11.4.1;FBSS/2;FBCR/vfnl;FBID/phone;FBLC/nl_NL;FBOP/5;FBRV/0]');
t.is(_parser.satisfies({
safari: '>9',
}), 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) => { test('Parser.is should pass', (t) => {
t.is(parser.is('opera'), true); t.is(parser.is('opera'), true);
t.is(parser.is('desktop'), true); t.is(parser.is('desktop'), true);
t.is(parser.is('macos'), true); t.is(parser.is('macos'), true);
}); });
test('Parser.is should pass when not including aliases', (t) => {
t.is(edgeParser.is('Microsoft Edge', false), true);
t.is(edgeParser.is('microsoft edge', false), true);
t.is(edgeParser.is('mIcrosoft eDge', false), true);
t.is(edgeParser.is('edge', false), false);
t.is(edgeParser.is('Edge', false), false);
t.is(edgeParser.is('desktop', false), false);
t.is(edgeParser.is('macos', false), false);
t.is(edgeParser.is('mobile', false), true);
t.is(edgeParser.is('android', false), true);
});
test('Parser.is should pass when including aliases', (t) => {
t.is(edgeParser.is('Microsoft Edge', true), true);
t.is(edgeParser.is('microsoft edge', true), true);
t.is(edgeParser.is('mIcrosoft eDge', true), true);
t.is(edgeParser.is('edge', true), true);
t.is(edgeParser.is('Edge', true), true);
t.is(edgeParser.is('desktop', true), false);
t.is(edgeParser.is('macos', true), false);
t.is(edgeParser.is('mobile', true), true);
t.is(edgeParser.is('android', true), true);
});
test('Parser.is using constants should pass', (t) => {
t.is(parser.is(Bowser.BROWSER_MAP.opera), true);
t.is(parser.is(Bowser.PLATFORMS_MAP.desktop), true);
t.is(parser.is(Bowser.OS_MAP.MacOS), true);
});
test('Parser.some should pass', (t) => { test('Parser.some should pass', (t) => {
t.is(parser.some(['opera', 'chrome', 'firefox']), true); t.is(parser.some(['opera', 'chrome', 'firefox']), true);
t.is(parser.some(['macos', 'windows']), true); t.is(parser.some(['macos', 'windows']), true);
@ -202,29 +127,3 @@ test('Parser.some should pass', (t) => {
t.is(parser.some([]), false); t.is(parser.some([]), false);
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);
});
test('Parser.isBrowser should pass for non-aliased browsers', (t) => {
t.is(focusParser.isBrowser('Focus', true), true);
t.is(focusParser.isBrowser('Focus', false), true);
});
test('Parser.isEngine should pass', (t) => {
t.is(parser.isEngine('blink'), true);
t.is(parser.isEngine('webkit'), false);
});

View File

@ -1,18 +1,8 @@
import test from 'ava'; import test from 'ava';
import { import {
getFirstMatch, getFirstMatch,
getSecondMatch,
matchAndReturnConst,
getWindowsVersionName, getWindowsVersionName,
getMacOSVersionName,
getAndroidVersionName,
getVersionPrecision,
compareVersions, compareVersions,
map,
find,
assign,
getBrowserAlias,
getBrowserTypeByAlias
} from '../../src/utils'; } from '../../src/utils';
test('getFirstMatch', (t) => { test('getFirstMatch', (t) => {
@ -20,45 +10,11 @@ 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);
}); });
test('getMacOSVersionName', (t) => {
t.is(getMacOSVersionName('10.14.5'), 'Mojave');
t.is(getMacOSVersionName('10.15'), 'Catalina');
t.is(getMacOSVersionName('11.0'), 'Big Sur');
t.is(getMacOSVersionName('12.3.1'), 'Monterey');
t.is(getMacOSVersionName('13.2.1'), 'Ventura');
t.is(getMacOSVersionName('14.0'), 'Sonoma');
t.is(getMacOSVersionName('15.1'), 'Sequoia');
t.is(getMacOSVersionName('10.999999'), void 0);
t.is(getMacOSVersionName('XXX'), void 0);
});
test('getAndroidVersionName', (t) => {
t.is(getAndroidVersionName('1.0'), void 0);
t.is(getAndroidVersionName('8.0'), 'Oreo');
t.is(getAndroidVersionName('9'), 'Pie');
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],
@ -94,52 +50,3 @@ test('compareVersions', (t) => {
t.is(compareVersions(versionA, versionB, isLoose), result, `version ${versionA} should be ${matching} version ${versionB}`); t.is(compareVersions(versionA, versionB, isLoose), result, `version ${versionA} should be ${matching} version ${versionB}`);
}); });
}); });
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), '');
});

View File

@ -1,15 +1,10 @@
const path = require('path'); const path = require('path');
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = { module.exports = {
plugins: [
new CompressionPlugin(),
],
mode: 'production', // "production" | "development" | "none" mode: 'production', // "production" | "development" | "none"
// Chosen mode tells webpack to use its built-in optimizations accordingly. // Chosen mode tells webpack to use its built-in optimizations accordingly.
entry: { entry: {
bundled: ['@babel/polyfill', './src/bowser.js'], bundled: ['babel-polyfill', './src/bowser.js'],
es5: './src/bowser.js', es5: './src/bowser.js',
}, // string | object | array }, // string | object | array
// defaults to ./src // defaults to ./src