new license file version [CI SKIP]

This commit is contained in:
2023-03-15 13:43:57 +00:00
parent d8a3063735
commit 00359d25c1
5600 changed files with 523898 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"version":3,"file":"isObject.js","sources":["../../../src/internal/util/isObject.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,CAAM;IAC7B,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;AAC7C,CAAC"}

View File

@@ -0,0 +1,81 @@
import { distinctUntilChanged } from './distinctUntilChanged';
import { MonoTypeOperatorFunction } from '../types';
/* tslint:disable:max-line-length */
export function distinctUntilKeyChanged<T>(key: keyof T): MonoTypeOperatorFunction<T>;
export function distinctUntilKeyChanged<T, K extends keyof T>(key: K, compare: (x: T[K], y: T[K]) => boolean): MonoTypeOperatorFunction<T>;
/* tslint:enable:max-line-length */
/**
* Returns an Observable that emits all items emitted by the source Observable that are distinct by comparison from the previous item,
* using a property accessed by using the key provided to check if the two items are distinct.
*
* If a comparator function is provided, then it will be called for each item to test for whether or not that value should be emitted.
*
* If a comparator function is not provided, an equality check is used by default.
*
* ## Examples
* An example comparing the name of persons
* ```typescript
* import { of } from 'rxjs';
* import { distinctUntilKeyChanged } from 'rxjs/operators';
*
* interface Person {
* age: number,
* name: string
* }
*
* of<Person>(
* { age: 4, name: 'Foo'},
* { age: 7, name: 'Bar'},
* { age: 5, name: 'Foo'},
* { age: 6, name: 'Foo'},
* ).pipe(
* distinctUntilKeyChanged('name'),
* )
* .subscribe(x => console.log(x));
*
* // displays:
* // { age: 4, name: 'Foo' }
* // { age: 7, name: 'Bar' }
* // { age: 5, name: 'Foo' }
* ```
*
* An example comparing the first letters of the name
* ```typescript
* import { of } from 'rxjs';
* import { distinctUntilKeyChanged } from 'rxjs/operators';
*
* interface Person {
* age: number,
* name: string
* }
*
* of<Person>(
* { age: 4, name: 'Foo1'},
* { age: 7, name: 'Bar'},
* { age: 5, name: 'Foo2'},
* { age: 6, name: 'Foo3'},
* ).pipe(
* distinctUntilKeyChanged('name', (x: string, y: string) => x.substring(0, 3) === y.substring(0, 3)),
* )
* .subscribe(x => console.log(x));
*
* // displays:
* // { age: 4, name: 'Foo1' }
* // { age: 7, name: 'Bar' }
* // { age: 5, name: 'Foo2' }
* ```
*
* @see {@link distinct}
* @see {@link distinctUntilChanged}
*
* @param {string} key String key for object property lookup on each item.
* @param {function} [compare] Optional comparison function called to test if an item is distinct from the previous item in the source.
* @return {Observable} An Observable that emits items from the source Observable with distinct values based on the key specified.
* @method distinctUntilKeyChanged
* @owner Observable
*/
export function distinctUntilKeyChanged<T, K extends keyof T>(key: K, compare?: (x: T[K], y: T[K]) => boolean): MonoTypeOperatorFunction<T> {
return distinctUntilChanged((x: T, y: T) => compare ? compare(x[key], y[key]) : x[key] === y[key]);
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"not.js","sources":["../src/util/not.ts"],"names":[],"mappings":";;;;;AAAA,0CAAqC"}

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var config_1 = require("./config");
var hostReportError_1 = require("./util/hostReportError");
exports.empty = {
closed: true,
next: function (value) { },
error: function (err) {
if (config_1.config.useDeprecatedSynchronousErrorHandling) {
throw err;
}
else {
hostReportError_1.hostReportError(err);
}
},
complete: function () { }
};
//# sourceMappingURL=Observer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"sequenceEqual.js","sources":["../../src/add/operator/sequenceEqual.ts"],"names":[],"mappings":";;AAAA,kDAAgD"}

View File

@@ -0,0 +1,410 @@
# buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url]
[travis-image]: https://img.shields.io/travis/feross/buffer/master.svg
[travis-url]: https://travis-ci.org/feross/buffer
[npm-image]: https://img.shields.io/npm/v/buffer.svg
[npm-url]: https://npmjs.org/package/buffer
[downloads-image]: https://img.shields.io/npm/dm/buffer.svg
[downloads-url]: https://npmjs.org/package/buffer
[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg
[standard-url]: https://standardjs.com
#### The buffer module from [node.js](https://nodejs.org/), for the browser.
[![saucelabs][saucelabs-image]][saucelabs-url]
[saucelabs-image]: https://saucelabs.com/browser-matrix/buffer.svg
[saucelabs-url]: https://saucelabs.com/u/buffer
With [browserify](http://browserify.org), simply `require('buffer')` or use the `Buffer` global and you will get this module.
The goal is to provide an API that is 100% identical to
[node's Buffer API](https://nodejs.org/api/buffer.html). Read the
[official docs](https://nodejs.org/api/buffer.html) for the full list of properties,
instance methods, and class methods that are supported.
## features
- Manipulate binary data like a boss, in all browsers!
- Super fast. Backed by Typed Arrays (`Uint8Array`/`ArrayBuffer`, not `Object`)
- Extremely small bundle size (**6.75KB minified + gzipped**, 51.9KB with comments)
- Excellent browser support (Chrome, Firefox, Edge, Safari 9+, IE 11, iOS 9+, Android, etc.)
- Preserves Node API exactly, with one minor difference (see below)
- Square-bracket `buf[4]` notation works!
- Does not modify any browser prototypes or put anything on `window`
- Comprehensive test suite (including all buffer tests from node.js core)
## install
To use this module directly (without browserify), install it:
```bash
npm install buffer
```
This module was previously called **native-buffer-browserify**, but please use **buffer**
from now on.
If you do not use a bundler, you can use the [standalone script](https://bundle.run/buffer).
## usage
The module's API is identical to node's `Buffer` API. Read the
[official docs](https://nodejs.org/api/buffer.html) for the full list of properties,
instance methods, and class methods that are supported.
As mentioned above, `require('buffer')` or use the `Buffer` global with
[browserify](http://browserify.org) and this module will automatically be included
in your bundle. Almost any npm module will work in the browser, even if it assumes that
the node `Buffer` API will be available.
To depend on this module explicitly (without browserify), require it like this:
```js
var Buffer = require('buffer/').Buffer // note: the trailing slash is important!
```
To require this module explicitly, use `require('buffer/')` which tells the node.js module
lookup algorithm (also used by browserify) to use the **npm module** named `buffer`
instead of the **node.js core** module named `buffer`!
## how does it work?
The Buffer constructor returns instances of `Uint8Array` that have their prototype
changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of `Uint8Array`,
so the returned instances will have all the node `Buffer` methods and the
`Uint8Array` methods. Square bracket notation works as expected -- it returns a
single octet.
The `Uint8Array` prototype remains unmodified.
## tracking the latest node api
This module tracks the Buffer API in the latest (unstable) version of node.js. The Buffer
API is considered **stable** in the
[node stability index](https://nodejs.org/docs/latest/api/documentation.html#documentation_stability_index),
so it is unlikely that there will ever be breaking changes.
Nonetheless, when/if the Buffer API changes in node, this module's API will change
accordingly.
## related packages
- [`buffer-reverse`](https://www.npmjs.com/package/buffer-reverse) - Reverse a buffer
- [`buffer-xor`](https://www.npmjs.com/package/buffer-xor) - Bitwise xor a buffer
- [`is-buffer`](https://www.npmjs.com/package/is-buffer) - Determine if an object is a Buffer without including the whole `Buffer` package
## conversion packages
### convert typed array to buffer
Use [`typedarray-to-buffer`](https://www.npmjs.com/package/typedarray-to-buffer) to convert any kind of typed array to a `Buffer`. Does not perform a copy, so it's super fast.
### convert buffer to typed array
`Buffer` is a subclass of `Uint8Array` (which is a typed array). So there is no need to explicitly convert to typed array. Just use the buffer as a `Uint8Array`.
### convert blob to buffer
Use [`blob-to-buffer`](https://www.npmjs.com/package/blob-to-buffer) to convert a `Blob` to a `Buffer`.
### convert buffer to blob
To convert a `Buffer` to a `Blob`, use the `Blob` constructor:
```js
var blob = new Blob([ buffer ])
```
Optionally, specify a mimetype:
```js
var blob = new Blob([ buffer ], { type: 'text/html' })
```
### convert arraybuffer to buffer
To convert an `ArrayBuffer` to a `Buffer`, use the `Buffer.from` function. Does not perform a copy, so it's super fast.
```js
var buffer = Buffer.from(arrayBuffer)
```
### convert buffer to arraybuffer
To convert a `Buffer` to an `ArrayBuffer`, use the `.buffer` property (which is present on all `Uint8Array` objects):
```js
var arrayBuffer = buffer.buffer.slice(
buffer.byteOffset, buffer.byteOffset + buffer.byteLength
)
```
Alternatively, use the [`to-arraybuffer`](https://www.npmjs.com/package/to-arraybuffer) module.
## performance
See perf tests in `/perf`.
`BrowserBuffer` is the browser `buffer` module (this repo). `Uint8Array` is included as a
sanity check (since `BrowserBuffer` uses `Uint8Array` under the hood, `Uint8Array` will
always be at least a bit faster). Finally, `NodeBuffer` is the node.js buffer module,
which is included to compare against.
NOTE: Performance has improved since these benchmarks were taken. PR welcome to update the README.
### Chrome 38
| Method | Operations | Accuracy | Sampled | Fastest |
|:-------|:-----------|:---------|:--------|:-------:|
| BrowserBuffer#bracket-notation | 11,457,464 ops/sec | ±0.86% | 66 | ✓ |
| Uint8Array#bracket-notation | 10,824,332 ops/sec | ±0.74% | 65 | |
| | | | |
| BrowserBuffer#concat | 450,532 ops/sec | ±0.76% | 68 | |
| Uint8Array#concat | 1,368,911 ops/sec | ±1.50% | 62 | ✓ |
| | | | |
| BrowserBuffer#copy(16000) | 903,001 ops/sec | ±0.96% | 67 | |
| Uint8Array#copy(16000) | 1,422,441 ops/sec | ±1.04% | 66 | ✓ |
| | | | |
| BrowserBuffer#copy(16) | 11,431,358 ops/sec | ±0.46% | 69 | |
| Uint8Array#copy(16) | 13,944,163 ops/sec | ±1.12% | 68 | ✓ |
| | | | |
| BrowserBuffer#new(16000) | 106,329 ops/sec | ±6.70% | 44 | |
| Uint8Array#new(16000) | 131,001 ops/sec | ±2.85% | 31 | ✓ |
| | | | |
| BrowserBuffer#new(16) | 1,554,491 ops/sec | ±1.60% | 65 | |
| Uint8Array#new(16) | 6,623,930 ops/sec | ±1.66% | 65 | ✓ |
| | | | |
| BrowserBuffer#readDoubleBE | 112,830 ops/sec | ±0.51% | 69 | ✓ |
| DataView#getFloat64 | 93,500 ops/sec | ±0.57% | 68 | |
| | | | |
| BrowserBuffer#readFloatBE | 146,678 ops/sec | ±0.95% | 68 | ✓ |
| DataView#getFloat32 | 99,311 ops/sec | ±0.41% | 67 | |
| | | | |
| BrowserBuffer#readUInt32LE | 843,214 ops/sec | ±0.70% | 69 | ✓ |
| DataView#getUint32 | 103,024 ops/sec | ±0.64% | 67 | |
| | | | |
| BrowserBuffer#slice | 1,013,941 ops/sec | ±0.75% | 67 | |
| Uint8Array#subarray | 1,903,928 ops/sec | ±0.53% | 67 | ✓ |
| | | | |
| BrowserBuffer#writeFloatBE | 61,387 ops/sec | ±0.90% | 67 | |
| DataView#setFloat32 | 141,249 ops/sec | ±0.40% | 66 | ✓ |
### Firefox 33
| Method | Operations | Accuracy | Sampled | Fastest |
|:-------|:-----------|:---------|:--------|:-------:|
| BrowserBuffer#bracket-notation | 20,800,421 ops/sec | ±1.84% | 60 | |
| Uint8Array#bracket-notation | 20,826,235 ops/sec | ±2.02% | 61 | ✓ |
| | | | |
| BrowserBuffer#concat | 153,076 ops/sec | ±2.32% | 61 | |
| Uint8Array#concat | 1,255,674 ops/sec | ±8.65% | 52 | ✓ |
| | | | |
| BrowserBuffer#copy(16000) | 1,105,312 ops/sec | ±1.16% | 63 | |
| Uint8Array#copy(16000) | 1,615,911 ops/sec | ±0.55% | 66 | ✓ |
| | | | |
| BrowserBuffer#copy(16) | 16,357,599 ops/sec | ±0.73% | 68 | |
| Uint8Array#copy(16) | 31,436,281 ops/sec | ±1.05% | 68 | ✓ |
| | | | |
| BrowserBuffer#new(16000) | 52,995 ops/sec | ±6.01% | 35 | |
| Uint8Array#new(16000) | 87,686 ops/sec | ±5.68% | 45 | ✓ |
| | | | |
| BrowserBuffer#new(16) | 252,031 ops/sec | ±1.61% | 66 | |
| Uint8Array#new(16) | 8,477,026 ops/sec | ±0.49% | 68 | ✓ |
| | | | |
| BrowserBuffer#readDoubleBE | 99,871 ops/sec | ±0.41% | 69 | |
| DataView#getFloat64 | 285,663 ops/sec | ±0.70% | 68 | ✓ |
| | | | |
| BrowserBuffer#readFloatBE | 115,540 ops/sec | ±0.42% | 69 | |
| DataView#getFloat32 | 288,722 ops/sec | ±0.82% | 68 | ✓ |
| | | | |
| BrowserBuffer#readUInt32LE | 633,926 ops/sec | ±1.08% | 67 | ✓ |
| DataView#getUint32 | 294,808 ops/sec | ±0.79% | 64 | |
| | | | |
| BrowserBuffer#slice | 349,425 ops/sec | ±0.46% | 69 | |
| Uint8Array#subarray | 5,965,819 ops/sec | ±0.60% | 65 | ✓ |
| | | | |
| BrowserBuffer#writeFloatBE | 59,980 ops/sec | ±0.41% | 67 | |
| DataView#setFloat32 | 317,634 ops/sec | ±0.63% | 68 | ✓ |
### Safari 8
| Method | Operations | Accuracy | Sampled | Fastest |
|:-------|:-----------|:---------|:--------|:-------:|
| BrowserBuffer#bracket-notation | 10,279,729 ops/sec | ±2.25% | 56 | ✓ |
| Uint8Array#bracket-notation | 10,030,767 ops/sec | ±2.23% | 59 | |
| | | | |
| BrowserBuffer#concat | 144,138 ops/sec | ±1.38% | 65 | |
| Uint8Array#concat | 4,950,764 ops/sec | ±1.70% | 63 | ✓ |
| | | | |
| BrowserBuffer#copy(16000) | 1,058,548 ops/sec | ±1.51% | 64 | |
| Uint8Array#copy(16000) | 1,409,666 ops/sec | ±1.17% | 65 | ✓ |
| | | | |
| BrowserBuffer#copy(16) | 6,282,529 ops/sec | ±1.88% | 58 | |
| Uint8Array#copy(16) | 11,907,128 ops/sec | ±2.87% | 58 | ✓ |
| | | | |
| BrowserBuffer#new(16000) | 101,663 ops/sec | ±3.89% | 57 | |
| Uint8Array#new(16000) | 22,050,818 ops/sec | ±6.51% | 46 | ✓ |
| | | | |
| BrowserBuffer#new(16) | 176,072 ops/sec | ±2.13% | 64 | |
| Uint8Array#new(16) | 24,385,731 ops/sec | ±5.01% | 51 | ✓ |
| | | | |
| BrowserBuffer#readDoubleBE | 41,341 ops/sec | ±1.06% | 67 | |
| DataView#getFloat64 | 322,280 ops/sec | ±0.84% | 68 | ✓ |
| | | | |
| BrowserBuffer#readFloatBE | 46,141 ops/sec | ±1.06% | 65 | |
| DataView#getFloat32 | 337,025 ops/sec | ±0.43% | 69 | ✓ |
| | | | |
| BrowserBuffer#readUInt32LE | 151,551 ops/sec | ±1.02% | 66 | |
| DataView#getUint32 | 308,278 ops/sec | ±0.94% | 67 | ✓ |
| | | | |
| BrowserBuffer#slice | 197,365 ops/sec | ±0.95% | 66 | |
| Uint8Array#subarray | 9,558,024 ops/sec | ±3.08% | 58 | ✓ |
| | | | |
| BrowserBuffer#writeFloatBE | 17,518 ops/sec | ±1.03% | 63 | |
| DataView#setFloat32 | 319,751 ops/sec | ±0.48% | 68 | ✓ |
### Node 0.11.14
| Method | Operations | Accuracy | Sampled | Fastest |
|:-------|:-----------|:---------|:--------|:-------:|
| BrowserBuffer#bracket-notation | 10,489,828 ops/sec | ±3.25% | 90 | |
| Uint8Array#bracket-notation | 10,534,884 ops/sec | ±0.81% | 92 | ✓ |
| NodeBuffer#bracket-notation | 10,389,910 ops/sec | ±0.97% | 87 | |
| | | | |
| BrowserBuffer#concat | 487,830 ops/sec | ±2.58% | 88 | |
| Uint8Array#concat | 1,814,327 ops/sec | ±1.28% | 88 | ✓ |
| NodeBuffer#concat | 1,636,523 ops/sec | ±1.88% | 73 | |
| | | | |
| BrowserBuffer#copy(16000) | 1,073,665 ops/sec | ±0.77% | 90 | |
| Uint8Array#copy(16000) | 1,348,517 ops/sec | ±0.84% | 89 | ✓ |
| NodeBuffer#copy(16000) | 1,289,533 ops/sec | ±0.82% | 93 | |
| | | | |
| BrowserBuffer#copy(16) | 12,782,706 ops/sec | ±0.74% | 85 | |
| Uint8Array#copy(16) | 14,180,427 ops/sec | ±0.93% | 92 | ✓ |
| NodeBuffer#copy(16) | 11,083,134 ops/sec | ±1.06% | 89 | |
| | | | |
| BrowserBuffer#new(16000) | 141,678 ops/sec | ±3.30% | 67 | |
| Uint8Array#new(16000) | 161,491 ops/sec | ±2.96% | 60 | |
| NodeBuffer#new(16000) | 292,699 ops/sec | ±3.20% | 55 | ✓ |
| | | | |
| BrowserBuffer#new(16) | 1,655,466 ops/sec | ±2.41% | 82 | |
| Uint8Array#new(16) | 14,399,926 ops/sec | ±0.91% | 94 | ✓ |
| NodeBuffer#new(16) | 3,894,696 ops/sec | ±0.88% | 92 | |
| | | | |
| BrowserBuffer#readDoubleBE | 109,582 ops/sec | ±0.75% | 93 | ✓ |
| DataView#getFloat64 | 91,235 ops/sec | ±0.81% | 90 | |
| NodeBuffer#readDoubleBE | 88,593 ops/sec | ±0.96% | 81 | |
| | | | |
| BrowserBuffer#readFloatBE | 139,854 ops/sec | ±1.03% | 85 | ✓ |
| DataView#getFloat32 | 98,744 ops/sec | ±0.80% | 89 | |
| NodeBuffer#readFloatBE | 92,769 ops/sec | ±0.94% | 93 | |
| | | | |
| BrowserBuffer#readUInt32LE | 710,861 ops/sec | ±0.82% | 92 | |
| DataView#getUint32 | 117,893 ops/sec | ±0.84% | 91 | |
| NodeBuffer#readUInt32LE | 851,412 ops/sec | ±0.72% | 93 | ✓ |
| | | | |
| BrowserBuffer#slice | 1,673,877 ops/sec | ±0.73% | 94 | |
| Uint8Array#subarray | 6,919,243 ops/sec | ±0.67% | 90 | ✓ |
| NodeBuffer#slice | 4,617,604 ops/sec | ±0.79% | 93 | |
| | | | |
| BrowserBuffer#writeFloatBE | 66,011 ops/sec | ±0.75% | 93 | |
| DataView#setFloat32 | 127,760 ops/sec | ±0.72% | 93 | ✓ |
| NodeBuffer#writeFloatBE | 103,352 ops/sec | ±0.83% | 93 | |
### iojs 1.8.1
| Method | Operations | Accuracy | Sampled | Fastest |
|:-------|:-----------|:---------|:--------|:-------:|
| BrowserBuffer#bracket-notation | 10,990,488 ops/sec | ±1.11% | 91 | |
| Uint8Array#bracket-notation | 11,268,757 ops/sec | ±0.65% | 97 | |
| NodeBuffer#bracket-notation | 11,353,260 ops/sec | ±0.83% | 94 | ✓ |
| | | | |
| BrowserBuffer#concat | 378,954 ops/sec | ±0.74% | 94 | |
| Uint8Array#concat | 1,358,288 ops/sec | ±0.97% | 87 | |
| NodeBuffer#concat | 1,934,050 ops/sec | ±1.11% | 78 | ✓ |
| | | | |
| BrowserBuffer#copy(16000) | 894,538 ops/sec | ±0.56% | 84 | |
| Uint8Array#copy(16000) | 1,442,656 ops/sec | ±0.71% | 96 | |
| NodeBuffer#copy(16000) | 1,457,898 ops/sec | ±0.53% | 92 | ✓ |
| | | | |
| BrowserBuffer#copy(16) | 12,870,457 ops/sec | ±0.67% | 95 | |
| Uint8Array#copy(16) | 16,643,989 ops/sec | ±0.61% | 93 | ✓ |
| NodeBuffer#copy(16) | 14,885,848 ops/sec | ±0.74% | 94 | |
| | | | |
| BrowserBuffer#new(16000) | 109,264 ops/sec | ±4.21% | 63 | |
| Uint8Array#new(16000) | 138,916 ops/sec | ±1.87% | 61 | |
| NodeBuffer#new(16000) | 281,449 ops/sec | ±3.58% | 51 | ✓ |
| | | | |
| BrowserBuffer#new(16) | 1,362,935 ops/sec | ±0.56% | 99 | |
| Uint8Array#new(16) | 6,193,090 ops/sec | ±0.64% | 95 | ✓ |
| NodeBuffer#new(16) | 4,745,425 ops/sec | ±1.56% | 90 | |
| | | | |
| BrowserBuffer#readDoubleBE | 118,127 ops/sec | ±0.59% | 93 | ✓ |
| DataView#getFloat64 | 107,332 ops/sec | ±0.65% | 91 | |
| NodeBuffer#readDoubleBE | 116,274 ops/sec | ±0.94% | 95 | |
| | | | |
| BrowserBuffer#readFloatBE | 150,326 ops/sec | ±0.58% | 95 | ✓ |
| DataView#getFloat32 | 110,541 ops/sec | ±0.57% | 98 | |
| NodeBuffer#readFloatBE | 121,599 ops/sec | ±0.60% | 87 | |
| | | | |
| BrowserBuffer#readUInt32LE | 814,147 ops/sec | ±0.62% | 93 | |
| DataView#getUint32 | 137,592 ops/sec | ±0.64% | 90 | |
| NodeBuffer#readUInt32LE | 931,650 ops/sec | ±0.71% | 96 | ✓ |
| | | | |
| BrowserBuffer#slice | 878,590 ops/sec | ±0.68% | 93 | |
| Uint8Array#subarray | 2,843,308 ops/sec | ±1.02% | 90 | |
| NodeBuffer#slice | 4,998,316 ops/sec | ±0.68% | 90 | ✓ |
| | | | |
| BrowserBuffer#writeFloatBE | 65,927 ops/sec | ±0.74% | 93 | |
| DataView#setFloat32 | 139,823 ops/sec | ±0.97% | 89 | ✓ |
| NodeBuffer#writeFloatBE | 135,763 ops/sec | ±0.65% | 96 | |
| | | | |
## Testing the project
First, install the project:
npm install
Then, to run tests in Node.js, run:
npm run test-node
To test locally in a browser, you can run:
npm run test-browser-es5-local # For ES5 browsers that don't support ES6
npm run test-browser-es6-local # For ES6 compliant browsers
This will print out a URL that you can then open in a browser to run the tests, using [airtap](https://www.npmjs.com/package/airtap).
To run automated browser tests using Saucelabs, ensure that your `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` environment variables are set, then run:
npm test
This is what's run in Travis, to check against various browsers. The list of browsers is kept in the `bin/airtap-es5.yml` and `bin/airtap-es6.yml` files.
## JavaScript Standard Style
This module uses [JavaScript Standard Style](https://github.com/feross/standard).
[![JavaScript Style Guide](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)
To test that the code conforms to the style, `npm install` and run:
./node_modules/.bin/standard
## credit
This was originally forked from [buffer-browserify](https://github.com/toots/buffer-browserify).
## Security Policies and Procedures
The `buffer` team and community take all security bugs in `buffer` seriously. Please see our [security policies and procedures](https://github.com/feross/security) document to learn how to report issues.
## license
MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org), and other contributors. Originally forked from an MIT-licensed module by Romain Beauxis.

View File

@@ -0,0 +1 @@
{"version":3,"file":"publishLast.js","sources":["../src/operators/publishLast.ts"],"names":[],"mappings":";;;;;AAAA,uDAAkD"}

View File

@@ -0,0 +1 @@
module.exports={C:{"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0.00466,"48":0.00933,"49":0,"50":0,"51":0,"52":0.03264,"53":0,"54":0,"55":0,"56":0.00466,"57":0,"58":0,"59":0.00466,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0.00466,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0.0373,"79":0,"80":0.00466,"81":0.00466,"82":0.00466,"83":0,"84":0.00466,"85":0,"86":0,"87":0.00933,"88":0.00933,"89":0,"90":0,"91":0.00933,"92":0,"93":0,"94":0.02798,"95":0.00466,"96":0.00466,"97":0.00466,"98":0,"99":0.00466,"100":0.00466,"101":0.00466,"102":0.04197,"103":0.00466,"104":0.00466,"105":0.00933,"106":0.02332,"107":0.02798,"108":1.05384,"109":0.66215,"110":0.00466,"111":0,"3.5":0,"3.6":0},D:{"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0.00466,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0.04197,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0.00466,"59":0,"60":0.00466,"61":0,"62":0,"63":0.06528,"64":0,"65":0.00466,"66":0.04663,"67":0.01399,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0.00466,"75":0,"76":0,"77":0.00466,"78":0.00466,"79":0.0373,"80":0.00933,"81":0.02332,"83":0.01865,"84":0.02332,"85":0.03264,"86":0.03264,"87":0.04197,"88":0.00933,"89":0.00933,"90":0.00933,"91":0.00466,"92":0.0373,"93":0.00933,"94":0.00466,"95":0.00933,"96":0.01399,"97":0.01399,"98":0.01399,"99":0.01865,"100":0.02332,"101":0.01399,"102":0.01865,"103":0.08393,"104":0.02798,"105":0.0373,"106":0.04663,"107":0.11658,"108":6.35567,"109":6.78933,"110":0.00466,"111":0,"112":0},F:{"9":0,"11":0,"12":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0.00466,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"60":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0.00933,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0.00466,"90":0.00466,"91":0,"92":0.00933,"93":0.21916,"94":0.33574,"9.5-9.6":0,"10.0-10.1":0,"10.5":0,"10.6":0,"11.1":0,"11.5":0,"11.6":0,"12.1":0},B:{"12":0,"13":0,"14":0,"15":0.00466,"16":0,"17":0.00466,"18":0.00466,"79":0,"80":0,"81":0,"83":0,"84":0.00466,"85":0.00466,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0.00466,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0.00466,"102":0,"103":0.00466,"104":0.00933,"105":0.00466,"106":0.00933,"107":0.02798,"108":0.9699,"109":1.03519},E:{"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0.00933,"14":0.06062,"15":0.01865,_:"0","3.1":0,"3.2":0,"5.1":0,"6.1":0,"7.1":0,"9.1":0.00466,"10.1":0,"11.1":0.00933,"12.1":0.02332,"13.1":0.10259,"14.1":0.13523,"15.1":0.02798,"15.2-15.3":0.02332,"15.4":0.06062,"15.5":0.10259,"15.6":0.47563,"16.0":0.0886,"16.1":0.29843,"16.2":0.5036,"16.3":0.04197},G:{"8":0.00243,"3.2":0,"4.0-4.1":0,"4.2-4.3":0,"5.0-5.1":0.00487,"6.0-6.1":0,"7.0-7.1":0.00487,"8.1-8.4":0,"9.0-9.2":0.0073,"9.3":0.10219,"10.0-10.2":0.0073,"10.3":0.09489,"11.0-11.2":0.01947,"11.3-11.4":0.04866,"12.0-12.1":0.02433,"12.2-12.5":0.41364,"13.0-13.1":0.0146,"13.2":0.00973,"13.3":0.04136,"13.4-13.7":0.13869,"14.0-14.4":0.34308,"14.5-14.8":0.76158,"15.0-15.1":0.20925,"15.2-15.3":0.25305,"15.4":0.29928,"15.5":0.63505,"15.6":2.24094,"16.0":3.85656,"16.1":7.47223,"16.2":5.69846,"16.3":0.53043},P:{"4":0.09292,"5.0-5.4":0,"6.2-6.4":0,"7.2-7.4":0,"8.2":0,"9.2":0.01032,"10.1":0.01032,"11.1-11.2":0.0413,"12.0":0.01032,"13.0":0.0413,"14.0":0.03097,"15.0":0.02065,"16.0":0.0826,"17.0":0.0826,"18.0":0.15487,"19.0":2.72576},I:{"0":0,"3":0,"4":0,"2.1":0,"2.2":0,"2.3":0,"4.1":0.01246,"4.2-4.3":0.03738,"4.4":0,"4.4.3-4.4.4":0.11213},K:{_:"0 10 11 12 11.1 11.5 12.1"},A:{"6":0,"7":0,"8":0.0049,"9":0.0049,"10":0,"11":0.08813,"5.5":0},J:{"7":0,"10":0},N:{"10":0,"11":0},R:{_:"0"},M:{"0":0.30421},Q:{"13.1":0},O:{"0":0.09607},H:{"0":0.25264},L:{"0":49.51224},S:{"2.5":0}};

View File

@@ -0,0 +1 @@
{"version":3,"file":"isEmpty.js","sources":["../src/operators/isEmpty.ts"],"names":[],"mappings":";;;;;AAAA,mDAA8C"}

View File

@@ -0,0 +1,73 @@
import { OuterSubscriber } from '../OuterSubscriber';
import { subscribeToResult } from '../util/subscribeToResult';
export function withLatestFrom(...args) {
return (source) => {
let project;
if (typeof args[args.length - 1] === 'function') {
project = args.pop();
}
const observables = args;
return source.lift(new WithLatestFromOperator(observables, project));
};
}
class WithLatestFromOperator {
constructor(observables, project) {
this.observables = observables;
this.project = project;
}
call(subscriber, source) {
return source.subscribe(new WithLatestFromSubscriber(subscriber, this.observables, this.project));
}
}
class WithLatestFromSubscriber extends OuterSubscriber {
constructor(destination, observables, project) {
super(destination);
this.observables = observables;
this.project = project;
this.toRespond = [];
const len = observables.length;
this.values = new Array(len);
for (let i = 0; i < len; i++) {
this.toRespond.push(i);
}
for (let i = 0; i < len; i++) {
let observable = observables[i];
this.add(subscribeToResult(this, observable, undefined, i));
}
}
notifyNext(_outerValue, innerValue, outerIndex) {
this.values[outerIndex] = innerValue;
const toRespond = this.toRespond;
if (toRespond.length > 0) {
const found = toRespond.indexOf(outerIndex);
if (found !== -1) {
toRespond.splice(found, 1);
}
}
}
notifyComplete() {
}
_next(value) {
if (this.toRespond.length === 0) {
const args = [value, ...this.values];
if (this.project) {
this._tryProject(args);
}
else {
this.destination.next(args);
}
}
}
_tryProject(args) {
let result;
try {
result = this.project.apply(this, args);
}
catch (err) {
this.destination.error(err);
return;
}
this.destination.next(result);
}
}
//# sourceMappingURL=withLatestFrom.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"isPromise.js","sources":["../../../src/internal/util/isPromise.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,SAAS,CAAC,KAAU;IAClC,OAAO,CAAC,CAAC,KAAK,IAAI,OAAa,KAAM,CAAC,SAAS,KAAK,UAAU,IAAI,OAAQ,KAAa,CAAC,IAAI,KAAK,UAAU,CAAC;AAC9G,CAAC"}

View File

@@ -0,0 +1,138 @@
const test = require('ava');
const mock = require('mock-fs');
const Config = require('../lib/config');
const defaultConfig = require('../config/release-it.json');
const localConfig = { github: { release: true } };
test.afterEach(() => mock.restore()); // eslint-disable-line ava/no-inline-assertions
test('should contain default values', t => {
mock({ '../.release-it.json': JSON.stringify(localConfig) });
const config = new Config();
t.deepEqual(config.constructorConfig, {});
t.deepEqual(config.localConfig, localConfig);
t.deepEqual(config.defaultConfig, defaultConfig);
mock.restore();
});
test('should merge provided options', t => {
mock({
'package.json': JSON.stringify({ 'release-it': { git: { push: false } } }),
'../.release-it.json': JSON.stringify(localConfig)
});
const config = new Config({
increment: '1.0.0',
verbose: true,
github: {
release: true
}
});
const { options } = config;
t.is(config.isVerbose, true);
t.is(config.isDryRun, false);
t.is(options.increment, '1.0.0');
t.is(options.git.push, false);
t.is(options.github.release, true);
mock.restore();
});
test('should set CI mode', t => {
const config = new Config({ ci: true });
t.is(config.isCI, true);
});
test('should detect CI mode', t => {
const isCI = require('is-ci');
const config = new Config();
t.is(config.options.ci, isCI);
t.is(config.isCI, isCI);
});
test('should override --no-npm.publish', t => {
const config = new Config({ npm: { publish: false } });
t.is(config.options.npm.publish, false);
});
test('should read YAML config', t => {
mock({ '.release-it.yaml': 'foo:\n bar: 1' });
const config = new Config({ config: '.release-it.yaml' });
t.deepEqual(config.options.foo, { bar: 1 });
mock.restore();
});
test('should read YML config', t => {
mock({ '.release-it.yml': 'foo:\n bar: 1' });
const config = new Config({ config: '.release-it.yml' });
t.deepEqual(config.options.foo, { bar: 1 });
mock.restore();
});
test('should read TOML config', t => {
mock({ '.release-it.toml': '[foo]\nbar=1' });
const config = new Config({ config: '.release-it.toml' });
t.deepEqual(config.options.foo, { bar: 1 });
mock.restore();
});
test('should throw if provided config file is not found', t => {
t.throws(() => new Config({ config: 'nofile' }), { message: /no such file.+nofile/ });
});
test('should throw if provided config file is invalid (cosmiconfig exception)', t => {
mock({ 'invalid-config-txt': 'foo\nbar\baz' });
t.throws(() => new Config({ config: 'invalid-config-txt' }), { message: /Invalid configuration file at/ });
mock.restore();
});
test('should throw if provided config file is invalid (no object)', t => {
mock({ 'invalid-config-rc': 'foo=bar' });
t.throws(() => new Config({ config: 'invalid-config-rc' }), { message: /Invalid configuration file at/ });
mock.restore();
});
test('should not set default increment (for CI mode)', t => {
const config = new Config({ ci: true });
t.is(config.options.version.increment, undefined);
});
test('should not set default increment (for interactive mode)', t => {
const config = new Config({ ci: false });
t.is(config.options.version.increment, undefined);
});
test('should expand pre-release shortcut', t => {
const config = new Config({ increment: 'major', preRelease: 'beta' });
t.deepEqual(config.options.version, {
increment: 'major',
isPreRelease: true,
preReleaseId: 'beta'
});
});
test('should expand pre-release shortcut (preRelease boolean)', t => {
const config = new Config({ ci: true, preRelease: true });
t.deepEqual(config.options.version, {
increment: undefined,
isPreRelease: true,
preReleaseId: undefined
});
});
test('should expand pre-release shortcut (without increment)', t => {
const config = new Config({ ci: false, preRelease: 'alpha' });
t.deepEqual(config.options.version, {
increment: undefined,
isPreRelease: true,
preReleaseId: 'alpha'
});
});
test('should expand pre-release shortcut (including increment and npm.tag)', t => {
const config = new Config({ increment: 'minor', preRelease: 'rc' });
t.deepEqual(config.options.version, {
increment: 'minor',
isPreRelease: true,
preReleaseId: 'rc'
});
});

View File

@@ -0,0 +1,202 @@
const test = require('ava');
const sinon = require('sinon');
const nock = require('nock');
const GitLab = require('../lib/plugin/gitlab/GitLab');
const {
interceptUser,
interceptCollaborator,
interceptCollaboratorFallback,
interceptPublish,
interceptAsset
} = require('./stub/gitlab');
const { factory, runTasks } = require('./util');
const tokenHeader = 'Private-Token';
const tokenRef = 'GITLAB_TOKEN';
test.serial('should validate token', async t => {
const tokenRef = 'MY_GITLAB_TOKEN';
const pushRepo = 'https://gitlab.com/user/repo';
const options = { gitlab: { release: true, tokenRef, tokenHeader, pushRepo } };
const gitlab = factory(GitLab, { options });
delete process.env[tokenRef];
await t.throwsAsync(gitlab.init(), {
message: /^Environment variable "MY_GITLAB_TOKEN" is required for GitLab releases/
});
process.env[tokenRef] = '123'; // eslint-disable-line require-atomic-updates
interceptUser(undefined, { reqheaders: { 'private-token': '123' } });
interceptCollaborator(undefined, { reqheaders: { 'private-token': '123' } });
await t.notThrowsAsync(gitlab.init());
});
test.serial('should support CI Job token header', async t => {
const tokenRef = 'CI_JOB_TOKEN';
const tokenHeader = 'Job-Token';
process.env[tokenRef] = 'j0b-t0k3n';
const pushRepo = 'https://gitlab.com/user/repo';
const options = { git: { pushRepo }, gitlab: { release: true, tokenRef, tokenHeader } };
const gitlab = factory(GitLab, { options });
interceptPublish(undefined, { reqheaders: { 'job-token': '1' } });
await t.notThrowsAsync(gitlab.init());
delete process.env[tokenRef];
});
test.serial('should upload assets and release', async t => {
const pushRepo = 'https://gitlab.com/user/repo';
const asset = 'file1';
const options = {
git: { pushRepo },
gitlab: {
tokenRef,
release: true,
releaseName: 'Release ${version}',
releaseNotes: 'echo Custom notes',
assets: `test/resources/${asset}`
}
};
const gitlab = factory(GitLab, { options });
sinon.stub(gitlab, 'getLatestVersion').resolves('2.0.0');
interceptUser();
interceptCollaborator();
interceptAsset();
interceptPublish({
body: {
name: 'Release 2.0.1',
tag_name: '2.0.1',
description: 'Custom notes',
assets: {
links: [
{
name: asset,
url: `${pushRepo}/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${asset}`
}
]
}
}
});
await runTasks(gitlab);
t.is(gitlab.assets[0].url, `${pushRepo}/uploads/7e8bec1fe27cc46a4bc6a91b9e82a07c/${asset}`);
const { isReleased, releaseUrl } = gitlab.getContext();
t.true(isReleased);
t.is(releaseUrl, `${pushRepo}/-/releases`);
});
test.serial('should release to self-managed host', async t => {
const host = 'https://gitlab.example.org';
const scope = nock(host);
scope.post('/api/v4/projects/user%2Frepo/releases').reply(200, {});
const options = {
git: { pushRepo: `${host}/user/repo` },
gitlab: { releaseName: 'Release ${version}', releaseNotes: 'echo readme', tokenRef }
};
const gitlab = factory(GitLab, { options });
sinon.stub(gitlab, 'getLatestVersion').resolves('1.0.0');
interceptUser({ host });
interceptCollaborator({ host });
await runTasks(gitlab);
const { origin, baseUrl } = gitlab.getContext();
t.is(origin, host);
t.is(baseUrl, `${host}/api/v4`);
});
test.serial('should release to sub-grouped repo', async t => {
const scope = nock('https://gitlab.com');
scope.post('/api/v4/projects/group%2Fsub-group%2Frepo/releases').reply(200, {});
const options = { gitlab: { tokenRef }, git: { pushRepo: 'git@gitlab.com:group/sub-group/repo.git' } };
const gitlab = factory(GitLab, { options });
interceptUser({ owner: 'sub-group' });
interceptCollaborator({ owner: 'sub-group', group: 'group' });
await runTasks(gitlab);
const { isReleased, releaseUrl } = gitlab.getContext();
t.true(isReleased);
t.is(releaseUrl, 'https://gitlab.com/group/sub-group/repo/-/releases');
});
test.serial('should throw for unauthenticated user', async t => {
const host = 'https://gitlab.com';
const pushRepo = `${host}/user/repo`;
const options = { gitlab: { tokenRef, pushRepo, host } };
const gitlab = factory(GitLab, { options });
const scope = nock(host);
scope.get(`/api/v4/user`).reply(401);
await t.throwsAsync(runTasks(gitlab), {
message: /^Could not authenticate with GitLab using environment variable "GITLAB_TOKEN"/
});
});
test.serial('should throw for non-collaborator', async t => {
const host = 'https://gitlab.com';
const pushRepo = `${host}/john/repo`;
const options = { gitlab: { tokenRef, pushRepo, host } };
const gitlab = factory(GitLab, { options });
const scope = nock(host);
scope.get(`/api/v4/projects/john%2Frepo/members/all/1`).reply(200, { username: 'emma' });
interceptUser({ owner: 'john' });
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
});
test.serial('should throw for insufficient access level', async t => {
const host = 'https://gitlab.com';
const pushRepo = `${host}/john/repo`;
const options = { gitlab: { tokenRef, pushRepo, host } };
const gitlab = factory(GitLab, { options });
const scope = nock(host);
scope.get(`/api/v4/projects/john%2Frepo/members/all/1`).reply(200, { username: 'john', access_level: 10 });
interceptUser({ owner: 'john' });
await t.throwsAsync(runTasks(gitlab), { message: /^User john is not a collaborator for john\/repo/ });
});
test.serial('should fallback for gitlab < v12.4', async t => {
const host = 'https://gitlab.com';
const pushRepo = `${host}/user/repo`;
const options = { gitlab: { tokenRef, pushRepo, host } };
const gitlab = factory(GitLab, { options });
const scope = nock(host);
scope.get(`/api/v4/projects/user%2Frepo/members/all/1`).reply(404);
interceptUser();
interceptCollaboratorFallback();
await t.notThrowsAsync(gitlab.init());
});
test('should not make requests in dry run', async t => {
const [host, owner, repo] = ['https://gitlab.example.org', 'user', 'repo'];
const pushRepo = `${host}/${owner}/${repo}`;
const options = { 'dry-run': true, git: { pushRepo }, gitlab: { releaseName: 'R', tokenRef } };
const gitlab = factory(GitLab, { options });
sinon.stub(gitlab, 'getLatestVersion').resolves('1.0.0');
const spy = sinon.spy(gitlab, 'client', ['get']);
await runTasks(gitlab);
const { isReleased, releaseUrl } = gitlab.getContext();
t.is(spy.get.callCount, 0);
t.is(gitlab.log.exec.args[1][0], 'gitlab releases#uploadAssets');
t.is(gitlab.log.exec.args[2][0], 'gitlab releases#createRelease "R" (1.0.1)');
t.true(isReleased);
t.is(releaseUrl, `${pushRepo}/-/releases`);
spy.restore();
});
test('should skip checks', async t => {
const options = { gitlab: { tokenRef, skipChecks: true } };
const gitlab = factory(GitLab, { options });
await t.notThrowsAsync(gitlab.init());
});

View File

@@ -0,0 +1,79 @@
let browserslist = require('browserslist')
let agents = require('caniuse-lite').agents
let utils = require('./utils')
class Browsers {
/**
* Return all prefixes for default browser data
*/
static prefixes () {
if (this.prefixesCache) {
return this.prefixesCache
}
this.prefixesCache = []
for (let name in agents) {
this.prefixesCache.push(`-${agents[name].prefix}-`)
}
this.prefixesCache = utils
.uniq(this.prefixesCache)
.sort((a, b) => b.length - a.length)
return this.prefixesCache
}
/**
* Check is value contain any possible prefix
*/
static withPrefix (value) {
if (!this.prefixesRegexp) {
this.prefixesRegexp = new RegExp(this.prefixes().join('|'))
}
return this.prefixesRegexp.test(value)
}
constructor (data, requirements, options, browserslistOpts) {
this.data = data
this.options = options || {}
this.browserslistOpts = browserslistOpts || {}
this.selected = this.parse(requirements)
}
/**
* Return browsers selected by requirements
*/
parse (requirements) {
let opts = {}
for (let i in this.browserslistOpts) {
opts[i] = this.browserslistOpts[i]
}
opts.path = this.options.from
return browserslist(requirements, opts)
}
/**
* Return prefix for selected browser
*/
prefix (browser) {
let [name, version] = browser.split(' ')
let data = this.data[name]
let prefix = data.prefix_exceptions && data.prefix_exceptions[version]
if (!prefix) {
prefix = data.prefix
}
return `-${prefix}-`
}
/**
* Is browser is selected by requirements
*/
isSelected (browser) {
return this.selected.includes(browser)
}
}
module.exports = Browsers