diff --git a/.travis.yml b/.travis.yml index 412c732a4..229664fbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,4 @@ branches: install: yarn -script: yarn build && yarn test:all +script: yarn build && yarn test:all && yarn lint diff --git a/CHANGELOG.md b/CHANGELOG.md index 81142b24b..f1c0434ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,40 @@ + +# [6.0.1](https://github.com/angular/angularfire2/compare/6.0.0...6.0.1) (2020-06-24) + +* Updating peer dependencies to allow for Angular 10 +* `ng add @angular/fire` should correctly add the `firebase` peer +* `ng add @angular/fire` will not duplicate settings entries, if they're already present +* `ng add @angular/fire` will error if there are peer incompatabilities +* `ng deploy` should function correctly on Windows devices +* `ng deploy` will now mark the Angular assets as immutable on Firebase Hosting +* RTDB and Firestore CRUD operations should return in the ngZone +* Use of `AngularFireAuthGuard` should no longer destablize Zone.js + + +# [6.0.0](https://github.com/angular/angularfire2/compare/6.0.0-rc.2...6.0.0) (2020-04-01) + +Final relase of version 6. + +* Updating peer dependencies +* `ng add @angular/fire` now will overwrite firebase config, if present +* `ng add @angular/fire` now adds `@firebase/firestore` to the server schematic `externalDependencies` if present +* `ng deploy --preview` is now interactive and functions on non-SSR +* `ng deploy` will respect the `bundleDependencies` and `externalDependencies` server schematic options +* `ng deploy` now defaults to 1GB of ram on Cloud Functions +* Fixed various issues with functions deploy +* Simplified `AngularPerformanceMonitoring` + + +# [6.0.0-rc.2](https://github.com/angular/angularfire2/compare/6.0.0-rc.1...6.0.0-rc.2) (2020-03-29) + +Continued work on 6.0. + +* Update peers +* No longer require developer add bare imports themselves (e.g, `import 'firebase/firestore'`) +* Zone.js fixes +* Angular Universal deploy schematic +* Storage listAll() + # [6.0.0-rc.1](https://github.com/angular/angularfire2/compare/6.0.0-rc.0...6.0.0-rc.1) (2020-02-06) @@ -74,7 +111,7 @@ Version 6 of AngularFire drops support for Angular version 8 and below, older ve * Dropped `StorageBucket` DI token in favor of `BUCKET` -## [5.4.2](https://github.com/angular/angularfire2/compare/5.4.1...5.4.2) (2020-02-06) +# [5.4.2](https://github.com/angular/angularfire2/compare/5.4.1...5.4.2) (2020-02-06) ### Bug Fixes @@ -82,7 +119,7 @@ Version 6 of AngularFire drops support for Angular version 8 and below, older ve -## [5.4.1](https://github.com/angular/angularfire2/compare/5.4.0...5.4.1) (2020-02-05) +# [5.4.1](https://github.com/angular/angularfire2/compare/5.4.0...5.4.1) (2020-02-05) ### Bug Fixes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47484db41..de9c0e29e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,8 +80,8 @@ Providing the following information will increase the chances of your issue bein * **Angular Version** - what version of Angular, Firebase, and AngularFire are you using? * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you * **Browsers and Operating System** - is this a problem with all browsers? -* **Reproduce the Error** - provide a live example (using [Plunker][plunker], - [JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps +* **Reproduce the Error** - provide a live example (using StackBlitz (https://stackblitz.com/edit/angular-fire-start)) + or a unambiguous set of steps * **Related Issues** - has a similar issue been reported before? * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 0f6a4eb5e..6b7814848 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -46,12 +46,12 @@ be fixed in the latest versions. --> ### How to reproduce these conditions -**Failing test unit, Plunkr, or JSFiddle demonstrating the problem** +**Failing test unit, Stackblitz demonstrating the problem** **Steps to set up and reproduce** @@ -60,7 +60,7 @@ Plunker (http://plnkr.co/) or JSFiddle (https://jsfiddle.net/). **Sample data and security rules** -<-- include/attach/link to some json sample data (or provide credentials to a sanitized, test Firebase project) --> + ### Debug output diff --git a/README.md b/README.md index 05dc39679..f8aa9ddfc 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ export class MyApp { [Contributing](CONTRIBUTING.md) -[Stackblitz Template](https://stackblitz.com/edit/angular-1iment) - Remember to set your Firebase configuration in `app/app.module.ts`. +[Stackblitz Template](https://stackblitz.com/edit/angular-fire-start) - Remember to set your Firebase configuration in `app/app.module.ts`. [Upgrading to v6.0? Check out our guide.](docs/version-6-upgrade.md) diff --git a/docs/analytics/getting-started.md b/docs/analytics/getting-started.md index 8db7a2f9d..76ee26859 100644 --- a/docs/analytics/getting-started.md +++ b/docs/analytics/getting-started.md @@ -122,7 +122,7 @@ See the gtag.js documentation to learn of the different configuration options at ### Use DebugView `DEBUG_MODE` -To use [DebugView in Analtyics](https://console.firebase.google.com/project/_/analytics/debugview) set `DEBUG_MODE` to `true` (*default: false*). +To use [DebugView in Analytics](https://console.firebase.google.com/project/_/analytics/debugview) set `DEBUG_MODE` to `true` (*default: false*). ### Track deployments with `APP_NAME` and `APP_VERSION` @@ -132,4 +132,4 @@ If you provide `APP_NAME` and `APP_VERSION` (*default: undefined*) you will be a If you set `COLLECTION_ENABLED` (*default: true*) to `false` then analytics collection will be disabled for this app on this device. To opt back in to analytics collection you could then call `setAnalyticsCollectionEnabled(true)`. -Putting these APIs to use with cookies would allow you to create a flexible analytics collection scheme that would respect your user's desire for privacy. \ No newline at end of file +Putting these APIs to use with cookies would allow you to create a flexible analytics collection scheme that would respect your user's desire for privacy. diff --git a/docs/auth/router-guards.md b/docs/auth/router-guards.md index e326f68f6..841eb306b 100644 --- a/docs/auth/router-guards.md +++ b/docs/auth/router-guards.md @@ -39,7 +39,7 @@ const belongsToAccount = (next) => hasCustomClaim(`account-${next.params.id}`); export const routes: Routes = [ { path: '', component: AppComponent }, { path: 'login', component: LoginComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectLoggedInToItems }}, - { path: 'items', component: ItemListComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectUnauthorizedToLogin }, + { path: 'items', component: ItemListComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectUnauthorizedToLogin }}, { path: 'admin', component: AdminComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: adminOnly }}, { path: 'accounts/:id', component: AdminComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: belongsToAccount }} ]; diff --git a/docs/deploy/getting-started.md b/docs/deploy/getting-started.md index 1158989ae..b9fb66276 100644 --- a/docs/deploy/getting-started.md +++ b/docs/deploy/getting-started.md @@ -28,25 +28,25 @@ The schematics will do the following: In the end, your `angular.json` project will look like below: -```js +```json5 { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "sample-app": { - // ... - "deploy": { - "builder": "@angular/fire:deploy", - "options": {} // Here you may find an "ssr": true option if you've - // selected that you want to deploy your Angular universal project - // as a firebase function. + // ... + "deploy": { + "builder": "@angular/fire:deploy", + "options": {} // Here you may find an "ssr": true option if you've + // selected that you want to deploy your Angular universal project + // as a firebase function. } } - } - // ... }, + // ... "defaultProject": "sample-app" + } ``` diff --git a/docs/firestore/collections.md b/docs/firestore/collections.md index 8099f5988..adeb2cb2a 100644 --- a/docs/firestore/collections.md +++ b/docs/firestore/collections.md @@ -43,7 +43,7 @@ The `AngularFirestoreCollection` is a service you use to create streams of the c With the exception of the `valueChanges()`, each streaming method returns an Observable of `DocumentChangeAction[]`. -A `DocumentChangeAction` gives you the `type` and `payload` properties. The `type` tells when what `DocumentChangeType` operation occured (`added`, `modified`, `removed`). The `payload` property is a `DocumentChange` which provides you important metdata about the change and a `doc` property which is the `DocumentSnapshot`. +A `DocumentChangeAction` gives you the `type` and `payload` properties. The `type` tells when what `DocumentChangeType` operation occured (`added`, `modified`, `removed`). The `payload` property is a `DocumentChange` which provides you important metadata about the change and a `doc` property which is the `DocumentSnapshot`. ```ts interface DocumentChangeAction { @@ -191,7 +191,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; export interface AccountDeposit { description: string; amount: number; } -export interface AccountDepoistId extends AccountDeposit { id: string; } +export interface AccountDepositId extends AccountDeposit { id: string; } @Component({ selector: 'app-root', diff --git a/docs/functions/functions.md b/docs/functions/functions.md index a9713e80b..47f2f52e7 100644 --- a/docs/functions/functions.md +++ b/docs/functions/functions.md @@ -110,7 +110,7 @@ import { AngularFireFunctionsModule, ORIGIN } from '@angular/fire/functions'; ], ... providers: [ - { provide: ORIGIN, useValue: 'http://localhost:5005' } + { provide: ORIGIN, useValue: 'http://localhost:5001' } ] }) export class AppModule {} @@ -145,7 +145,7 @@ Next, configure functions origin to point at your app domain: ```ts import { NgModule } from '@angular/core'; -import { AngularFireFunctionsModule, FUNCTIONS_ORIGIN } from '@angular/fire/functions'; +import { AngularFireFunctionsModule, ORIGIN } from '@angular/fire/functions'; @NgModule({ imports: [ diff --git a/docs/install-and-setup.md b/docs/install-and-setup.md index 095b7de00..eb6483352 100644 --- a/docs/install-and-setup.md +++ b/docs/install-and-setup.md @@ -13,14 +13,14 @@ The Angular CLI's `new` command will set up the latest Angular build in a new pr ### 2. Install AngularFire and Firebase ```bash -ng add @angular/fire@next +ng add @angular/fire ``` Now that you have a new project setup, install AngularFire and Firebase from npm. ### 3. Add Firebase config to environments variable -Open `/src/environments/environment.ts` and add your Firebase configuration. You can find your project configuration in [the Firebase Console](https://console.firebase.google.com). From the project overview page, click **Add Firebase to your web app**. +Open `/src/environments/environment.ts` and add your Firebase configuration. You can find your project configuration in [the Firebase Console](https://console.firebase.google.com). Click the Gear icon next to Project Overview, then click Project Settings and under "Firebase SDK snippet" click Config. ```ts export const environment = { @@ -62,7 +62,7 @@ export class AppModule {} After adding the AngularFireModule you also need to add modules for the individual @NgModules that your application needs. -For example if your application was using both Google Analtyics and the Firestore you would add `AngularFireAnalyticsModule` and `AngularFirestoreModule`: +For example if your application was using both Google Analytics and the Firestore you would add `AngularFireAnalyticsModule` and `AngularFirestoreModule`: ```ts import { BrowserModule } from '@angular/platform-browser'; @@ -146,7 +146,7 @@ ng serve Your Angular app will compile and serve locally, visit it we should see an empty list. -In another tab [start adding data to an `items` collection in Firestore](https://firebase.corp.google.com/project/_/database/firestore/data). *As we're not authenticating users yet, be sure to start Firestore in **test mode** or allow reading from the `items` collection in Security Rules (`allow read: if true`).* +In another tab [start adding data to an `items` collection in Firestore](https://firebase.google.com/docs/firestore/manage-data/add-data). *As we're not authenticating users yet, be sure to start Firestore in **test mode** or allow reading from the `items` collection in Security Rules (`allow read: if true`).* Once you've created a `items` collection and are inserting documents, you should see data streaming into your Angular application. diff --git a/docs/performance/getting-started.md b/docs/performance/getting-started.md index 15cf105ce..5b1832367 100644 --- a/docs/performance/getting-started.md +++ b/docs/performance/getting-started.md @@ -52,12 +52,12 @@ You can inject `AngularFirePerformance` to perform manual traces. ```ts constructor(private performance: AngularFirePerformance) {} -ngOnInit() { - const trace = this.performance.trace('some-trace'); - trace.start(); - ... - trace.stop(); -} +... + +const trace = await this.performance.trace('some-trace'); +trace.start(); +... +trace.stop(); ``` ## RXJS operators diff --git a/package.json b/package.json index 0cb99e87a..f87e48af1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@angular/fire", - "version": "6.0.0", + "version": "6.0.1", "description": "The official library of Firebase and Angular.", "private": true, "scripts": { @@ -16,6 +16,11 @@ "build": "tsc tools/build.ts; node ./tools/build.js", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1" }, + "husky": { + "hooks": { + "pre-commit": "npm run lint" + } + }, "schematics": "./dist/packages-dist/collection.json", "builders": "./dist/packages-dist/builders.json", "keywords": [ @@ -34,23 +39,25 @@ }, "homepage": "https://github.com/angular/angularfire2#readme", "dependencies": { - "@angular-devkit/architect": "~0.900", - "@angular-devkit/core": "^9.0.0", - "@angular-devkit/schematics": "^9.0.0", - "@angular/common": "^9.0.0", - "@angular/compiler": "^9.0.0", - "@angular/core": "^9.0.0", - "@angular/platform-browser": "^9.0.0", - "@angular/platform-browser-dynamic": "^9.0.0", - "@angular/router": "^9.0.0", + "@angular-devkit/architect": ">= 0.900 < 0.1100", + "@angular-devkit/core": "^9.0.0 || ^10.0.0", + "@angular-devkit/schematics": "^9.0.0 || ^10.0.0", + "@angular/common": "^9.0.0 || ^10.0.0", + "@angular/compiler": "^9.0.0 || ^10.0.0", + "@angular/core": "^9.0.0 || ^10.0.0", + "@angular/platform-browser": "^9.0.0 || ^10.0.0", + "@angular/platform-browser-dynamic": "^9.0.0 || ^10.0.0", + "@angular/router": "^9.0.0 || ^10.0.0", "firebase": "^7.13.1", "firebase-admin": "^8.10.0", "firebase-functions": "^3.6.0", "firebase-tools": "^8.0.0", "fs-extra": "^8.0.1", "fuzzy": "^0.1.3", + "husky": "^4.2.5", "inquirer": "^6.2.2", "inquirer-autocomplete-prompt": "^1.0.1", + "open": "^7.0.3", "rxfire": "^3.9.7", "rxjs": "^6.5.3", "semver": "^7.1.3", @@ -64,12 +71,12 @@ "utf-8-validate": "^5.0.2" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.900", - "@angular-devkit/build-ng-packagr": "~0.900", - "@angular/animations": " ^9.0.0", - "@angular/cli": "^9.0.0", - "@angular/compiler-cli": "^9.0.0", - "@angular/platform-server": "^9.0.0", + "@angular-devkit/build-angular": ">= 0.900 < 0.1100", + "@angular-devkit/build-ng-packagr": ">= 0.900 < 0.1100", + "@angular/animations": " ^9.0.0 || ^10.0.0", + "@angular/cli": "^9.0.0 || ^10.0.0", + "@angular/compiler-cli": "^9.0.0 || ^10.0.0", + "@angular/platform-server": "^9.0.0 || ^10.0.0", "@types/fs-extra": "^7.0.0", "@types/gzip-size": "^5.1.1", "@types/inquirer": "^0.0.44", @@ -80,7 +87,7 @@ "codelyzer": "^5.0.0", "concurrently": "^2.2.0", "conventional-changelog-cli": "^1.2.0", - "firebase-functions-test": "^0.1.7", + "firebase-functions-test": "^0.2.0", "gzip-size": "^5.1.1", "jasmine": "^3.4.0", "jasmine-core": "^3.4.0", diff --git a/sample/angular.json b/sample/angular.json index 9b326a8ab..5ac57205f 100644 --- a/sample/angular.json +++ b/sample/angular.json @@ -126,7 +126,6 @@ "tsConfig": "tsconfig.server.json", "bundleDependencies": false, "externalDependencies": [ - "@firebase/firestore", "@firebase/firestore" ] }, diff --git a/sample/firebase.json b/sample/firebase.json index 1857f85f6..f92bcbba1 100644 --- a/sample/firebase.json +++ b/sample/firebase.json @@ -4,10 +4,15 @@ "target": "sample", "public": "dist/sample/dist/sample/browser", "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" + "**/.*" ], + "headers": [{ + "source": "*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)", + "headers": [{ + "key": "Cache-Control", + "value": "public,max-age=31536000,immutable" + }] + }], "rewrites": [ { "source": "**", diff --git a/sample/package.json b/sample/package.json index ca6f187e3..ba87dadb0 100644 --- a/sample/package.json +++ b/sample/package.json @@ -19,7 +19,7 @@ "@angular/common": "~9.1.0", "@angular/compiler": "~9.1.0", "@angular/core": "~9.1.0", - "@angular/fire": "file:../dist/packages-dist", + "@angular/fire": "../dist/packages-dist", "@angular/forms": "~9.1.0", "@angular/platform-browser": "~9.1.0", "@angular/platform-browser-dynamic": "~9.1.0", @@ -27,7 +27,8 @@ "@angular/router": "~9.1.0", "@angular/service-worker": "~9.1.0", "@nguniversal/express-engine": "~9.1.0", - "firebase": "^7.13.1", + "firebase": "^7.13.2", + "proxy-polyfill": "^0.3.1", "rxjs": "~6.5.4", "tslib": "^1.10.0", "zone.js": "~0.10.2" diff --git a/sample/server.ts b/sample/server.ts index 329e5797a..c59772b10 100644 --- a/sample/server.ts +++ b/sample/server.ts @@ -9,8 +9,10 @@ import { APP_BASE_HREF } from '@angular/common'; import { existsSync } from 'fs'; // Polyfill XMLHttpRequest and WS for Firebase -global['XMLHttpRequest'] = require("xhr2"); -global['WebSocket'] = require("ws"); +/* tslint:disable:no-string-literal */ +global['XMLHttpRequest'] = require('xhr2'); +global['WebSocket'] = require('ws'); +/* tslint:enable:no-string-literal */ // The Express app is exported so that it can be used by serverless Functions. export function app() { diff --git a/sample/src/app/app-routing.module.ts b/sample/src/app/app-routing.module.ts index db7155ca0..61b02b7c2 100644 --- a/sample/src/app/app-routing.module.ts +++ b/sample/src/app/app-routing.module.ts @@ -1,13 +1,16 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; +import { HomeComponent } from './home/home.component'; -const routes: Routes = []; +const routes: Routes = [ + { path: '', component: HomeComponent, pathMatch: 'full' } +]; @NgModule({ imports: [RouterModule.forRoot(routes, { initialNavigation: 'enabled' -})], + })], exports: [RouterModule] }) export class AppRoutingModule { } diff --git a/sample/src/app/app.component.spec.ts b/sample/src/app/app.component.spec.ts index 58e834776..480adc6b2 100644 --- a/sample/src/app/app.component.spec.ts +++ b/sample/src/app/app.component.spec.ts @@ -1,4 +1,4 @@ -import { TestBed, async } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { AppComponent } from './app.component'; diff --git a/sample/src/app/app.component.ts b/sample/src/app/app.component.ts index 280a572ca..e0cb7c544 100644 --- a/sample/src/app/app.component.ts +++ b/sample/src/app/app.component.ts @@ -1,20 +1,14 @@ -import { Component, ApplicationRef } from '@angular/core'; +import { ApplicationRef, Component } from '@angular/core'; import { FirebaseApp } from '@angular/fire'; @Component({ selector: 'app-root', template: ` - Hello world! - {{ firebaseApp.name }} - - - - + `, styles: [``] }) export class AppComponent { - title = 'sample'; constructor(public readonly firebaseApp: FirebaseApp, appRef: ApplicationRef) { appRef.isStable.subscribe(it => console.log('isStable', it)); } diff --git a/sample/src/app/app.module.ts b/sample/src/app/app.module.ts index d6fae8dbf..c24b599c4 100644 --- a/sample/src/app/app.module.ts +++ b/sample/src/app/app.module.ts @@ -1,5 +1,5 @@ import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser'; -import { NgModule, isDevMode } from '@angular/core'; +import { isDevMode, NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -9,7 +9,12 @@ import { environment } from '../environments/environment'; import { AngularFireModule } from '@angular/fire'; import { AngularFireStorageModule } from '@angular/fire/storage'; -import { AngularFireAnalyticsModule, UserTrackingService, ScreenTrackingService, DEBUG_MODE as ANALYTICS_DEBUG_MODE } from '@angular/fire/analytics'; +import { + AngularFireAnalyticsModule, + DEBUG_MODE as ANALYTICS_DEBUG_MODE, + ScreenTrackingService, + UserTrackingService +} from '@angular/fire/analytics'; import { FirestoreComponent } from './firestore/firestore.component'; @@ -24,11 +29,21 @@ import { AngularFireAuthGuardModule } from '@angular/fire/auth-guard'; import { DatabaseComponent } from './database/database.component'; import { StorageComponent } from './storage/storage.component'; import { RemoteConfigComponent } from './remote-config/remote-config.component'; +import { HomeComponent } from './home/home.component'; +import { AuthComponent } from './auth/auth.component'; const shouldUseEmulator = () => false; @NgModule({ - declarations: [ AppComponent, StorageComponent, FirestoreComponent, DatabaseComponent, RemoteConfigComponent ], + declarations: [ + AppComponent, + StorageComponent, + FirestoreComponent, + DatabaseComponent, + RemoteConfigComponent, + HomeComponent, + AuthComponent + ], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), BrowserTransferStateModule, @@ -50,12 +65,19 @@ const shouldUseEmulator = () => false; UserTrackingService, ScreenTrackingService, PerformanceMonitoringService, - { provide: ANALYTICS_DEBUG_MODE, useFactory: () => isDevMode() }, - { provide: DATABASE_URL, useFactory: () => shouldUseEmulator() ? `http://localhost:9000?ns=${environment.firebase.projectId}` : undefined }, - { provide: FIRESTORE_SETTINGS, useFactory: () => shouldUseEmulator() ? { host: 'localhost:8080', ssl: false } : {} }, - { provide: FUNCTIONS_ORIGIN, useFactory: () => shouldUseEmulator() ? 'http://localhost:9999' : undefined }, + { + provide: ANALYTICS_DEBUG_MODE, + useFactory: () => isDevMode() + }, + { + provide: DATABASE_URL, + useFactory: () => shouldUseEmulator() ? `http://localhost:9000?ns=${environment.firebase.projectId}` : undefined + }, + { provide: FIRESTORE_SETTINGS, useFactory: () => shouldUseEmulator() ? { host: 'localhost:8080', ssl: false } : {} }, + { provide: FUNCTIONS_ORIGIN, useFactory: () => shouldUseEmulator() ? 'http://localhost:9999' : undefined }, { provide: REMOTE_CONFIG_SETTINGS, useFactory: () => isDevMode() ? { minimumFetchIntervalMillis: 10_000 } : {} } ], - bootstrap: [ AppComponent ] + bootstrap: [AppComponent] }) -export class AppModule { } +export class AppModule { +} diff --git a/sample/src/app/auth/auth.component.ts b/sample/src/app/auth/auth.component.ts index 7a0cf3c7c..28cf780a3 100644 --- a/sample/src/app/auth/auth.component.ts +++ b/sample/src/app/auth/auth.component.ts @@ -1,19 +1,51 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { AngularFireAuth } from '@angular/fire/auth'; +import { auth as rawAuth } from 'firebase/app'; +import { Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { trace } from '@angular/fire/performance'; @Component({ selector: 'app-auth', template: `

- auth works! + Auth! + {{ (auth.user | async)?.uid | json }} + +

`, styles: [] }) -export class AuthComponent implements OnInit { +export class AuthComponent implements OnInit, OnDestroy { - constructor() { } + private readonly userDisposable: Subscription; - ngOnInit(): void { + showLoginButton = false; + showLogoutButton = false; + + constructor(public readonly auth: AngularFireAuth) { + this.userDisposable = this.auth.authState.pipe( + trace('auth'), + map(u => !!u) + ).subscribe(isLoggedIn => { + this.showLoginButton = !isLoggedIn; + this.showLogoutButton = isLoggedIn; + }); + } + + ngOnInit(): void { } + + ngOnDestroy(): void { + this.userDisposable.unsubscribe(); + } + + login() { + this.auth.signInWithPopup(new rawAuth.GoogleAuthProvider()); + } + + logout() { + this.auth.signOut(); } } diff --git a/sample/src/app/database/database.component.ts b/sample/src/app/database/database.component.ts index b5136a874..5367f9d4e 100644 --- a/sample/src/app/database/database.component.ts +++ b/sample/src/app/database/database.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { AngularFireDatabase } from '@angular/fire/database'; import { Observable } from 'rxjs'; -import { TransferState, makeStateKey } from '@angular/platform-browser'; +import { makeStateKey, TransferState } from '@angular/platform-browser'; import { startWith, tap } from 'rxjs/operators'; import { trace } from '@angular/fire/performance'; diff --git a/sample/src/app/firestore/firestore.component.ts b/sample/src/app/firestore/firestore.component.ts index 09be15bea..d01e0cf1c 100644 --- a/sample/src/app/firestore/firestore.component.ts +++ b/sample/src/app/firestore/firestore.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { AngularFirestore } from '@angular/fire/firestore'; import { Observable } from 'rxjs'; -import { tap, startWith } from 'rxjs/operators'; -import { TransferState, makeStateKey } from '@angular/platform-browser'; +import { startWith, tap } from 'rxjs/operators'; +import { makeStateKey, TransferState } from '@angular/platform-browser'; import { trace } from '@angular/fire/performance'; @Component({ diff --git a/sample/src/app/home/home.component.ts b/sample/src/app/home/home.component.ts new file mode 100644 index 000000000..7fdd06e07 --- /dev/null +++ b/sample/src/app/home/home.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { FirebaseApp } from '@angular/fire'; + +@Component({ + selector: 'app-home', + template: ` + Hello world! + {{ firebaseApp.name }} + + + + + + `, + styles: [``] +}) +export class HomeComponent { + constructor(public readonly firebaseApp: FirebaseApp) { + } +} diff --git a/sample/src/app/remote-config/remote-config.component.ts b/sample/src/app/remote-config/remote-config.component.ts index 9bd3af5e5..a2d3311c5 100644 --- a/sample/src/app/remote-config/remote-config.component.ts +++ b/sample/src/app/remote-config/remote-config.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { AngularFireRemoteConfig } from '@angular/fire/remote-config'; +import { AngularFireRemoteConfig, mapToObject } from '@angular/fire/remote-config'; import { trace } from '@angular/fire/performance'; import { Observable } from 'rxjs'; @@ -18,7 +18,7 @@ export class RemoteConfigComponent implements OnInit { readonly change$: Observable; constructor(public readonly remoteConfig: AngularFireRemoteConfig) { - this.change$ = remoteConfig.changes.pipe(trace('remote-config')); + this.change$ = remoteConfig.parameters.pipe(trace('remote-config'), mapToObject({})); } ngOnInit(): void { diff --git a/sample/src/app/storage/storage.component.ts b/sample/src/app/storage/storage.component.ts index 077741ab5..b8e3547ee 100644 --- a/sample/src/app/storage/storage.component.ts +++ b/sample/src/app/storage/storage.component.ts @@ -5,14 +5,15 @@ import { startWith, tap } from 'rxjs/operators'; import { makeStateKey, TransferState } from '@angular/platform-browser'; import { trace } from '@angular/fire/performance'; -const TRANSPARENT_PNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=' +const TRANSPARENT_PNG + = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; @Component({ selector: 'app-storage', template: `

Storage! - +

`, styles: [] diff --git a/sample/src/environments/environment.prod.ts b/sample/src/environments/environment.prod.ts index c4610812a..77e62a543 100644 --- a/sample/src/environments/environment.prod.ts +++ b/sample/src/environments/environment.prod.ts @@ -1,13 +1,13 @@ export const environment = { production: true, firebase: { - apiKey: "AIzaSyA7CNE9aHbcSEbt9y03QReJ-Xr0nwKg7Yg", - authDomain: "aftest-94085.firebaseapp.com", - databaseURL: "https://aftest-94085.firebaseio.com", - projectId: "aftest-94085", - storageBucket: "aftest-94085.appspot.com", - messagingSenderId: "480362569154", - appId: "1:480362569154:web:2fe6f75104cdfb82f50a5b", - measurementId: "G-CBRYER9PJR" + apiKey: 'AIzaSyA7CNE9aHbcSEbt9y03QReJ-Xr0nwKg7Yg', + authDomain: 'aftest-94085.firebaseapp.com', + databaseURL: 'https://aftest-94085.firebaseio.com', + projectId: 'aftest-94085', + storageBucket: 'aftest-94085.appspot.com', + messagingSenderId: '480362569154', + appId: '1:480362569154:web:2fe6f75104cdfb82f50a5b', + measurementId: 'G-CBRYER9PJR' } }; diff --git a/sample/src/environments/environment.ts b/sample/src/environments/environment.ts index 0acc17a8d..6e0d7c872 100644 --- a/sample/src/environments/environment.ts +++ b/sample/src/environments/environment.ts @@ -5,14 +5,14 @@ export const environment = { production: false, firebase: { - apiKey: "AIzaSyA7CNE9aHbcSEbt9y03QReJ-Xr0nwKg7Yg", - authDomain: "aftest-94085.firebaseapp.com", - databaseURL: "https://aftest-94085.firebaseio.com", - projectId: "aftest-94085", - storageBucket: "aftest-94085.appspot.com", - messagingSenderId: "480362569154", - appId: "1:480362569154:web:2fe6f75104cdfb82f50a5b", - measurementId: "G-CBRYER9PJR" + apiKey: 'AIzaSyA7CNE9aHbcSEbt9y03QReJ-Xr0nwKg7Yg', + authDomain: 'aftest-94085.firebaseapp.com', + databaseURL: 'https://aftest-94085.firebaseio.com', + projectId: 'aftest-94085', + storageBucket: 'aftest-94085.appspot.com', + messagingSenderId: '480362569154', + appId: '1:480362569154:web:2fe6f75104cdfb82f50a5b', + measurementId: 'G-CBRYER9PJR' } }; @@ -23,4 +23,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -import 'zone.js/dist/zone-error'; // Included with Angular CLI. +import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/sample/src/polyfills.ts b/sample/src/polyfills.ts index 03711e5d9..ad4c19af5 100644 --- a/sample/src/polyfills.ts +++ b/sample/src/polyfills.ts @@ -55,9 +55,11 @@ /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js/dist/zone'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ + +import 'proxy-polyfill/proxy.min.js'; diff --git a/sample/src/test.ts b/sample/src/test.ts index 50193eb0f..ea29c06f0 100644 --- a/sample/src/test.ts +++ b/sample/src/test.ts @@ -2,10 +2,7 @@ import 'zone.js/dist/zone-testing'; import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; declare const require: { context(path: string, deep?: boolean, filter?: RegExp): { diff --git a/sample/yarn.lock b/sample/yarn.lock index 843ce9c7d..84ea3c5c9 100644 --- a/sample/yarn.lock +++ b/sample/yarn.lock @@ -181,8 +181,8 @@ resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.1.0.tgz#9dfc386bd1461e0fd4786031fd245da04371421c" integrity sha512-RVlyegdIAij0P1wLY5ObIdsBAzvmHkHfElnmfiNKhaDftP6U/3zRtaKDu0bq0jvn1WCQ8zXxFQ8AWyKZwyFS+w== -"@angular/fire@file:../dist/packages-dist": - version "6.0.0" +"@angular/fire@../dist/packages-dist": + version "6.0.1" "@angular/forms@~9.1.0": version "9.1.0" @@ -977,16 +977,16 @@ resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.3.0.tgz#33c3f695313b561d48d18d663a20f20362d3ee7c" integrity sha512-0AJ6xn53Qn0D/YOVHHvlWFfnzzRSdd98Lr8Oqe1PJ2HPIN+o7qf03YmOG7fLpR1uplcWd+7vGKmxUrN3jKUBwg== -"@firebase/analytics@0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.3.0.tgz#943e73e792ba3f282df4d47aff5a1603b93b37a5" - integrity sha512-EEHuK+OcWH6UxufRLVU3lAJ4rmm7aVHmcgkhE9ZQJQy5c+w7QTLvVpGqtrpqD+cYyIBJkFBKJB8NziVyqKwQHw== +"@firebase/analytics@0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.3.1.tgz#2c81837b1ecfc8405ee9ba8e9051c0753608e441" + integrity sha512-/Fo4tU+tVADVirH/RPOorirlQWxDw0oR0TJJoZH9F7+B/IZi8DHdZSl2gOVYBOa9jrL2jA7lNV8VGkWXLXhcXg== dependencies: "@firebase/analytics-types" "0.3.0" - "@firebase/component" "0.1.8" - "@firebase/installations" "0.4.6" - "@firebase/logger" "0.2.0" - "@firebase/util" "0.2.43" + "@firebase/component" "0.1.9" + "@firebase/installations" "0.4.7" + "@firebase/logger" "0.2.1" + "@firebase/util" "0.2.44" tslib "1.11.1" "@firebase/app-types@0.6.0": @@ -994,15 +994,15 @@ resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.0.tgz#8dcc3e793c6983e9d54f7eb623a7618c05f2d94c" integrity sha512-ld6rzjXk/SUauHiQZJkeuSJpxIZ5wdnWuF5fWBFQNPaxsaJ9kyYg9GqEvwZ1z2e6JP5cU9gwRBlfW1WkGtGDYA== -"@firebase/app@0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.0.tgz#62f1720a8764333d32a11b14f1c46d82f536cf4e" - integrity sha512-utFL07aO64ZVs9g79cv1KHomtLdKkkAeKN5e8G9NlXXuO6dZXhcHLbOmKY1AfwrkAvUzPEKkFFY3dytOIt+nlg== +"@firebase/app@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.1.tgz#ce7d2bb530e1fd0cb2fb74c85509249c783647fe" + integrity sha512-KSzSFQfiJgxi+7Ff/EZQcdvCnqKj2db9xa7I8z1UoRIRez9e0Q6+GpW3mrSVmmSCrBbKYsOO/SJh5NaFot0evg== dependencies: "@firebase/app-types" "0.6.0" - "@firebase/component" "0.1.8" - "@firebase/logger" "0.2.0" - "@firebase/util" "0.2.43" + "@firebase/component" "0.1.9" + "@firebase/logger" "0.2.1" + "@firebase/util" "0.2.44" dom-storage "2.1.0" tslib "1.11.1" xmlhttprequest "1.8.0" @@ -1017,10 +1017,10 @@ resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.10.0.tgz#9403633e723336055fad4bbf5e4c9fe3c55f8d3f" integrity sha512-VuW7c+RAk3AYPU0Hxmun3RzXn7fbJDdjQbxvvpRMnQ9zrhk8mH42cY466M0n4e/UGQ+0smlx5BqZII8aYQ5XPg== -"@firebase/auth@0.14.1": - version "0.14.1" - resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.14.1.tgz#0cb3226025c27bf2e01a738f3841ab6bde80572e" - integrity sha512-LE+QED10cjp28jJ7wwIY58HQBXoJioEWiQy7iQS8Fo2UxHGY5BvGjwnxX4yyszQPbcZZRLDSlBIUaYfog+rdEA== +"@firebase/auth@0.14.2": + version "0.14.2" + resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.14.2.tgz#2f5356cd7893ebd26ea6c4a0933eae6f6e0a0aff" + integrity sha512-5HaEGne2JbcVvzK9FeOEGi8NNQwq00thmL88uduqI8LTXHSOWaC8Y4El9DesVu6aFEOXELpf7W4I34CG9WwjlA== dependencies: "@firebase/auth-types" "0.10.0" @@ -1032,6 +1032,14 @@ "@firebase/util" "0.2.43" tslib "1.11.1" +"@firebase/component@0.1.9": + version "0.1.9" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.1.9.tgz#738d1a4c79431a1e899df5de7b310eee370d34ed" + integrity sha512-i58GsVpxBGnKn1rx2RCAH0rk1Ldp6WterfBNDHyxmuyRO6BaZAgvxrZ3Ku1/lqiI7XMbmmRpP3emmwrStbFt9Q== + dependencies: + "@firebase/util" "0.2.44" + tslib "1.11.1" + "@firebase/database-types@0.4.14": version "0.4.14" resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.4.14.tgz#181e10c1d1ae64fd0a080f6e0369cec115c51d70" @@ -1039,7 +1047,20 @@ dependencies: "@firebase/app-types" "0.6.0" -"@firebase/database@0.5.24", "@firebase/database@^0.5.17": +"@firebase/database@0.5.25": + version "0.5.25" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.5.25.tgz#fa3b00cf315cebd7a29ca1dfd869853b61469534" + integrity sha512-qUIpgDoODWs/FEdCQoH/VwRDvW7nn7m99TGxbMhdiE2WV/nzKbCo/PbbGm0dltdZzQ/SE87E2lfpPGK89Riw6Q== + dependencies: + "@firebase/auth-interop-types" "0.1.4" + "@firebase/component" "0.1.9" + "@firebase/database-types" "0.4.14" + "@firebase/logger" "0.2.1" + "@firebase/util" "0.2.44" + faye-websocket "0.11.3" + tslib "1.11.1" + +"@firebase/database@^0.5.17": version "0.5.24" resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.5.24.tgz#548b2030def35a7b6f4d71a4b2d1a67499d1eef3" integrity sha512-9whAQzU8cxDUKGBWCT/aHVmqfyzCP2RkGhbZi2oHpMrmvht7cuBtXtUbDD5R8WomniCOUP8rtQfmCFI7V9ehYw== @@ -1057,15 +1078,15 @@ resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-1.10.1.tgz#bf018f9c495f470592de745389474dc1c2960d3f" integrity sha512-vyKdm+AYUFT8XeUX62IOqaqPFCs/mAMoSEsqIz9HnSVsqCw/IocNjtjSa+3M80kRw4V8fI7JI+Xz6Wg5VJXLqA== -"@firebase/firestore@1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.13.0.tgz#2638f25b2a3d19cb891a6b334a0dc14aefef5a34" - integrity sha512-GctO+sxLqOnY8SkBN5Z5p1nUYRX+yWSc9Kcx9nIPbUZ0WqBM5BaSlBHZHTFtjmJxS+0j/Y8Mu7c6qm6q5rVnjA== +"@firebase/firestore@1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.13.1.tgz#272485845ec9796c52237b57d81ce9943553b95e" + integrity sha512-VcJCaj8Sxt89tLiL5q7szkdQ141KCsNanTAGBNdDWtHU4TbL66DKNgk798jopzN4LIhK2nnX34ntNek2p6r9PQ== dependencies: - "@firebase/component" "0.1.8" + "@firebase/component" "0.1.9" "@firebase/firestore-types" "1.10.1" - "@firebase/logger" "0.2.0" - "@firebase/util" "0.2.43" + "@firebase/logger" "0.2.1" + "@firebase/util" "0.2.44" "@firebase/webchannel-wrapper" "0.2.38" "@grpc/proto-loader" "^0.5.0" grpc "1.24.2" @@ -1076,12 +1097,12 @@ resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.3.16.tgz#be0362d7f61648fdf36a7d95de239eddee88f931" integrity sha512-kHhBvSYiY2prY4vNQCALYs1+OruTdylvGemHG6G6Bs/rj3qw7ui3WysBsDU/rInJitHIcsZ35qrtanoJeQUIXQ== -"@firebase/functions@0.4.38": - version "0.4.38" - resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.4.38.tgz#f49e3f4a4a3c67e527c472f05b2e517ea057e7fc" - integrity sha512-t5QkJg251FmIEEi2mh3Xrf7Q3yonSLRaUW/vhgze7A3Xy3uTIUT3BVNWuKaRmg1n0PgKQaBHCjlDoLJAdSpujg== +"@firebase/functions@0.4.39": + version "0.4.39" + resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.4.39.tgz#1cb8289caf43d5bae30a25734760a03fcdfe5714" + integrity sha512-D44hDaUFXsu6a+riagFzKP6NiAW2H//gLh9NwRLaEvwSopPF6irw1OmAA1fylFhugRgdiKJr0n13BxEN1/l9lQ== dependencies: - "@firebase/component" "0.1.8" + "@firebase/component" "0.1.9" "@firebase/functions-types" "0.3.16" "@firebase/messaging-types" "0.4.4" isomorphic-fetch "2.2.1" @@ -1092,14 +1113,14 @@ resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.3.3.tgz#f2e49e73afaeb7b352250365d0d90dff0b792592" integrity sha512-XvWhPPAGeZlc+CfCA8jTt2pv19Jovi/nUV73u30QbjBbk5xci9bp5I29aBZukHsR6YNBjFCLSkLPbno4m/bLUg== -"@firebase/installations@0.4.6": - version "0.4.6" - resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.4.6.tgz#e288e18b39dda3e8b3b35c3be6185a7b187924e5" - integrity sha512-ey8cE2ldRO4pYqg0lCWQ+XFLETHZWha3Hw1CnYJjLivk4FMM8u/es3Oa257wwtYXAUfr0UsPDfHFgYME9E9EhA== +"@firebase/installations@0.4.7": + version "0.4.7" + resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.4.7.tgz#143d1bfb20fbcd00e826e7afe283527c329e3c25" + integrity sha512-Fz9B/H58xfkAnDGVTW1V/73Jd5LAN9o5dpz1K3+u2W+zp0iU6HoRTwm9Bgk+aV6/0FYjqmtYEDjK8T0OYPoIQA== dependencies: - "@firebase/component" "0.1.8" + "@firebase/component" "0.1.9" "@firebase/installations-types" "0.3.3" - "@firebase/util" "0.2.43" + "@firebase/util" "0.2.44" idb "3.0.2" tslib "1.11.1" @@ -1108,20 +1129,25 @@ resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.2.0.tgz#d40149b8a33bca3dfbfb5b4a63e06b3ffa193157" integrity sha512-qOMnAh1JY9NkYUEy3iFviiFq0dCvk6qN2DsRy2Y7eAhHR6RqwA47l1kI+0MIXmSzlJ9akXjWAXxV5ijzr68Big== +"@firebase/logger@0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.2.1.tgz#09cdc5d3fe8ba4ed9bf8d6e6ab2a3b5398bd80bb" + integrity sha512-H4nttTqUzEw3TA/JYl8ma6oMSNKHcdpEWV2L2qA+ZEcpM2OLAzagi//DrYBFR5xpPb17IGagpzSxFgx937Sq/A== + "@firebase/messaging-types@0.4.4": version "0.4.4" resolved "https://registry.yarnpkg.com/@firebase/messaging-types/-/messaging-types-0.4.4.tgz#bef66157bdd3ddaafd6d48f1c5ee973fdc385f84" integrity sha512-JGtkr+1A1Dw7+yCqQigqBfGKtq0gTCruFScBD4MVjqZHiqGIYpnQisWnpGbkzPR6aOt6iQxgwxUhHG1ulUQGeg== -"@firebase/messaging@0.6.10": - version "0.6.10" - resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.6.10.tgz#0f2713a85732ce23ec7968e2f0ac784a259330e4" - integrity sha512-WYnKEffG6m0EMHzib8KCWVUGno1cuBC13RrOfGWOCv/whdy9QCIZgMxH/NsY3BrYst8FnjuXEU16fi5AEf4qbg== +"@firebase/messaging@0.6.11": + version "0.6.11" + resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.6.11.tgz#8be61ba73106c3907a0526758a038da6c09fa286" + integrity sha512-rYLNX9XjH3nmJ20KeMta78npGah65nvv+4zOIW8DJVs9jXJO6YSah4q0ugQESVC6H9VUFZw1e6iM9e75WHhxFA== dependencies: - "@firebase/component" "0.1.8" - "@firebase/installations" "0.4.6" + "@firebase/component" "0.1.9" + "@firebase/installations" "0.4.7" "@firebase/messaging-types" "0.4.4" - "@firebase/util" "0.2.43" + "@firebase/util" "0.2.44" idb "3.0.2" tslib "1.11.1" @@ -1130,16 +1156,16 @@ resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.0.12.tgz#15fa79e296b502e21054a66c9e7ded59398fd8a7" integrity sha512-eIDF7CHetOE5sc+hCaUebEn/2Aiaju7UkgZDTl7lNQHz5fK9wJ/11HaE8WdnDr//ngS3lQAGC2RB4lAZeEWraA== -"@firebase/performance@0.2.36": - version "0.2.36" - resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.2.36.tgz#341bad35e786a377a38c4b4165088ebd4f07d025" - integrity sha512-nMx3gT+ZD86MV5n460XFA1o75YYMGcs2MXrJa462rfUQtqOrtOOvdUvVtmE6cLrHsL4Y83B+VBWKHzACIPghPw== +"@firebase/performance@0.2.37": + version "0.2.37" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.2.37.tgz#d77be238553ed12465ef0ccdf5275474b8202321" + integrity sha512-BL4/19Hh5nyq6aaoo2b87rDHf2hSX/UOl0GBw7hDkWXYRodARtbQvIfhb+CZ8IlZn0Xg0x8SyNIpSCIp9UfYlA== dependencies: - "@firebase/component" "0.1.8" - "@firebase/installations" "0.4.6" - "@firebase/logger" "0.2.0" + "@firebase/component" "0.1.9" + "@firebase/installations" "0.4.7" + "@firebase/logger" "0.2.1" "@firebase/performance-types" "0.0.12" - "@firebase/util" "0.2.43" + "@firebase/util" "0.2.44" tslib "1.11.1" "@firebase/polyfill@0.3.33": @@ -1156,16 +1182,16 @@ resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.1.8.tgz#0c8d8a839621230053ba55704b5d1145bfe54daa" integrity sha512-K12IBHO7OD4gCW0FEqZL9zMqVAfS4+joC4YIn3bHezZfu3RL+Bw1wCb0cAD7RfDPcQxWJjxOHpce4YhuqSxPFA== -"@firebase/remote-config@0.1.17": - version "0.1.17" - resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.1.17.tgz#ac4a8c9def48d404bdfe72cdf47199360cd44d01" - integrity sha512-jIRHXih0krVTNGYMewFVIaX8WPE1iS06fV4oMMHCCSSforGodv535uVZZ41Il29Q+22zOcyJvahoc990V0cFoA== +"@firebase/remote-config@0.1.18": + version "0.1.18" + resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.1.18.tgz#2fb1f7b7f95b263824f5818470c27fb9854d4ac8" + integrity sha512-ufbhnP3O6bRYs74jFIyYZ0dPsv/PsMSmGs669Os5SkEdfjEWX8hnhssfuZCg5VfJQiCrqoSQD/KfPGACmeBcbQ== dependencies: - "@firebase/component" "0.1.8" - "@firebase/installations" "0.4.6" - "@firebase/logger" "0.2.0" + "@firebase/component" "0.1.9" + "@firebase/installations" "0.4.7" + "@firebase/logger" "0.2.1" "@firebase/remote-config-types" "0.1.8" - "@firebase/util" "0.2.43" + "@firebase/util" "0.2.44" tslib "1.11.1" "@firebase/storage-types@0.3.11": @@ -1173,14 +1199,14 @@ resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.3.11.tgz#98f6ced5460502ab12778ce71d4dc9bf0ab7f2ee" integrity sha512-EMOo5aeiJIa8eQ/VqjIa/DYlDcEJX1V84FOxmLfNWZIlmCSvcqx9E9mcNlOnoUB4iePqQjTMQRtKlIBvvEVhVg== -"@firebase/storage@0.3.30": - version "0.3.30" - resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.3.30.tgz#195f6bd9b526710b7446e430b71dfb82cf8b35cc" - integrity sha512-wapt4+NiEqTiLKPpsy+XbdLTN99pkqjf46Z7zqeS+vh+61cJsUT8M7YBfBb0ZN+dY6gnI5QNzviiKpykhJQbVA== +"@firebase/storage@0.3.31": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.3.31.tgz#399d8aab883be28ac73c792e6c34b44ba8ee498b" + integrity sha512-b5rwcMa89mFnKDlhFmGRC0QFpOgqGoNVn4klJDvSnpRGmwOcByQXoos8w1IWP0DW+EWhHcafy7DvUHFlr70onw== dependencies: - "@firebase/component" "0.1.8" + "@firebase/component" "0.1.9" "@firebase/storage-types" "0.3.11" - "@firebase/util" "0.2.43" + "@firebase/util" "0.2.44" tslib "1.11.1" "@firebase/util@0.2.43": @@ -1190,6 +1216,13 @@ dependencies: tslib "1.11.1" +"@firebase/util@0.2.44": + version "0.2.44" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.2.44.tgz#bdf031f2714761ed6062ba2c32edca9113a339af" + integrity sha512-yWnFdeuz7P0QC4oC77JyPdAQ/rTGPDfhHcR5WsoMsKBBHTyqEhaKWL9HeRird+p3AL9M4++ep0FYFNd1UKU3Wg== + dependencies: + tslib "1.11.1" + "@firebase/webchannel-wrapper@0.2.38": version "0.2.38" resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.38.tgz#1f0602cd73f7402ffc4d6116c811dfbb652caa73" @@ -5229,25 +5262,25 @@ firebase-tools@^8.0.0: winston "^3.0.0" ws "^7.2.3" -firebase@^7.13.1: - version "7.13.1" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-7.13.1.tgz#f9c05ef60341cf8f7796ad7b8f3181b31be6dcf5" - integrity sha512-v4Z7Wioy/7LMC8RJn1jNlOaUqLK7bUEva+Uf+qrbtFd7hM2rWLW+0IqHZBwPrQ5tI604uHj7IlhqAZEjm38AMw== +firebase@^7.13.2: + version "7.13.2" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-7.13.2.tgz#4a4af2b76514aecb2c4f7fb312fff7b828ab52bc" + integrity sha512-23auhESlkyW0q59BB1e9dVuK/eITLsQvzz2J4ImVDfHDIF4JnjNpVnoKgBsj1oOYtSnRE5QppJ8kZR3q9rIPaQ== dependencies: - "@firebase/analytics" "0.3.0" - "@firebase/app" "0.6.0" + "@firebase/analytics" "0.3.1" + "@firebase/app" "0.6.1" "@firebase/app-types" "0.6.0" - "@firebase/auth" "0.14.1" - "@firebase/database" "0.5.24" - "@firebase/firestore" "1.13.0" - "@firebase/functions" "0.4.38" - "@firebase/installations" "0.4.6" - "@firebase/messaging" "0.6.10" - "@firebase/performance" "0.2.36" + "@firebase/auth" "0.14.2" + "@firebase/database" "0.5.25" + "@firebase/firestore" "1.13.1" + "@firebase/functions" "0.4.39" + "@firebase/installations" "0.4.7" + "@firebase/messaging" "0.6.11" + "@firebase/performance" "0.2.37" "@firebase/polyfill" "0.3.33" - "@firebase/remote-config" "0.1.17" - "@firebase/storage" "0.3.30" - "@firebase/util" "0.2.43" + "@firebase/remote-config" "0.1.18" + "@firebase/storage" "0.3.31" + "@firebase/util" "0.2.44" flat-arguments@^1.0.0: version "1.0.2" @@ -9578,6 +9611,11 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" +proxy-polyfill@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/proxy-polyfill/-/proxy-polyfill-0.3.1.tgz#163d5283cf928dd8ddb5c5e88528e4ccd233496f" + integrity sha512-jywE1NIksgIGqZc4uF0QLbXGz2RcHQobsCkAW+8F0nr/6agap+TWksEAKyLnIBafPD88HT9qZR2ec0oomHdjcQ== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" diff --git a/src/analytics/analytics.module.ts b/src/analytics/analytics.module.ts index a1e470a6f..3c104d5d3 100644 --- a/src/analytics/analytics.module.ts +++ b/src/analytics/analytics.module.ts @@ -1,5 +1,5 @@ import { NgModule, Optional } from '@angular/core'; -import { UserTrackingService, ScreenTrackingService } from './analytics.service'; +import { ScreenTrackingService, UserTrackingService } from './analytics.service'; import { AngularFireAnalytics } from './analytics'; @NgModule({ @@ -12,6 +12,7 @@ export class AngularFireAnalyticsModule { @Optional() userTracking: UserTrackingService ) { // calling anything on analytics will eagerly load the SDK + // tslint:disable-next-line:no-unused-expression analytics.app; } } diff --git a/src/analytics/analytics.service.ts b/src/analytics/analytics.service.ts index c7df44ac6..ea00a572b 100644 --- a/src/analytics/analytics.service.ts +++ b/src/analytics/analytics.service.ts @@ -1,7 +1,17 @@ -import { Injectable, Optional, NgZone, OnDestroy, ComponentFactoryResolver, Inject, PLATFORM_ID, Injector, NgModuleFactory } from '@angular/core'; -import { Subscription, from, Observable, of } from 'rxjs'; -import { filter, withLatestFrom, switchMap, map, tap, pairwise, startWith, groupBy, mergeMap, observeOn } from 'rxjs/operators'; -import { Router, NavigationEnd, ActivationEnd, ROUTES } from '@angular/router'; +import { + ComponentFactoryResolver, + Inject, + Injectable, + Injector, + NgModuleFactory, + NgZone, + OnDestroy, + Optional, + PLATFORM_ID +} from '@angular/core'; +import { from, Observable, of, Subscription } from 'rxjs'; +import { filter, groupBy, map, mergeMap, observeOn, pairwise, startWith, switchMap, tap, withLatestFrom } from 'rxjs/operators'; +import { ActivationEnd, NavigationEnd, Router, ROUTES } from '@angular/router'; import { ɵAngularFireSchedulers } from '@angular/fire'; import { AngularFireAnalytics, DEBUG_MODE } from './analytics'; import { User } from 'firebase/app'; @@ -10,7 +20,7 @@ import { isPlatformBrowser, isPlatformServer } from '@angular/common'; const FIREBASE_EVENT_ORIGIN_KEY = 'firebase_event_origin'; const FIREBASE_PREVIOUS_SCREEN_CLASS_KEY = 'firebase_previous_class'; -const FIREBASE_PREVIOUS_SCREEN_INSTANCE_ID_KEY = 'firebase_previous_id'; +const FIREBASE_PREVIOUS_SCREEN_INSTANCE_ID_KEY = 'firebase_previous_id'; const FIREBASE_PREVIOUS_SCREEN_NAME_KEY = 'firebase_previous_screen'; const FIREBASE_SCREEN_CLASS_KEY = 'firebase_screen_class'; const FIREBASE_SCREEN_INSTANCE_ID_KEY = 'firebase_screen_id'; @@ -29,178 +39,191 @@ const SCREEN_INSTANCE_DELIMITER = '#'; const ANNOTATIONS = '__annotations__'; + +// this is an INT64 in iOS/Android but use INT32 cause javascript +let nextScreenInstanceID = Math.floor(Math.random() * (2 ** 32 - 1)) - 2 ** 31; + +const knownScreenInstanceIDs: { [key: string]: number } = {}; + +const getScreenInstanceID = (params: { [key: string]: any }) => { + // unique the screen class against the outlet name + const screenInstanceKey = [ + params[SCREEN_CLASS_KEY], + params[OUTLET_KEY] + ].join(SCREEN_INSTANCE_DELIMITER); + if (knownScreenInstanceIDs.hasOwnProperty(screenInstanceKey)) { + return knownScreenInstanceIDs[screenInstanceKey]; + } else { + const ret = nextScreenInstanceID++; + knownScreenInstanceIDs[screenInstanceKey] = ret; + return ret; + } +}; + @Injectable({ - providedIn: 'any' + providedIn: 'any' }) export class ScreenTrackingService implements OnDestroy { - private disposable: Subscription|undefined; - - constructor( - analytics: AngularFireAnalytics, - @Optional() router:Router, - @Optional() title:Title, - componentFactoryResolver: ComponentFactoryResolver, - @Inject(PLATFORM_ID) platformId:Object, - @Optional() @Inject(DEBUG_MODE) debugModeEnabled:boolean|null, - zone: NgZone, - injector: Injector - ) { - if (!router || !isPlatformBrowser(platformId)) { return this } - zone.runOutsideAngular(() => { - const activationEndEvents = router.events.pipe(filter(e => e instanceof ActivationEnd)); - const navigationEndEvents = router.events.pipe(filter(e => e instanceof NavigationEnd)); - this.disposable = navigationEndEvents.pipe( - withLatestFrom(activationEndEvents), - switchMap(([navigationEnd, activationEnd]) => { - // SEMVER: start using optional chains and nullish coalescing once we support newer typescript - const page_path = navigationEnd.url; - const screen_name = activationEnd.snapshot.routeConfig && activationEnd.snapshot.routeConfig.path || page_path; - const params = { - [SCREEN_NAME_KEY]: screen_name, - [PAGE_PATH_KEY]: page_path, - [FIREBASE_EVENT_ORIGIN_KEY]: EVENT_ORIGIN_AUTO, - [FIREBASE_SCREEN_NAME_KEY]: screen_name, - [OUTLET_KEY]: activationEnd.snapshot.outlet - }; - if (title) { - params[PAGE_TITLE_KEY] = title.getTitle() - } - const component = activationEnd.snapshot.component; - const routeConfig = activationEnd.snapshot.routeConfig; - const loadChildren = routeConfig && routeConfig.loadChildren; - // TODO figure out how to handle minification - if (typeof loadChildren === "string") { - // SEMVER: this is the older lazy load style "./path#ClassName", drop this when we drop old ng - // TODO is it worth seeing if I can look up the component factory selector from the module name? - // it's lazy so it's not registered with componentFactoryResolver yet... seems a pain for a depreciated style - return of({...params, [SCREEN_CLASS_KEY]: loadChildren.split('#')[1]}); - } else if (typeof component === 'string') { - return of({...params, [SCREEN_CLASS_KEY]: component }); - } else if (component) { - const componentFactory = componentFactoryResolver.resolveComponentFactory(component); - return of({...params, [SCREEN_CLASS_KEY]: componentFactory.selector }); - } else if (loadChildren) { - const loadedChildren = loadChildren(); - var loadedChildren$: Observable = (loadedChildren instanceof Observable) ? loadedChildren : from(Promise.resolve(loadedChildren)); - return loadedChildren$.pipe( - map(lazyModule => { - if (lazyModule instanceof NgModuleFactory) { - // AOT create an injector - const moduleRef = lazyModule.create(injector); - // INVESTIGATE is this the right way to get at the matching route? - const routes = moduleRef.injector.get(ROUTES); - const component = routes[0][0].component; // should i just be grabbing 0-0 here? - try { - const componentFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(component!); - return {...params, [SCREEN_CLASS_KEY]: componentFactory.selector}; - } catch(_) { - return {...params, [SCREEN_CLASS_KEY]: DEFAULT_SCREEN_CLASS}; - } - } else { - // JIT look at the annotations - // INVESTIGATE are there public APIs for this stuff? - const declarations = [].concat.apply([], (lazyModule[ANNOTATIONS] || []).map((f:any) => f.declarations)); - const selectors = [].concat.apply([], declarations.map((c:any) => (c[ANNOTATIONS] || []).map((f:any) => f.selector))); - // should I just be grabbing the selector like this or should i match against the route component? - // const routerModule = lazyModule.ngInjectorDef.imports.find(i => i.ngModule && ....); - // const route = routerModule.providers[0].find(p => p.provide == ROUTES).useValue[0]; - return {...params, [SCREEN_CLASS_KEY]: selectors[0] || DEFAULT_SCREEN_CLASS}; - } - }) - ); - } else { - return of({...params, [SCREEN_CLASS_KEY]: DEFAULT_SCREEN_CLASS}); - } - }), - map(params => ({ - [FIREBASE_SCREEN_CLASS_KEY]: params[SCREEN_CLASS_KEY], - [FIREBASE_SCREEN_INSTANCE_ID_KEY]: getScreenInstanceID(params), - ...params - })), - tap(params => { - // TODO perhaps I can be smarter about this, bubble events up to the nearest outlet? - if (params[OUTLET_KEY] == NG_PRIMARY_OUTLET) { - analytics.setCurrentScreen(params[SCREEN_NAME_KEY]); - analytics.updateConfig({ - [PAGE_PATH_KEY]: params[PAGE_PATH_KEY], - [SCREEN_CLASS_KEY]: params[SCREEN_CLASS_KEY] - }); - if (title) { - analytics.updateConfig({ [PAGE_TITLE_KEY]: params[PAGE_TITLE_KEY] }) - } - } - }), - groupBy(params => params[OUTLET_KEY]), - mergeMap(group => group.pipe(startWith(undefined), pairwise())), - map(([prior, current]) => prior ? { - [FIREBASE_PREVIOUS_SCREEN_CLASS_KEY]: prior[SCREEN_CLASS_KEY], - [FIREBASE_PREVIOUS_SCREEN_NAME_KEY]: prior[SCREEN_NAME_KEY], - [FIREBASE_PREVIOUS_SCREEN_INSTANCE_ID_KEY]: prior[FIREBASE_SCREEN_INSTANCE_ID_KEY], - ...current! - } : current!), - tap(params => debugModeEnabled && console.info(SCREEN_VIEW_EVENT, params)), - tap(params => zone.runOutsideAngular(() => analytics.logEvent(SCREEN_VIEW_EVENT, params))) - ).subscribe(); - }); + private disposable: Subscription | undefined; + + constructor( + analytics: AngularFireAnalytics, + @Optional() router: Router, + @Optional() title: Title, + componentFactoryResolver: ComponentFactoryResolver, + // tslint:disable-next-line:ban-types + @Inject(PLATFORM_ID) platformId: Object, + @Optional() @Inject(DEBUG_MODE) debugModeEnabled: boolean | null, + zone: NgZone, + injector: Injector + ) { + if (!router || !isPlatformBrowser(platformId)) { + return this; } - - ngOnDestroy() { - if (this.disposable) { this.disposable.unsubscribe(); } + zone.runOutsideAngular(() => { + const activationEndEvents = router.events.pipe(filter(e => e instanceof ActivationEnd)); + const navigationEndEvents = router.events.pipe(filter(e => e instanceof NavigationEnd)); + this.disposable = navigationEndEvents.pipe( + withLatestFrom(activationEndEvents), + switchMap(([navigationEnd, activationEnd]) => { + // SEMVER: start using optional chains and nullish coalescing once we support newer typescript + const pagePath = navigationEnd.url; + const screenName = activationEnd.snapshot.routeConfig && activationEnd.snapshot.routeConfig.path || pagePath; + const params = { + [SCREEN_NAME_KEY]: screenName, + [PAGE_PATH_KEY]: pagePath, + [FIREBASE_EVENT_ORIGIN_KEY]: EVENT_ORIGIN_AUTO, + [FIREBASE_SCREEN_NAME_KEY]: screenName, + [OUTLET_KEY]: activationEnd.snapshot.outlet + }; + if (title) { + params[PAGE_TITLE_KEY] = title.getTitle(); + } + const component = activationEnd.snapshot.component; + const routeConfig = activationEnd.snapshot.routeConfig; + const loadChildren = routeConfig && routeConfig.loadChildren; + // TODO figure out how to handle minification + if (typeof loadChildren === 'string') { + // SEMVER: this is the older lazy load style "./path#ClassName", drop this when we drop old ng + // TODO is it worth seeing if I can look up the component factory selector from the module name? + // it's lazy so it's not registered with componentFactoryResolver yet... seems a pain for a depreciated style + return of({ ...params, [SCREEN_CLASS_KEY]: loadChildren.split('#')[1] }); + } else if (typeof component === 'string') { + return of({ ...params, [SCREEN_CLASS_KEY]: component }); + } else if (component) { + const componentFactory = componentFactoryResolver.resolveComponentFactory(component); + return of({ ...params, [SCREEN_CLASS_KEY]: componentFactory.selector }); + } else if (loadChildren) { + const loadedChildren = loadChildren(); + const loadedChildren$: Observable = (loadedChildren instanceof Observable) ? + loadedChildren : + from(Promise.resolve(loadedChildren)); + return loadedChildren$.pipe( + map(lazyModule => { + if (lazyModule instanceof NgModuleFactory) { + // AOT create an injector + const moduleRef = lazyModule.create(injector); + // INVESTIGATE is this the right way to get at the matching route? + const routes = moduleRef.injector.get(ROUTES); + const component = routes[0][0].component; // should i just be grabbing 0-0 here? + try { + const componentFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(component); + return { ...params, [SCREEN_CLASS_KEY]: componentFactory.selector }; + } catch (_) { + return { ...params, [SCREEN_CLASS_KEY]: DEFAULT_SCREEN_CLASS }; + } + } else { + // JIT look at the annotations + // INVESTIGATE are there public APIs for this stuff? + const declarations = [].concat.apply([], (lazyModule[ANNOTATIONS] || []).map((f: any) => f.declarations)); + const selectors = [].concat.apply([], declarations.map((c: any) => (c[ANNOTATIONS] || []).map((f: any) => f.selector))); + // should I just be grabbing the selector like this or should i match against the route component? + // const routerModule = lazyModule.ngInjectorDef.imports.find(i => i.ngModule && ....); + // const route = routerModule.providers[0].find(p => p.provide == ROUTES).useValue[0]; + return { ...params, [SCREEN_CLASS_KEY]: selectors[0] || DEFAULT_SCREEN_CLASS }; + } + }) + ); + } else { + return of({ ...params, [SCREEN_CLASS_KEY]: DEFAULT_SCREEN_CLASS }); + } + }), + map(params => ({ + [FIREBASE_SCREEN_CLASS_KEY]: params[SCREEN_CLASS_KEY], + [FIREBASE_SCREEN_INSTANCE_ID_KEY]: getScreenInstanceID(params), + ...params + })), + tap(params => { + // TODO perhaps I can be smarter about this, bubble events up to the nearest outlet? + if (params[OUTLET_KEY] === NG_PRIMARY_OUTLET) { + analytics.setCurrentScreen(params[SCREEN_NAME_KEY]); + analytics.updateConfig({ + [PAGE_PATH_KEY]: params[PAGE_PATH_KEY], + [SCREEN_CLASS_KEY]: params[SCREEN_CLASS_KEY] + }); + if (title) { + analytics.updateConfig({ [PAGE_TITLE_KEY]: params[PAGE_TITLE_KEY] }); + } + } + }), + groupBy(params => params[OUTLET_KEY]), + // tslint:disable-next-line + mergeMap(group => group.pipe(startWith(undefined), pairwise())), + map(([prior, current]) => prior ? { + [FIREBASE_PREVIOUS_SCREEN_CLASS_KEY]: prior[SCREEN_CLASS_KEY], + [FIREBASE_PREVIOUS_SCREEN_NAME_KEY]: prior[SCREEN_NAME_KEY], + [FIREBASE_PREVIOUS_SCREEN_INSTANCE_ID_KEY]: prior[FIREBASE_SCREEN_INSTANCE_ID_KEY], + ...current + } : current), + // tslint:disable-next-line:no-console + tap(params => debugModeEnabled && console.info(SCREEN_VIEW_EVENT, params)), + tap(params => zone.runOutsideAngular(() => analytics.logEvent(SCREEN_VIEW_EVENT, params))) + ).subscribe(); + }); + } + + ngOnDestroy() { + if (this.disposable) { + this.disposable.unsubscribe(); } - + } + } @Injectable({ - providedIn: 'any' + providedIn: 'any' }) export class UserTrackingService implements OnDestroy { - private disposable: Subscription|undefined; - - // TODO a user properties injector - constructor( - analytics: AngularFireAnalytics, - zone: NgZone, - @Inject(PLATFORM_ID) platformId:Object - ) { - const schedulers = new ɵAngularFireSchedulers(zone); - - if (!isPlatformServer(platformId)) { - zone.runOutsideAngular(() => { - // @ts-ignore zap the import in the UMD - this.disposable = from(import('firebase/auth')).pipe( - observeOn(schedulers.outsideAngular), - switchMap(() => analytics.app), - map(app => app.auth()), - switchMap(auth => new Observable(auth.onAuthStateChanged.bind(auth))), - switchMap(user => analytics.setUserId(user ? user.uid : null!)) - ).subscribe(); - }); - } - } + private disposable: Subscription | undefined; + + // TODO a user properties injector + constructor( + analytics: AngularFireAnalytics, + zone: NgZone, + // tslint:disable-next-line:ban-types + @Inject(PLATFORM_ID) platformId: Object + ) { + const schedulers = new ɵAngularFireSchedulers(zone); - ngOnDestroy() { - if (this.disposable) { this.disposable.unsubscribe(); } + if (!isPlatformServer(platformId)) { + zone.runOutsideAngular(() => { + // @ts-ignore zap the import in the UMD + this.disposable = from(import('firebase/auth')).pipe( + observeOn(schedulers.outsideAngular), + switchMap(() => analytics.app), + map(app => app.auth()), + switchMap(auth => new Observable(auth.onAuthStateChanged.bind(auth))), + switchMap(user => analytics.setUserId(user ? user.uid : null)) + ).subscribe(); + }); } -} + } -// this is an INT64 in iOS/Android but use INT32 cause javascript -let nextScreenInstanceID = Math.floor(Math.random() * (2**32 - 1)) - 2**31; - -const knownScreenInstanceIDs: {[key:string]: number} = {}; - -const getScreenInstanceID = (params:{[key:string]: any}) => { - // unique the screen class against the outlet name - const screenInstanceKey = [ - params[SCREEN_CLASS_KEY], - params[OUTLET_KEY] - ].join(SCREEN_INSTANCE_DELIMITER); - if (knownScreenInstanceIDs.hasOwnProperty(screenInstanceKey)) { - return knownScreenInstanceIDs[screenInstanceKey]; - } else { - const ret = nextScreenInstanceID++; - knownScreenInstanceIDs[screenInstanceKey] = ret; - return ret; + ngOnDestroy() { + if (this.disposable) { + this.disposable.unsubscribe(); } -} \ No newline at end of file + } +} diff --git a/src/analytics/analytics.spec.ts b/src/analytics/analytics.spec.ts index b956dc76d..9804f993a 100644 --- a/src/analytics/analytics.spec.ts +++ b/src/analytics/analytics.spec.ts @@ -1,6 +1,6 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; -import { AngularFireAnalytics, AngularFireAnalyticsModule, COLLECTION_ENABLED, APP_VERSION, APP_NAME } from './public_api'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; +import { AngularFireAnalytics, AngularFireAnalyticsModule } from './public_api'; import { COMMON_CONFIG } from '../test-config'; import { rando } from '../firestore/utils.spec'; @@ -16,10 +16,9 @@ describe('AngularFireAnalytics', () => { AngularFireAnalyticsModule ] }); - inject([FirebaseApp, AngularFireAnalytics], (app_: FirebaseApp, _analytics: AngularFireAnalytics) => { - app = app_; - analytics = _analytics; - })(); + + app = TestBed.inject(FirebaseApp); + analytics = TestBed.inject(AngularFireAnalytics); }); afterEach(() => { @@ -34,4 +33,4 @@ describe('AngularFireAnalytics', () => { expect(analytics.app).toBeDefined(); }); -}); \ No newline at end of file +}); diff --git a/src/analytics/analytics.ts b/src/analytics/analytics.ts index 9862f32f5..3e6977cc9 100644 --- a/src/analytics/analytics.ts +++ b/src/analytics/analytics.ts @@ -1,11 +1,22 @@ -import { Injectable, Inject, Optional, NgZone, InjectionToken, PLATFORM_ID } from '@angular/core'; -import { of, empty, Observable } from 'rxjs'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { EMPTY, Observable, of } from 'rxjs'; import { isPlatformBrowser } from '@angular/common'; import { map, tap, shareReplay, switchMap, observeOn } from 'rxjs/operators'; -import { FirebaseAppConfig, FirebaseOptions, ɵAngularFireSchedulers, ɵlazySDKProxy, FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵfirebaseAppFactory, ɵPromiseProxy } from '@angular/fire'; -import { analytics } from 'firebase'; +import { + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵlazySDKProxy, + FIREBASE_OPTIONS, + FIREBASE_APP_NAME, + ɵfirebaseAppFactory, + ɵPromiseProxy +} from '@angular/fire'; +import { analytics } from 'firebase/app'; -export interface Config {[key:string]: any}; +export interface Config { + [key: string]: any; +} export const COLLECTION_ENABLED = new InjectionToken('angularfire2.analytics.analyticsCollectionEnabled'); export const APP_VERSION = new InjectionToken('angularfire2.analytics.appVersion'); @@ -21,11 +32,12 @@ const GTAG_CONFIG_COMMAND = 'config'; const GTAG_FUNCTION_NAME = 'gtag'; const DATA_LAYER_NAME = 'dataLayer'; -export interface AngularFireAnalytics extends ɵPromiseProxy {}; +export interface AngularFireAnalytics extends ɵPromiseProxy { +} let gtag: (...args: any[]) => void; let analyticsInitialized: Promise; -const analyticsInstanceCache: {[key:string]: Observable} = {}; +const analyticsInstanceCache: { [key: string]: Observable } = {}; @Injectable({ providedIn: 'any' @@ -35,34 +47,40 @@ export class AngularFireAnalytics { async updateConfig(config: Config) { await analyticsInitialized; gtag(GTAG_CONFIG_COMMAND, this.options[ANALYTICS_ID_FIELD], { ...config, update: true }); - }; + } constructor( - @Inject(FIREBASE_OPTIONS) private options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, - @Optional() @Inject(COLLECTION_ENABLED) analyticsCollectionEnabled:boolean|null, - @Optional() @Inject(APP_VERSION) providedAppVersion:string|null, - @Optional() @Inject(APP_NAME) providedAppName:string|null, - @Optional() @Inject(DEBUG_MODE) debugModeEnabled:boolean|null, - @Optional() @Inject(CONFIG) providedConfig:Config|null, - @Inject(PLATFORM_ID) platformId:Object, + @Inject(FIREBASE_OPTIONS) private options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, + @Optional() @Inject(COLLECTION_ENABLED) analyticsCollectionEnabled: boolean | null, + @Optional() @Inject(APP_VERSION) providedAppVersion: string | null, + @Optional() @Inject(APP_NAME) providedAppName: string | null, + @Optional() @Inject(DEBUG_MODE) debugModeEnabled: boolean | null, + @Optional() @Inject(CONFIG) providedConfig: Config | null, + // tslint:disable-next-line:ban-types + @Inject(PLATFORM_ID) platformId: Object, zone: NgZone ) { if (!analyticsInitialized) { if (isPlatformBrowser(platformId)) { - gtag = window[GTAG_FUNCTION_NAME] || function() { window[DATA_LAYER_NAME].push(arguments) }; + gtag = window[GTAG_FUNCTION_NAME] || ((...args: any[]) => { + window[DATA_LAYER_NAME].push(args); + }); window[DATA_LAYER_NAME] = window[DATA_LAYER_NAME] || []; analyticsInitialized = zone.runOutsideAngular(() => new Promise(resolve => { window[GTAG_FUNCTION_NAME] = (...args: any[]) => { - if (args[0] == 'js') { resolve() } + if (args[0] === 'js') { + resolve(); + } gtag(...args); - } + }; }) ); } else { - gtag = () => {}; + gtag = () => { + }; analyticsInitialized = Promise.resolve(); } } @@ -71,24 +89,34 @@ export class AngularFireAnalytics { if (!analytics) { analytics = of(undefined).pipe( observeOn(new ɵAngularFireSchedulers(zone).outsideAngular), - switchMap(() => isPlatformBrowser(platformId) ? import('firebase/analytics') : empty()), + switchMap(() => isPlatformBrowser(platformId) ? import('firebase/analytics') : EMPTY), map(() => ɵfirebaseAppFactory(options, zone, nameOrConfig)), map(app => app.analytics()), tap(analytics => { - if (analyticsCollectionEnabled === false) { analytics.setAnalyticsCollectionEnabled(false) } + if (analyticsCollectionEnabled === false) { + analytics.setAnalyticsCollectionEnabled(false); + } }), - shareReplay({ bufferSize: 1, refCount: false }), + shareReplay({ bufferSize: 1, refCount: false }) ); analyticsInstanceCache[options[ANALYTICS_ID_FIELD]] = analytics; } - if (providedConfig) { this.updateConfig(providedConfig) } - if (providedAppName) { this.updateConfig({ [APP_NAME_KEY]: providedAppName }) } - if (providedAppVersion) { this.updateConfig({ [APP_VERSION_KEY]: providedAppVersion }) } - if (debugModeEnabled) { this.updateConfig({ [DEBUG_MODE_KEY]: 1 }) } + if (providedConfig) { + this.updateConfig(providedConfig); + } + if (providedAppName) { + this.updateConfig({ [APP_NAME_KEY]: providedAppName }); + } + if (providedAppVersion) { + this.updateConfig({ [APP_VERSION_KEY]: providedAppVersion }); + } + if (debugModeEnabled) { + this.updateConfig({ [DEBUG_MODE_KEY]: 1 }); + } return ɵlazySDKProxy(this, analytics, zone); } -} \ No newline at end of file +} diff --git a/src/auth-guard/auth-guard.spec.ts b/src/auth-guard/auth-guard.spec.ts index c930b24cf..7c3ed2c45 100644 --- a/src/auth-guard/auth-guard.spec.ts +++ b/src/auth-guard/auth-guard.spec.ts @@ -1,39 +1,38 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, AngularFireModule } from '@angular/fire'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; import { COMMON_CONFIG } from '../test-config'; -import { AngularFireAuthGuardModule, AngularFireAuthGuard } from './public_api'; -import { RouterModule, Router } from '@angular/router'; +import { AngularFireAuthGuard, AngularFireAuthGuardModule } from './public_api'; +import { Router, RouterModule } from '@angular/router'; import { APP_BASE_HREF } from '@angular/common'; import { rando } from '../firestore/utils.spec'; describe('AngularFireAuthGuard', () => { - let app: FirebaseApp; - let router: Router; + let app: FirebaseApp; + let router: Router; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - AngularFireModule.initializeApp(COMMON_CONFIG, rando()), - AngularFireAuthGuardModule, - RouterModule.forRoot([ - { path: 'a', redirectTo: '/', canActivate: [AngularFireAuthGuard] } - ]) - ], - providers: [ - { provide: APP_BASE_HREF, useValue: 'http://localhost:4200/' } - ] - }); - inject([FirebaseApp, Router], (app_: FirebaseApp, router_: Router) => { - app = app_; - router = router_; - })(); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + AngularFireModule.initializeApp(COMMON_CONFIG, rando()), + AngularFireAuthGuardModule, + RouterModule.forRoot([ + { path: 'a', redirectTo: '/', canActivate: [AngularFireAuthGuard] } + ]) + ], + providers: [ + { provide: APP_BASE_HREF, useValue: 'http://localhost:4200/' } + ] }); - afterEach(done => { - app.delete().then(done, done); - }); - - it('should be injectable', () => { - expect(router).toBeTruthy(); - }); -}); \ No newline at end of file + app = TestBed.inject(FirebaseApp); + router = TestBed.inject(Router); + }); + + afterEach(done => { + app.delete().then(done, done); + }); + + it('should be injectable', () => { + expect(router).toBeTruthy(); + }); +}); diff --git a/src/auth-guard/auth-guard.ts b/src/auth-guard/auth-guard.ts index 93ebb13d4..f63aeb621 100644 --- a/src/auth-guard/auth-guard.ts +++ b/src/auth-guard/auth-guard.ts @@ -1,13 +1,23 @@ -import { Injectable, Inject, Optional, NgZone } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { Inject, Injectable, NgZone, Optional } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { Observable, of, pipe, UnaryFunction } from 'rxjs'; -import { map, switchMap, take, observeOn, shareReplay } from 'rxjs/operators' +import { map, observeOn, shareReplay, switchMap, take } from 'rxjs/operators'; import { User } from 'firebase/app'; -import { ɵAngularFireSchedulers, FirebaseOptions, FirebaseAppConfig, FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵfirebaseAppFactory } from '@angular/fire'; +import { + ɵAngularFireSchedulers, + FirebaseOptions, + FirebaseAppConfig, + FIREBASE_OPTIONS, + FIREBASE_APP_NAME, + ɵfirebaseAppFactory, + ɵkeepUnstableUntilFirstFactory +} from '@angular/fire'; export type AuthPipeGenerator = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => AuthPipe; export type AuthPipe = UnaryFunction, Observable>; +export const loggedIn: AuthPipe = map(user => !!user); + @Injectable({ providedIn: 'any' }) @@ -16,22 +26,26 @@ export class AngularFireAuthGuard implements CanActivate { authState: Observable; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string|FirebaseAppConfig|null|undefined, zone: NgZone, private router: Router ) { + + const schedulers = new ɵAngularFireSchedulers(zone); + const keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(schedulers); + const auth = of(undefined).pipe( observeOn(new ɵAngularFireSchedulers(zone).outsideAngular), switchMap(() => zone.runOutsideAngular(() => import('firebase/auth'))), - observeOn(new ɵAngularFireSchedulers(zone).insideAngular), map(() => ɵfirebaseAppFactory(options, zone, nameOrConfig)), - map(app => app.auth()), + map(app => zone.runOutsideAngular(() => app.auth())), shareReplay({ bufferSize: 1, refCount: false }), ); this.authState = auth.pipe( - switchMap(auth => new Observable(auth.onAuthStateChanged.bind(auth))) + switchMap(auth => new Observable(auth.onAuthStateChanged.bind(auth))), + keepUnstableUntilFirst ); } @@ -40,7 +54,7 @@ export class AngularFireAuthGuard implements CanActivate { return this.authState.pipe( take(1), authPipeFactory(next, state), - map(can => typeof can == "boolean" ? can : this.router.createUrlTree(can)) + map(can => typeof can === 'boolean' ? can : this.router.createUrlTree(can as any[])) ); } @@ -50,11 +64,14 @@ export const canActivate = (pipe: AuthPipeGenerator) => ({ canActivate: [ AngularFireAuthGuard ], data: { authGuardPipe: pipe } }); -export const loggedIn: AuthPipe = map(user => !!user); + export const isNotAnonymous: AuthPipe = map(user => !!user && !user.isAnonymous); export const idTokenResult = switchMap((user: User|null) => user ? user.getIdTokenResult() : of(null)); export const emailVerified: AuthPipe = map(user => !!user && user.emailVerified); export const customClaims = pipe(idTokenResult, map(idTokenResult => idTokenResult ? idTokenResult.claims : [])); -export const hasCustomClaim = (claim:string) => pipe(customClaims, map(claims => claims.hasOwnProperty(claim))); -export const redirectUnauthorizedTo = (redirect: any[]) => pipe(loggedIn, map(loggedIn => loggedIn || redirect)); -export const redirectLoggedInTo = (redirect: any[]) => pipe(loggedIn, map(loggedIn => loggedIn && redirect || true)); +export const hasCustomClaim: (claim: string) => AuthPipe = + (claim) => pipe(customClaims, map(claims => claims.hasOwnProperty(claim))); +export const redirectUnauthorizedTo: (redirect: any[]) => AuthPipe = + (redirect) => pipe(loggedIn, map(loggedIn => loggedIn || redirect)); +export const redirectLoggedInTo: (redirect: any[]) => AuthPipe = + (redirect) => pipe(loggedIn, map(loggedIn => loggedIn && redirect || true)); diff --git a/src/auth-guard/public_api.ts b/src/auth-guard/public_api.ts index f939652ac..468fd9657 100644 --- a/src/auth-guard/public_api.ts +++ b/src/auth-guard/public_api.ts @@ -1,2 +1,2 @@ export * from './auth-guard'; -export * from './auth-guard.module'; \ No newline at end of file +export * from './auth-guard.module'; diff --git a/src/auth/auth.spec.ts b/src/auth/auth.spec.ts index a5e04572e..70aefc9e8 100644 --- a/src/auth/auth.spec.ts +++ b/src/auth/auth.spec.ts @@ -1,30 +1,20 @@ import { User } from 'firebase/app'; -import { Observable, Subject } from 'rxjs' -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; +import { Observable, Subject } from 'rxjs'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; import { AngularFireAuth, AngularFireAuthModule } from './public_api'; import { COMMON_CONFIG } from '../test-config'; -import { take, skip } from 'rxjs/operators'; import 'firebase/auth'; import { rando } from '../firestore/utils.spec'; -function authTake(auth: Observable, count: number): Observable { - return take.call(auth, 1); -} - -function authSkip(auth: Observable, count: number): Observable { - return skip.call(auth, 1); -} - -const firebaseUser = { +const firebaseUser = { uid: '12345', providerData: [{ displayName: 'jeffbcrossyface' }] -}; +} as User; describe('AngularFireAuth', () => { let app: FirebaseApp; let afAuth: AngularFireAuth; - let authSpy: jasmine.Spy; let mockAuthState: Subject; beforeEach(() => { @@ -34,18 +24,17 @@ describe('AngularFireAuth', () => { AngularFireAuthModule ] }); - inject([FirebaseApp, AngularFireAuth], (app_: FirebaseApp, _auth: AngularFireAuth) => { - app = app_; - afAuth = _auth; - })(); + + app = TestBed.inject(FirebaseApp); + afAuth = TestBed.inject(AngularFireAuth); mockAuthState = new Subject(); - //@ts-ignore + // @ts-ignore spyOn(afAuth, 'authState').and.returnValue(mockAuthState); - //@ts-ignore + // @ts-ignore spyOn(afAuth, 'idToken').and.returnValue(mockAuthState); - (afAuth).authState = mockAuthState as Observable; - (afAuth).idToken = mockAuthState as Observable; + (afAuth as any).authState = mockAuthState as Observable; + (afAuth as any).idToken = mockAuthState as Observable; }); afterEach(() => { @@ -55,16 +44,16 @@ describe('AngularFireAuth', () => { describe('Zones', () => { it('should call operators and subscriber in the same zone as when service was initialized', (done) => { // Initialize the app outside of the zone, to mimick real life behavior. - let ngZone = Zone.current.fork({ + const ngZone = Zone.current.fork({ name: 'ngZone' }); ngZone.run(() => { const subs = [ - afAuth.authState.subscribe(user => { + afAuth.authState.subscribe(() => { expect(Zone.current.name).toBe('ngZone'); done(); }, done.fail), - afAuth.authState.subscribe(user => { + afAuth.authState.subscribe(() => { expect(Zone.current.name).toBe('ngZone'); done(); }, done.fail) @@ -87,36 +76,44 @@ describe('AngularFireAuth', () => { let count = 0; // Check that the first value is null and second is the auth user - const subs = afAuth.authState.subscribe(user => { - if (count === 0) { - expect(user).toBe(null!); - count = count + 1; - mockAuthState.next(firebaseUser); - } else { - expect(user).toEqual(firebaseUser); - subs.unsubscribe(); - done(); - } - }, done, done.fail); - mockAuthState.next(null!); + const subs = afAuth.authState.subscribe({ + next: (user => { + if (count === 0) { + expect(user).toBe(null); + count = count + 1; + mockAuthState.next(firebaseUser); + } else { + expect(user).toEqual(firebaseUser); + subs.unsubscribe(); + done(); + } + }), + error: done, + complete: done.fail + }); + mockAuthState.next(null); }); it('should emit auth updates through idToken', (done: any) => { let count = 0; // Check that the first value is null and second is the auth user - const subs = afAuth.idToken.subscribe(user => { - if (count === 0) { - expect(user).toBe(null!); - count = count + 1; - mockAuthState.next(firebaseUser); - } else { - expect(user).toEqual(firebaseUser); - subs.unsubscribe(); - done(); - } - }, done, done.fail); - mockAuthState.next(null!); + const subs = afAuth.idToken.subscribe({ + next: user => { + if (count === 0) { + expect(user).toBe(null); + count = count + 1; + mockAuthState.next(firebaseUser); + } else { + expect(user as any).toEqual(firebaseUser); + subs.unsubscribe(); + done(); + } + }, + error: done, + complete: done.fail + }); + mockAuthState.next(null); }); }); @@ -138,10 +135,9 @@ describe('AngularFireAuth with different app', () => { { provide: FIREBASE_OPTIONS, useValue: COMMON_CONFIG } ] }); - inject([FirebaseApp, AngularFireAuth], (app_: FirebaseApp, _afAuth: AngularFireAuth) => { - app = app_; - afAuth = _afAuth; - })(); + + app = TestBed.inject(FirebaseApp); + afAuth = TestBed.inject(AngularFireAuth); }); afterEach(() => { diff --git a/src/auth/auth.ts b/src/auth/auth.ts index aa5c52b91..93eb9cc28 100644 --- a/src/auth/auth.ts +++ b/src/auth/auth.ts @@ -1,10 +1,20 @@ import { Injectable, Inject, Optional, NgZone, PLATFORM_ID } from '@angular/core'; import { Observable, of, from } from 'rxjs'; -import { switchMap, map, observeOn, shareReplay } from 'rxjs/operators'; -import { FIREBASE_OPTIONS, FIREBASE_APP_NAME, FirebaseOptions, FirebaseAppConfig, ɵPromiseProxy, ɵlazySDKProxy, ɵfirebaseAppFactory, ɵAngularFireSchedulers, ɵkeepUnstableUntilFirstFactory } from '@angular/fire'; +import { switchMap, map, observeOn, shareReplay, first } from 'rxjs/operators'; +import { + FIREBASE_OPTIONS, + FIREBASE_APP_NAME, + FirebaseOptions, + FirebaseAppConfig, + ɵPromiseProxy, + ɵlazySDKProxy, + ɵfirebaseAppFactory, + ɵAngularFireSchedulers, + ɵkeepUnstableUntilFirstFactory +} from '@angular/fire'; import { User, auth } from 'firebase/app'; -export interface AngularFireAuth extends ɵPromiseProxy {}; +export interface AngularFireAuth extends ɵPromiseProxy {} @Injectable({ providedIn: 'any' @@ -34,31 +44,37 @@ export class AngularFireAuth { public readonly idTokenResult: Observable; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string|FirebaseAppConfig|null|undefined, + // tslint:disable-next-line:ban-types @Inject(PLATFORM_ID) platformId: Object, zone: NgZone ) { const schedulers = new ɵAngularFireSchedulers(zone); - const keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(schedulers, platformId); + const keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(schedulers); const auth = of(undefined).pipe( observeOn(schedulers.outsideAngular), switchMap(() => zone.runOutsideAngular(() => import('firebase/auth'))), map(() => ɵfirebaseAppFactory(options, zone, nameOrConfig)), - map(app => app.auth()), + map(app => zone.runOutsideAngular(() => app.auth())), shareReplay({ bufferSize: 1, refCount: false }), ); + // HACK, as we're exporting auth.Auth, rather than auth, developers importing firebase.auth + // (e.g, `import { auth } from 'firebase/app'`) are getting an undefined auth object unexpectedly + // as we're completely lazy. Let's eagerly load the Auth SDK here. + // There could potentially be race conditions still... but this greatly decreases the odds while + // we reevaluate the API. + const _ = auth.pipe(first()).subscribe(); + this.authState = auth.pipe( - observeOn(schedulers.outsideAngular), - switchMap(auth => new Observable(auth.onAuthStateChanged.bind(auth))), + switchMap(auth => zone.runOutsideAngular(() => new Observable(auth.onAuthStateChanged.bind(auth)))), keepUnstableUntilFirst ); this.user = auth.pipe( - observeOn(schedulers.outsideAngular), - switchMap(auth => new Observable(auth.onIdTokenChanged.bind(auth))), + switchMap(auth => zone.runOutsideAngular(() => new Observable(auth.onIdTokenChanged.bind(auth)))), keepUnstableUntilFirst ); diff --git a/src/core/angularfire2.spec.ts b/src/core/angularfire2.spec.ts index f90910a25..d62d0b481 100644 --- a/src/core/angularfire2.spec.ts +++ b/src/core/angularfire2.spec.ts @@ -1,24 +1,22 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { PlatformRef, NgModule, CompilerFactory, NgZone } from '@angular/core'; -import { FirebaseApp, AngularFireModule } from './public_api'; -import { Subscription, Observable, Subject, of } from 'rxjs'; +import { TestBed } from '@angular/core/testing'; +import { CompilerFactory, NgModule, NgZone, PlatformRef } from '@angular/core'; +import { AngularFireModule, FirebaseApp } from './public_api'; +import { Observable, of, Subject } from 'rxjs'; import { COMMON_CONFIG } from '../test-config'; import { BrowserModule } from '@angular/platform-browser'; import { database } from 'firebase/app'; -import { ɵZoneScheduler, ɵkeepUnstableUntilFirstFactory, ɵAngularFireSchedulers } from './angularfire2'; -import { ɵPLATFORM_BROWSER_ID, ɵPLATFORM_SERVER_ID } from '@angular/common'; -import { tap } from 'rxjs/operators'; +import { ɵAngularFireSchedulers, ɵkeepUnstableUntilFirstFactory, ɵZoneScheduler } from './angularfire2'; +import { tap } from 'rxjs/operators'; import { TestScheduler } from 'rxjs/testing'; import { rando } from '../firestore/utils.spec'; describe('angularfire', () => { - let subscription:Subscription; let app: FirebaseApp; let rootRef: database.Reference; let questionsRef: database.Reference; let listOfQuestionsRef: database.Reference; let defaultPlatform: PlatformRef; - let appName:string; + let appName: string; beforeEach(() => { @@ -28,27 +26,21 @@ describe('angularfire', () => { imports: [AngularFireModule.initializeApp(COMMON_CONFIG, appName)] }); - inject([FirebaseApp, PlatformRef], (_app: FirebaseApp, _platform: PlatformRef) => { - app = _app; - rootRef = app.database!().ref(); - questionsRef = rootRef.child('questions'); - listOfQuestionsRef = rootRef.child('list-of-questions'); - defaultPlatform = _platform; - })(); - + app = TestBed.inject(FirebaseApp); + defaultPlatform = TestBed.inject(PlatformRef); + rootRef = app.database().ref(); + questionsRef = rootRef.child('questions'); + listOfQuestionsRef = rootRef.child('list-of-questions'); }); afterEach(() => { - rootRef.remove() - if(subscription && !subscription.closed) { - subscription.unsubscribe(); - } + rootRef.remove(); app.delete(); }); describe('ZoneScheduler', () => { it('should execute the scheduled work inside the specified zone', done => { - let ngZone = Zone.current.fork({ + const ngZone = Zone.current.fork({ name: 'ngZone' }); const rootZone = Zone.current; @@ -64,11 +56,11 @@ describe('angularfire', () => { }); it('should execute nested scheduled work inside the specified zone', done => { - const testScheduler = new TestScheduler(null!); + const testScheduler = new TestScheduler(null); testScheduler.run(helpers => { const outsideAngularScheduler = new ɵZoneScheduler(Zone.current, testScheduler); - let ngZone = Zone.current.fork({ + const ngZone = Zone.current.fork({ name: 'ngZone' }); @@ -97,13 +89,13 @@ describe('angularfire', () => { helpers.flush(); done(); expect(callbacksRan).toEqual(3); - }) + }); }); helpers.flush(); }); }); - }) - }) + }); + }); describe('keepUnstableUntilFirstFactory', () => { let schedulers: ɵAngularFireSchedulers; @@ -121,10 +113,10 @@ describe('angularfire', () => { runTask: insideZone.run.bind(insideZone) } as NgZone; schedulers = new ɵAngularFireSchedulers(ngZone); - }) + }); it('should re-schedule emissions asynchronously', done => { - const keepUnstableOp = ɵkeepUnstableUntilFirstFactory(schedulers, ɵPLATFORM_SERVER_ID); + const keepUnstableOp = ɵkeepUnstableUntilFirstFactory(schedulers); let ran = false; of(null).pipe( @@ -133,38 +125,39 @@ describe('angularfire', () => { ).subscribe(() => { expect(ran).toEqual(true); done(); - }, () => fail("Should not error")); + }, () => fail('Should not error')); expect(ran).toEqual(false); }); - [ɵPLATFORM_SERVER_ID, ɵPLATFORM_BROWSER_ID].map(platformId => - it(`should subscribe outside angular and observe inside angular (${platformId})`, done => { - const keepUnstableOp = ɵkeepUnstableUntilFirstFactory(schedulers, platformId); - - insideZone.run(() => { - new Observable(s => { - expect(Zone.current).toEqual(outsideZone); - s.next("test"); - }).pipe( - keepUnstableOp, - tap(() => { - expect(Zone.current).toEqual(insideZone); - }) - ).subscribe(() => { + it(`should subscribe outside angular and observe inside angular`, done => { + + const keepUnstableOp = ɵkeepUnstableUntilFirstFactory(schedulers); + + insideZone.run(() => { + new Observable(s => { + expect(Zone.current).toEqual(outsideZone); + s.next('test'); + }).pipe( + keepUnstableOp, + tap(() => { expect(Zone.current).toEqual(insideZone); - done(); - }, err => { - fail(err); - }); + }) + ).subscribe(() => { + expect(Zone.current).toEqual(insideZone); + done(); + }, err => { + fail(err); }); - }) - ); + }); + + }); it('should block until first emission', done => { - const testScheduler = new TestScheduler(null!); + const testScheduler = new TestScheduler(null); testScheduler.run(helpers => { const outsideZone = Zone.current; + // tslint:disable-next-line:no-string-literal const taskTrack = new Zone['TaskTrackingZoneSpec'](); const insideZone = Zone.current.fork(taskTrack); const trackingSchedulers: ɵAngularFireSchedulers = { @@ -175,14 +168,18 @@ describe('angularfire', () => { runTask: insideZone.run.bind(insideZone) } as NgZone, outsideAngular: new ɵZoneScheduler(outsideZone, testScheduler), - insideAngular: new ɵZoneScheduler(insideZone, testScheduler), + insideAngular: new ɵZoneScheduler(insideZone, testScheduler) }; - const keepUnstableOp = ɵkeepUnstableUntilFirstFactory(trackingSchedulers, ɵPLATFORM_SERVER_ID); + const keepUnstableOp = ɵkeepUnstableUntilFirstFactory(trackingSchedulers); const s = new Subject(); s.pipe( - keepUnstableOp, - ).subscribe(() => { }, err => { fail(err); }, () => { }); + keepUnstableOp + ).subscribe(() => { + }, err => { + fail(err); + }, () => { + }); // Flush to ensure all async scheduled functions are run helpers.flush(); @@ -202,9 +199,9 @@ describe('angularfire', () => { }, 150); }); - }) + }); - }) + }); describe('FirebaseApp', () => { @@ -223,13 +220,15 @@ describe('angularfire', () => { imports: [ AngularFireModule.initializeApp(COMMON_CONFIG, appName), BrowserModule - ]}) + ] + }) class MyModule { - ngDoBootstrap() {} + ngDoBootstrap() { + } } const compilerFactory: CompilerFactory = - defaultPlatform.injector.get(CompilerFactory, null); + defaultPlatform.injector.get(CompilerFactory, null); const moduleFactory = compilerFactory.createCompiler().compileModuleSync(MyModule); defaultPlatform.bootstrapModuleFactory(moduleFactory) @@ -237,10 +236,10 @@ describe('angularfire', () => { const ref = moduleRef.injector.get(FirebaseApp); expect(ref.name).toEqual(app.name); }).then(done, e => { - fail(e); - done() - }); - }) + fail(e); + done(); + }); + }); } }); diff --git a/src/core/angularfire2.ts b/src/core/angularfire2.ts index a8fa36d67..34841d582 100644 --- a/src/core/angularfire2.ts +++ b/src/core/angularfire2.ts @@ -1,14 +1,27 @@ import { NgZone } from '@angular/core'; -import { Observable, Subscription, SchedulerLike, SchedulerAction, queueScheduler, Operator, Subscriber, TeardownLogic, asyncScheduler } from 'rxjs'; -import { subscribeOn, observeOn, tap } from 'rxjs/operators'; - -function noop() { } +import { + asyncScheduler, + Observable, + Operator, + queueScheduler, + SchedulerAction, + SchedulerLike, + Subscriber, + Subscription, + TeardownLogic +} from 'rxjs'; +import { observeOn, subscribeOn, tap } from 'rxjs/operators'; + +function noop() { +} /** * Schedules tasks so that they are invoked inside the Zone that is passed in the constructor. */ +// tslint:disable-next-line:class-name export class ɵZoneScheduler implements SchedulerLike { - constructor(private zone: any, private delegate: any = queueScheduler) { } + constructor(private zone: any, private delegate: any = queueScheduler) { + } now() { return this.delegate.now(); @@ -18,36 +31,38 @@ export class ɵZoneScheduler implements SchedulerLike { const targetZone = this.zone; // Wrap the specified work function to make sure that if nested scheduling takes place the // work is executed in the correct zone - const workInZone = function (this: SchedulerAction, state: any) { + const workInZone = function(this: SchedulerAction, state: any) { targetZone.runGuarded(() => { work.apply(this, [state]); }); - } + }; // Scheduling itself needs to be run in zone to ensure setInterval calls for async scheduling are done // inside the correct zone. This scheduler needs to schedule asynchronously always to ensure that // firebase emissions are never synchronous. Specifying a delay causes issues with the queueScheduler delegate. - return this.delegate.schedule(workInZone, delay, state) + return this.delegate.schedule(workInZone, delay, state); } } +// tslint:disable-next-line:class-name export class ɵBlockUntilFirstOperator implements Operator { private task: MacroTask | null = null; - constructor(private zone: any) { } + constructor(private zone: any) { + } call(subscriber: Subscriber, source: Observable): TeardownLogic { const unscheduleTask = this.unscheduleTask.bind(this); this.task = this.zone.run(() => Zone.current.scheduleMacroTask('firebaseZoneBlock', noop, {}, noop, noop)); return source.pipe( - tap(unscheduleTask, unscheduleTask, unscheduleTask) + tap({ next: unscheduleTask, complete: unscheduleTask, error: unscheduleTask }) ).subscribe(subscriber).add(unscheduleTask); } private unscheduleTask() { // maybe this is a race condition, invoke in a timeout - // hold for 10ms while I try to figure out what is going on + // hold for 10ms while I try to figure out what is going on setTimeout(() => { if (this.task != null && this.task.state === 'scheduled') { this.task.invoke(); @@ -57,6 +72,7 @@ export class ɵBlockUntilFirstOperator implements Operator { } } +// tslint:disable-next-line:class-name export class ɵAngularFireSchedulers { public readonly outsideAngular: ɵZoneScheduler; public readonly insideAngular: ɵZoneScheduler; @@ -73,10 +89,7 @@ export class ɵAngularFireSchedulers { * value from firebase but doesn't block the zone forever since the firebase subscription * is still alive. */ -export function ɵkeepUnstableUntilFirstFactory( - schedulers: ɵAngularFireSchedulers, - platformId: Object -) { +export function ɵkeepUnstableUntilFirstFactory(schedulers: ɵAngularFireSchedulers) { return function keepUnstableUntilFirst(obs$: Observable): Observable { obs$ = obs$.lift( new ɵBlockUntilFirstOperator(schedulers.ngZone) @@ -90,17 +103,23 @@ export function ɵkeepUnstableUntilFirstFactory( // INVESTIGATE https://github.com/angular/angularfire/pull/2315 // share() ); - } + }; } +// tslint:disable:ban-types type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; -type PromiseReturningFunctionPropertyNames = { [K in FunctionPropertyNames]: ReturnType extends Promise ? K : never }[FunctionPropertyNames]; -type NonPromiseReturningFunctionPropertyNames = { [K in FunctionPropertyNames]: ReturnType extends Promise ? never : K }[FunctionPropertyNames]; +type PromiseReturningFunctionPropertyNames = { + [K in FunctionPropertyNames]: ReturnType extends Promise ? K : never +}[FunctionPropertyNames]; +type NonPromiseReturningFunctionPropertyNames = { + [K in FunctionPropertyNames]: ReturnType extends Promise ? never : K +}[FunctionPropertyNames]; type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; +// tslint:enable:ban-types export type ɵPromiseProxy = { [K in NonFunctionPropertyNames]: Promise } & { [K in NonPromiseReturningFunctionPropertyNames]: (...args: Parameters) => Promise> } & - { [K in PromiseReturningFunctionPropertyNames ]: (...args: Parameters) => ReturnType }; + { [K in PromiseReturningFunctionPropertyNames]: (...args: Parameters) => ReturnType }; // DEBUG quick debugger function for inline logging that typescript doesn't complain about @@ -117,16 +136,21 @@ const noopFunctions = ['ngOnDestroy']; // right now it's fairly simple but I'm sure this will grow in complexity export const ɵlazySDKProxy = (klass: any, observable: Observable, zone: NgZone) => { return new Proxy(klass, { - get: (_, name:string) => zone.runOutsideAngular(() => { - if (klass[name]) { return klass[name] } - if (noopFunctions.includes(name)) { return () => {} } - let promise = observable.toPromise().then(mod => { + get: (_, name: string) => zone.runOutsideAngular(() => { + if (klass[name]) { + return klass[name]; + } + if (noopFunctions.includes(name)) { + return () => { + }; + } + const promise = observable.toPromise().then(mod => { const ret = mod && mod[name]; // TODO move to proper type guards - if (typeof ret == 'function') { + if (typeof ret === 'function') { return ret.bind(mod); } else if (ret && ret.then) { - return ret.then((res:any) => zone.run(() => res)); + return ret.then((res: any) => zone.run(() => res)); } else { return zone.run(() => ret); } @@ -134,10 +158,10 @@ export const ɵlazySDKProxy = (klass: any, observable: Observable, zone: Ng // recurse the proxy return new Proxy(() => undefined, { get: (_, name) => promise[name], - // TODO handle callbacks as transparently as I can + // TODO handle callbacks as transparently as I can apply: (self, _, args) => promise.then(it => it && it(...args)) } - ) + ); }) - }) -}; \ No newline at end of file + }); +}; diff --git a/src/core/firebase.app.module.ts b/src/core/firebase.app.module.ts index e3b8311e5..dc39f1894 100644 --- a/src/core/firebase.app.module.ts +++ b/src/core/firebase.app.module.ts @@ -1,69 +1,76 @@ -import { InjectionToken, NgModule, Optional, NgZone, VERSION as NG_VERSION, Version, PLATFORM_ID, Inject } from '@angular/core'; -import { app, auth, database, messaging, storage, firestore, functions, analytics, performance, remoteConfig } from 'firebase/app'; +import { Inject, InjectionToken, NgModule, NgZone, Optional, PLATFORM_ID, VERSION as NG_VERSION, Version } from '@angular/core'; import * as firebase from 'firebase/app'; +import { analytics, app, auth, database, firestore, functions, messaging, performance, remoteConfig, storage } from 'firebase/app'; // INVESTIGATE Public types don't expose FirebaseOptions or FirebaseAppConfig, is this the case anylonger? -export interface FirebaseOptions {[key:string]: any}; -export interface FirebaseAppConfig {[key:string]: any}; +export interface FirebaseOptions { + [key: string]: any; +} + +export interface FirebaseAppConfig { + [key: string]: any; +} export const FIREBASE_OPTIONS = new InjectionToken('angularfire2.app.options'); -export const FIREBASE_APP_NAME = new InjectionToken('angularfire2.app.nameOrConfig'); +export const FIREBASE_APP_NAME = new InjectionToken('angularfire2.app.nameOrConfig'); // Have to implement as we need to return a class from the provider, we should consider exporting // this in the firebase/app types as this is our highest risk of breaks export class FirebaseApp implements Partial { - name: string; - options: {}; - analytics: () => analytics.Analytics; - auth: () => auth.Auth; - database: (databaseURL?: string) => database.Database; - messaging: () => messaging.Messaging; - performance: () => performance.Performance; - storage: (storageBucket?: string) => storage.Storage; - delete: () => Promise; - firestore: () => firestore.Firestore; - functions: (region?: string) => functions.Functions; - remoteConfig: () => remoteConfig.RemoteConfig; + name: string; + options: {}; + analytics: () => analytics.Analytics; + auth: () => auth.Auth; + database: (databaseURL?: string) => database.Database; + messaging: () => messaging.Messaging; + performance: () => performance.Performance; + storage: (storageBucket?: string) => storage.Storage; + delete: () => Promise; + firestore: () => firestore.Firestore; + functions: (region?: string) => functions.Functions; + remoteConfig: () => remoteConfig.RemoteConfig; } export const VERSION = new Version('ANGULARFIRE2_VERSION'); -export function ɵfirebaseAppFactory(options: FirebaseOptions, zone: NgZone, nameOrConfig?: string|FirebaseAppConfig|null) { - const name = typeof nameOrConfig === 'string' && nameOrConfig || '[DEFAULT]'; - const config = typeof nameOrConfig === 'object' && nameOrConfig || {}; - config.name = config.name || name; - // Added any due to some inconsistency between @firebase/app and firebase types - const existingApp = firebase.apps.filter(app => app && app.name === config.name)[0] as any; - // We support FirebaseConfig, initializeApp's public type only accepts string; need to cast as any - // Could be solved with https://github.com/firebase/firebase-js-sdk/pull/1206 - return (existingApp || zone.runOutsideAngular(() => firebase.initializeApp(options, config as any))) as FirebaseApp; +export function ɵfirebaseAppFactory(options: FirebaseOptions, zone: NgZone, nameOrConfig?: string | FirebaseAppConfig | null) { + const name = typeof nameOrConfig === 'string' && nameOrConfig || '[DEFAULT]'; + const config = typeof nameOrConfig === 'object' && nameOrConfig || {}; + config.name = config.name || name; + // Added any due to some inconsistency between @firebase/app and firebase types + const existingApp = firebase.apps.filter(app => app && app.name === config.name)[0] as any; + // We support FirebaseConfig, initializeApp's public type only accepts string; need to cast as any + // Could be solved with https://github.com/firebase/firebase-js-sdk/pull/1206 + return (existingApp || zone.runOutsideAngular(() => firebase.initializeApp(options, config as any))) as FirebaseApp; } -const FirebaseAppProvider = { - provide: FirebaseApp, - useFactory: ɵfirebaseAppFactory, - deps: [ - FIREBASE_OPTIONS, - NgZone, - [new Optional(), FIREBASE_APP_NAME] - ] +const FIREBASE_APP_PROVIDER = { + provide: FirebaseApp, + useFactory: ɵfirebaseAppFactory, + deps: [ + FIREBASE_OPTIONS, + NgZone, + [new Optional(), FIREBASE_APP_NAME] + ] }; - + @NgModule({ - providers: [ FirebaseAppProvider ], + providers: [FIREBASE_APP_PROVIDER] }) export class AngularFireModule { - static initializeApp(options: FirebaseOptions, nameOrConfig?: string | FirebaseAppConfig) { - return { - ngModule: AngularFireModule, - providers: [ - { provide: FIREBASE_OPTIONS, useValue: options }, - { provide: FIREBASE_APP_NAME, useValue: nameOrConfig } - ] - } - } - constructor(@Inject(PLATFORM_ID) platformId:Object ) { - firebase.registerVersion('angularfire', VERSION.full, platformId.toString()); - firebase.registerVersion('angular', NG_VERSION.full); - } -} \ No newline at end of file + static initializeApp(options: FirebaseOptions, nameOrConfig?: string | FirebaseAppConfig) { + return { + ngModule: AngularFireModule, + providers: [ + { provide: FIREBASE_OPTIONS, useValue: options }, + { provide: FIREBASE_APP_NAME, useValue: nameOrConfig } + ] + }; + } + + // tslint:disable-next-line:ban-types + constructor(@Inject(PLATFORM_ID) platformId: Object) { + firebase.registerVersion('angularfire', VERSION.full, platformId.toString()); + firebase.registerVersion('angular', NG_VERSION.full); + } +} diff --git a/src/core/public_api.ts b/src/core/public_api.ts index edf1b3425..77f50e30e 100644 --- a/src/core/public_api.ts +++ b/src/core/public_api.ts @@ -1,2 +1,2 @@ export * from './angularfire2'; -export * from './firebase.app.module'; \ No newline at end of file +export * from './firebase.app.module'; diff --git a/src/database/database.spec.ts b/src/database/database.spec.ts index 3834d43d1..fce81c16c 100644 --- a/src/database/database.spec.ts +++ b/src/database/database.spec.ts @@ -1,6 +1,6 @@ -import { FirebaseApp, AngularFireModule, FIREBASE_OPTIONS, FIREBASE_APP_NAME } from '@angular/fire'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; import { AngularFireDatabase, AngularFireDatabaseModule, URL } from './public_api'; -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../test-config'; import { NgZone } from '@angular/core'; import 'firebase/database'; @@ -9,7 +9,7 @@ import { rando } from '../firestore/utils.spec'; describe('AngularFireDatabase', () => { let app: FirebaseApp; let db: AngularFireDatabase; - let zone: NgZone + let zone: NgZone; let firebaseAppName: string; beforeEach(() => { @@ -20,14 +20,13 @@ describe('AngularFireDatabase', () => { AngularFireDatabaseModule ], providers: [ - { provide: URL, useValue: 'http://localhost:9000'} + { provide: URL, useValue: 'http://localhost:9000' } ] }); - inject([FirebaseApp, AngularFireDatabase, NgZone], (app_: FirebaseApp, _db: AngularFireDatabase, _zone: NgZone) => { - app = app_; - db = _db; - zone = _zone; - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); + zone = TestBed.inject(NgZone); }); afterEach(() => { @@ -45,9 +44,9 @@ describe('AngularFireDatabase', () => { }); it('should accept a Firebase App in the constructor', (done) => { - const __db = new AngularFireDatabase(app.options, rando(), undefined!, {}, zone); - expect(__db instanceof AngularFireDatabase).toEqual(true); - __db.database.app.delete().then(done, done); + const database = new AngularFireDatabase(app.options, rando(), undefined, {}, zone); + expect(database instanceof AngularFireDatabase).toEqual(true); + database.database.app.delete().then(done, done); }); it('should have an initialized Firebase app instance member', () => { @@ -68,7 +67,7 @@ describe('AngularFireDatabase w/options', () => { beforeEach(() => { query = rando(); firebaseAppName = rando(); - url = `http://localhost:${Math.floor(Math.random()*9999)}`; + url = `http://localhost:${Math.floor(Math.random() * 9999)}`; TestBed.configureTestingModule({ imports: [ AngularFireModule.initializeApp(COMMON_CONFIG, rando()), @@ -80,10 +79,9 @@ describe('AngularFireDatabase w/options', () => { { provide: URL, useValue: url } ] }); - inject([FirebaseApp, AngularFireDatabase], (app_: FirebaseApp, _db: AngularFireDatabase) => { - app = app_; - db = _db; - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); }); afterEach(() => { @@ -104,20 +102,20 @@ describe('AngularFireDatabase w/options', () => { expect(db.database.app.name).toEqual(firebaseAppName); }); -/* INVESTIGATE database(url) does not seem to be working + /* INVESTIGATE database(url) does not seem to be working - it('database be pointing to the provided DB instance', () => { - expect(db.database.ref().toString()).toEqual(url); - }); + it('database be pointing to the provided DB instance', () => { + expect(db.database.ref().toString()).toEqual(url); + }); - it('list should be using the provided DB instance', () => { - expect(db.list(query).query.toString()).toEqual(`${url}/${query}`); - }); + it('list should be using the provided DB instance', () => { + expect(db.list(query).query.toString()).toEqual(`${url}/${query}`); + }); - it('object should be using the provided DB instance', () => { - expect(db.object(query).query.toString()).toEqual(`${url}/${query}`); - }); -*/ + it('object should be using the provided DB instance', () => { + expect(db.object(query).query.toString()).toEqual(`${url}/${query}`); + }); + */ }); }); diff --git a/src/database/database.ts b/src/database/database.ts index 9f2c086bb..6cd94d6a4 100644 --- a/src/database/database.ts +++ b/src/database/database.ts @@ -1,14 +1,22 @@ -import { Injectable, Inject, Optional, NgZone, PLATFORM_ID, InjectionToken } from '@angular/core'; -import { DatabaseQuery, PathReference, QueryFn, AngularFireList, AngularFireObject } from './interfaces'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { AngularFireList, AngularFireObject, DatabaseQuery, PathReference, QueryFn } from './interfaces'; import { getRef } from './utils'; import { createListReference } from './list/create-reference'; import { createObjectReference } from './object/create-reference'; -import { FirebaseOptions, FirebaseAppConfig, FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵfirebaseAppFactory, ɵkeepUnstableUntilFirstFactory, ɵAngularFireSchedulers } from '@angular/fire'; +import { + FIREBASE_APP_NAME, + FIREBASE_OPTIONS, + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵfirebaseAppFactory, + ɵkeepUnstableUntilFirstFactory +} from '@angular/fire'; import { Observable } from 'rxjs'; import { database } from 'firebase/app'; import 'firebase/database'; -export const URL = new InjectionToken('angularfire2.realtimeDatabaseURL') +export const URL = new InjectionToken('angularfire2.realtimeDatabaseURL'); @Injectable({ providedIn: 'any' @@ -20,14 +28,15 @@ export class AngularFireDatabase { public readonly keepUnstableUntilFirst: (obs$: Observable) => Observable; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, - @Optional() @Inject(URL) databaseURL:string|null, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, + @Optional() @Inject(URL) databaseURL: string | null, + // tslint:disable-next-line:ban-types @Inject(PLATFORM_ID) platformId: Object, zone: NgZone ) { this.schedulers = new ɵAngularFireSchedulers(zone); - this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers, platformId); + this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers); this.database = zone.runOutsideAngular(() => { const app = ɵfirebaseAppFactory(options, zone, nameOrConfig); @@ -38,13 +47,13 @@ export class AngularFireDatabase { list(pathOrRef: PathReference, queryFn?: QueryFn): AngularFireList { const ref = getRef(this.database, pathOrRef); let query: DatabaseQuery = ref; - if(queryFn) { + if (queryFn) { query = queryFn(ref); } return createListReference(query, this); } - object(pathOrRef: PathReference): AngularFireObject { + object(pathOrRef: PathReference): AngularFireObject { const ref = getRef(this.database, pathOrRef); return createObjectReference(ref, this); } diff --git a/src/database/interfaces.ts b/src/database/interfaces.ts index d2ce4e8f3..e1ff15b3a 100644 --- a/src/database/interfaces.ts +++ b/src/database/interfaces.ts @@ -38,7 +38,7 @@ export type ListenEvent = 'value' | ChildEvent; export interface Action { type: ListenEvent; payload: T; -}; +} export interface AngularFireAction extends Action { prevKey: string | null | undefined; diff --git a/src/database/list/audit-trail.spec.ts b/src/database/list/audit-trail.spec.ts index baa817e7f..c866417a5 100644 --- a/src/database/list/audit-trail.spec.ts +++ b/src/database/list/audit-trail.spec.ts @@ -1,7 +1,7 @@ import { DatabaseReference } from '../interfaces'; -import { FirebaseApp, AngularFireModule } from '@angular/fire'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; import { AngularFireDatabase, AngularFireDatabaseModule, auditTrail, ChildEvent, URL } from '../public_api'; -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; import { skip } from 'rxjs/operators'; import 'firebase/database'; @@ -12,10 +12,9 @@ describe('auditTrail', () => { let db: AngularFireDatabase; let createRef: (path: string) => DatabaseReference; let batch = {}; - const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ( { key: i.toString(), ...item } )); - Object.keys(items).forEach(function (key, i) { - const itemValue = items[key]; - batch[i] = itemValue; + const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ({ key: i.toString(), ...item })); + Object.keys(items).forEach((key, i) => { + batch[i] = items[key]; }); // make batch immutable to preserve integrity batch = Object.freeze(batch); @@ -30,11 +29,10 @@ describe('auditTrail', () => { { provide: URL, useValue: 'http://localhost:9000' } ] }); - inject([FirebaseApp, AngularFireDatabase], (app_: FirebaseApp, _db: AngularFireDatabase) => { - app = app_; - db = _db; - createRef = (path: string) => db.database.ref(path); - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); + createRef = (path: string) => db.database.ref(path); }); afterEach(() => { diff --git a/src/database/list/audit-trail.ts b/src/database/list/audit-trail.ts index 6461dec72..1ead7342b 100644 --- a/src/database/list/audit-trail.ts +++ b/src/database/list/audit-trail.ts @@ -1,9 +1,9 @@ -import { DataSnapshot, DatabaseQuery, ChildEvent, DatabaseSnapshot, AngularFireAction, SnapshotAction } from '../interfaces'; +import { AngularFireAction, ChildEvent, DatabaseQuery, DataSnapshot, SnapshotAction } from '../interfaces'; import { stateChanges } from './state-changes'; import { Observable, SchedulerLike } from 'rxjs'; import { fromRef } from '../observable/fromRef'; -import { skipWhile, withLatestFrom, map, scan } from 'rxjs/operators'; +import { map, scan, skipWhile, withLatestFrom } from 'rxjs/operators'; export function auditTrail(query: DatabaseQuery, events?: ChildEvent[], scheduler?: SchedulerLike): Observable[]> { const auditTrail$ = stateChanges(query, events) @@ -46,10 +46,10 @@ function waitForLoaded(query: DatabaseQuery, action$: Observable { // Store the last key in the data set - let lastKeyToLoad = loaded.lastKeyToLoad; + const lastKeyToLoad = loaded.lastKeyToLoad; // Store all child keys loaded at this point const loadedKeys = actions.map(snap => snap.key); - return { actions, lastKeyToLoad, loadedKeys } + return { actions, lastKeyToLoad, loadedKeys }; }), // This is the magical part, only emit when the last load key // in the dataset has been loaded by a child event. At this point diff --git a/src/database/list/changes.spec.ts b/src/database/list/changes.spec.ts index 75e70dd05..c21c2a8bb 100644 --- a/src/database/list/changes.spec.ts +++ b/src/database/list/changes.spec.ts @@ -1,9 +1,9 @@ import { database } from 'firebase/app'; -import { FirebaseApp, AngularFireModule } from '@angular/fire'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; import { AngularFireDatabase, AngularFireDatabaseModule, listChanges, URL } from '../public_api'; -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; -import { skip, take, tap } from 'rxjs/operators'; +import { skip, take } from 'rxjs/operators'; import 'firebase/database'; import { rando } from '../../firestore/utils.spec'; @@ -12,10 +12,9 @@ describe('listChanges', () => { let db: AngularFireDatabase; let ref: (path: string) => database.Reference; let batch = {}; - const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ( { key: i.toString(), ...item } )); - Object.keys(items).forEach(function (key, i) { - const itemValue = items[key]; - batch[i] = itemValue; + const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ({ key: i.toString(), ...item })); + Object.keys(items).forEach((key, i) => { + batch[i] = items[key]; }); // make batch immutable to preserve integrity batch = Object.freeze(batch); @@ -30,11 +29,10 @@ describe('listChanges', () => { { provide: URL, useValue: 'http://localhost:9000' } ] }); - inject([FirebaseApp, AngularFireDatabase], (app_: FirebaseApp, _db: AngularFireDatabase) => { - app = app_; - db = _db; - ref = (path: string) => db.database.ref(path); - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); + ref = (path: string) => db.database.ref(path); }); afterEach(() => { @@ -46,7 +44,7 @@ describe('listChanges', () => { it('should stream value at first', (done) => { const someRef = ref(rando()); const obs = listChanges(someRef, ['child_added']); - const sub = obs.pipe(take(1)).subscribe(changes => { + obs.pipe(take(1)).subscribe(changes => { const data = changes.map(change => change.payload.val()); expect(data).toEqual(items); }).add(done); @@ -56,7 +54,7 @@ describe('listChanges', () => { it('should process a new child_added event', done => { const aref = ref(rando()); const obs = listChanges(aref, ['child_added']); - const sub = obs.pipe(skip(1),take(1)).subscribe(changes => { + obs.pipe(skip(1), take(1)).subscribe(changes => { const data = changes.map(change => change.payload.val()); expect(data[3]).toEqual({ name: 'anotha one' }); }).add(done); @@ -67,7 +65,7 @@ describe('listChanges', () => { it('should stream in order events', (done) => { const aref = ref(rando()); const obs = listChanges(aref.orderByChild('name'), ['child_added']); - const sub = obs.pipe(take(1)).subscribe(changes => { + obs.pipe(take(1)).subscribe(changes => { const names = changes.map(change => change.payload.val().name); expect(names[0]).toEqual('one'); expect(names[1]).toEqual('two'); @@ -79,7 +77,7 @@ describe('listChanges', () => { it('should stream in order events w/child_added', (done) => { const aref = ref(rando()); const obs = listChanges(aref.orderByChild('name'), ['child_added']); - const sub = obs.pipe(skip(1),take(1)).subscribe(changes => { + obs.pipe(skip(1), take(1)).subscribe(changes => { const names = changes.map(change => change.payload.val().name); expect(names[0]).toEqual('anotha one'); expect(names[1]).toEqual('one'); @@ -93,7 +91,7 @@ describe('listChanges', () => { it('should stream events filtering', (done) => { const aref = ref(rando()); const obs = listChanges(aref.orderByChild('name').equalTo('zero'), ['child_added']); - obs.pipe(skip(1),take(1)).subscribe(changes => { + obs.pipe(skip(1), take(1)).subscribe(changes => { const names = changes.map(change => change.payload.val().name); expect(names[0]).toEqual('zero'); expect(names[1]).toEqual('zero'); diff --git a/src/database/list/changes.ts b/src/database/list/changes.ts index f47b3cf3c..cb37d0694 100644 --- a/src/database/list/changes.ts +++ b/src/database/list/changes.ts @@ -1,17 +1,17 @@ import { fromRef } from '../observable/fromRef'; -import { Observable, of, merge, SchedulerLike } from 'rxjs'; +import { merge, Observable, of, SchedulerLike } from 'rxjs'; -import { DatabaseQuery, ChildEvent, SnapshotAction } from '../interfaces'; +import { ChildEvent, DatabaseQuery, SnapshotAction } from '../interfaces'; import { isNil } from '../utils'; -import { switchMap, distinctUntilChanged, scan } from 'rxjs/operators'; +import { distinctUntilChanged, scan, switchMap } from 'rxjs/operators'; -export function listChanges(ref: DatabaseQuery, events: ChildEvent[], scheduler?: SchedulerLike): Observable[]> { +export function listChanges(ref: DatabaseQuery, events: ChildEvent[], scheduler?: SchedulerLike): Observable[]> { return fromRef(ref, 'value', 'once', scheduler).pipe( switchMap(snapshotAction => { const childEvent$ = [of(snapshotAction)]; events.forEach(event => childEvent$.push(fromRef(ref, event, 'on', scheduler))); - return merge(...childEvent$).pipe(scan(buildView, [])) + return merge(...childEvent$).pipe(scan(buildView, [])); }), distinctUntilChanged() ); @@ -19,8 +19,8 @@ export function listChanges(ref: DatabaseQuery, events: ChildEvent[], sch function positionFor(changes: SnapshotAction[], key) { const len = changes.length; - for(let i=0; i(changes: SnapshotAction[], key) { } function positionAfter(changes: SnapshotAction[], prevKey?: string) { - if(isNil(prevKey)) { + if (isNil(prevKey)) { return 0; } else { const i = positionFor(changes, prevKey); - if( i === -1) { + if (i === -1) { return changes.length; } else { return i + 1; @@ -41,7 +41,7 @@ function positionAfter(changes: SnapshotAction[], prevKey?: string) { } function buildView(current, action) { - const { payload, type, prevKey, key } = action; + const { payload, prevKey, key } = action; const currentKeyPosition = positionFor(current, key); const afterPreviousKeyPosition = positionAfter(current, prevKey); switch (action.type) { @@ -49,7 +49,7 @@ function buildView(current, action) { if (action.payload && action.payload.exists()) { let prevKey = null; action.payload.forEach(payload => { - const action = {payload, type: 'value', prevKey, key: payload.key}; + const action = { payload, type: 'value', prevKey, key: payload.key }; prevKey = payload.key; current = [...current, action]; return false; @@ -60,14 +60,14 @@ function buildView(current, action) { if (currentKeyPosition > -1) { // check that the previouskey is what we expect, else reorder const previous = current[currentKeyPosition - 1]; - if ((previous && previous.key || null) != prevKey) { + if ((previous && previous.key || null) !== prevKey) { current = current.filter(x => x.payload.key !== payload.key); current.splice(afterPreviousKeyPosition, 0, action); } } else if (prevKey == null) { return [action, ...current]; } else { - current = current.slice() + current = current.slice(); current.splice(afterPreviousKeyPosition, 0, action); } return current; @@ -76,9 +76,9 @@ function buildView(current, action) { case 'child_changed': return current.map(x => x.payload.key === key ? action : x); case 'child_moved': - if(currentKeyPosition > -1) { + if (currentKeyPosition > -1) { const data = current.splice(currentKeyPosition, 1)[0]; - current = current.slice() + current = current.slice(); current.splice(afterPreviousKeyPosition, 0, data); return current; } diff --git a/src/database/list/create-reference.ts b/src/database/list/create-reference.ts index 69359e22d..b80136a62 100644 --- a/src/database/list/create-reference.ts +++ b/src/database/list/create-reference.ts @@ -1,4 +1,4 @@ -import { DatabaseQuery, AngularFireList, ChildEvent } from '../interfaces'; +import { AngularFireList, ChildEvent, DatabaseQuery } from '../interfaces'; import { snapshotChanges } from './snapshot-changes'; import { stateChanges } from './state-changes'; import { auditTrail } from './audit-trail'; @@ -7,14 +7,15 @@ import { createRemoveMethod } from './remove'; import { AngularFireDatabase } from '../database'; import { map } from 'rxjs/operators'; -export function createListReference(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireList { +export function createListReference(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireList { const outsideAngularScheduler = afDatabase.schedulers.outsideAngular; + const refInZone = afDatabase.schedulers.ngZone.run(() => query.ref); return { query, - update: createDataOperationMethod>(query.ref, 'update'), - set: createDataOperationMethod(query.ref, 'set'), - push: (data: T) => query.ref.push(data), - remove: createRemoveMethod(query.ref), + update: createDataOperationMethod>(refInZone, 'update'), + set: createDataOperationMethod(refInZone, 'set'), + push: (data: T) => refInZone.push(data), + remove: createRemoveMethod(refInZone), snapshotChanges(events?: ChildEvent[]) { return snapshotChanges(query, events, outsideAngularScheduler).pipe(afDatabase.keepUnstableUntilFirst); }, @@ -31,5 +32,5 @@ export function createListReference(query: DatabaseQuery, afDatabase: Ang afDatabase.keepUnstableUntilFirst ); } - } + }; } diff --git a/src/database/list/data-operation.ts b/src/database/list/data-operation.ts index 0bc1a0210..78bb0bf4e 100644 --- a/src/database/list/data-operation.ts +++ b/src/database/list/data-operation.ts @@ -1,13 +1,12 @@ - -import { DatabaseReference, FirebaseOperation, DatabaseSnapshot } from '../interfaces'; +import { DatabaseReference, DatabaseSnapshot, FirebaseOperation } from '../interfaces'; import { checkOperationCases } from '../utils'; export function createDataOperationMethod(ref: DatabaseReference, operation: string) { return function dataOperation(item: FirebaseOperation, value: T) { return checkOperationCases(item, { - stringCase: () => ref.child(item)[operation](value), - firebaseCase: () => (item)[operation](value), - snapshotCase: () => (>item).ref[operation](value) + stringCase: () => ref.child(item as string)[operation](value), + firebaseCase: () => (item as DatabaseReference)[operation](value), + snapshotCase: () => (item as DatabaseSnapshot).ref[operation](value) }); - } + }; } diff --git a/src/database/list/remove.ts b/src/database/list/remove.ts index 49751a340..45928df86 100644 --- a/src/database/list/remove.ts +++ b/src/database/list/remove.ts @@ -1,16 +1,15 @@ -import { DatabaseReference, DataSnapshot, FirebaseOperation, DatabaseSnapshot } from '../interfaces'; +import { DatabaseReference, DatabaseSnapshot, FirebaseOperation } from '../interfaces'; import { checkOperationCases } from '../utils'; -import { database } from 'firebase/app'; // TODO(davideast): Find out why TS thinks this returns firebase.Primise // instead of Promise. export function createRemoveMethod(ref: DatabaseReference) { return function remove(item?: FirebaseOperation): any { - if(!item) { return ref.remove(); } + if (!item) { return ref.remove(); } return checkOperationCases(item, { - stringCase: () => ref.child(item).remove(), - firebaseCase: () => (item).remove(), - snapshotCase: () => (>item).ref.remove() + stringCase: () => ref.child(item as string).remove(), + firebaseCase: () => (item as DatabaseReference).remove(), + snapshotCase: () => (item as DatabaseSnapshot).ref.remove() }); - } + }; } diff --git a/src/database/list/snapshot-changes.spec.ts b/src/database/list/snapshot-changes.spec.ts index bfed665a5..6ba1959ea 100644 --- a/src/database/list/snapshot-changes.spec.ts +++ b/src/database/list/snapshot-changes.spec.ts @@ -1,10 +1,10 @@ import { database } from 'firebase/app'; -import { FirebaseApp, AngularFireModule } from '@angular/fire'; -import { AngularFireDatabase, AngularFireDatabaseModule, snapshotChanges, ChildEvent, URL } from '../public_api'; -import { TestBed, inject } from '@angular/core/testing'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; +import { AngularFireDatabase, AngularFireDatabaseModule, ChildEvent, snapshotChanges, URL } from '../public_api'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; import { BehaviorSubject } from 'rxjs'; -import { skip, take, switchMap } from 'rxjs/operators'; +import { skip, switchMap, take } from 'rxjs/operators'; import 'firebase/database'; import { rando } from '../../firestore/utils.spec'; @@ -13,10 +13,9 @@ describe('snapshotChanges', () => { let db: AngularFireDatabase; let createRef: (path: string) => database.Reference; let batch = {}; - const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ( { key: i.toString(), ...item } )); - Object.keys(items).forEach(function (key, i) { - const itemValue = items[key]; - batch[i] = itemValue; + const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ({ key: i.toString(), ...item })); + Object.keys(items).forEach((key, i) => { + batch[i] = items[key]; }); // make batch immutable to preserve integrity batch = Object.freeze(batch); @@ -31,11 +30,10 @@ describe('snapshotChanges', () => { { provide: URL, useValue: 'http://localhost:9000' } ] }); - inject([FirebaseApp, AngularFireDatabase], (app_: FirebaseApp, _db: AngularFireDatabase) => { - app = app_; - db = _db; - createRef = (path: string) => db.database.ref(path);; - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); + createRef = (path: string) => db.database.ref(path); }); afterEach(() => { @@ -55,7 +53,7 @@ describe('snapshotChanges', () => { it('should listen to all events by default', (done) => { const { snapChanges, ref } = prepareSnapshotChanges(); snapChanges.pipe(take(1)).subscribe(actions => { - const data = actions.map(a => a.payload!.val()); + const data = actions.map(a => a.payload.val()); expect(data).toEqual(items); }).add(done); ref.set(batch); @@ -63,9 +61,10 @@ describe('snapshotChanges', () => { it('should handle multiple subscriptions (hot)', (done) => { const { snapChanges, ref } = prepareSnapshotChanges(); - const sub = snapChanges.subscribe(() => {}).add(done); + const sub = snapChanges.subscribe(() => { + }).add(done); snapChanges.pipe(take(1)).subscribe(actions => { - const data = actions.map(a => a.payload!.val()); + const data = actions.map(a => a.payload.val()); expect(data).toEqual(items); }).add(sub); ref.set(batch); @@ -73,19 +72,20 @@ describe('snapshotChanges', () => { it('should handle multiple subscriptions (warm)', done => { const { snapChanges, ref } = prepareSnapshotChanges(); - snapChanges.pipe(take(1)).subscribe(() => {}).add(() => { + snapChanges.pipe(take(1)).subscribe(() => { + }).add(() => { snapChanges.pipe(take(1)).subscribe(actions => { - const data = actions.map(a => a.payload!.val()); + const data = actions.map(a => a.payload.val()); expect(data).toEqual(items); }).add(done); }); ref.set(batch); }); - it('should listen to only child_added events', (done) => { + it('should listen to only child_added events', (done) => { const { snapChanges, ref } = prepareSnapshotChanges({ events: ['child_added'], skipnumber: 0 }); snapChanges.pipe(take(1)).subscribe(actions => { - const data = actions.map(a => a.payload!.val()); + const data = actions.map(a => a.payload.val()); expect(data).toEqual(items); }).add(done); ref.set(batch); @@ -118,24 +118,22 @@ describe('snapshotChanges', () => { }); it('should handle dynamic queries that return empty sets', done => { - const ITEMS = 10; let count = 0; - let firstIndex = 0; - let namefilter$ = new BehaviorSubject(null); + const namefilter$ = new BehaviorSubject(null); const aref = createRef(rando()); aref.set(batch); namefilter$.pipe(switchMap(name => { - const filteredRef = name ? aref.child('name').equalTo(name) : aref + const filteredRef = name ? aref.child('name').equalTo(name) : aref; return snapshotChanges(filteredRef); - }),take(2)).subscribe(data => { + }), take(2)).subscribe(data => { count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { expect(Object.keys(data).length).toEqual(3); namefilter$.next(-1); } // on the second round, we should have filtered out everything - if(count === 2) { + if (count === 2) { expect(Object.keys(data).length).toEqual(0); } }).add(done); diff --git a/src/database/list/snapshot-changes.ts b/src/database/list/snapshot-changes.ts index 2dbb731b2..7422c65bd 100644 --- a/src/database/list/snapshot-changes.ts +++ b/src/database/list/snapshot-changes.ts @@ -1,9 +1,13 @@ import { Observable, SchedulerLike } from 'rxjs'; import { listChanges } from './changes'; -import { DatabaseQuery, ChildEvent, SnapshotAction } from '../interfaces'; +import { ChildEvent, DatabaseQuery, SnapshotAction } from '../interfaces'; import { validateEventsArray } from './utils'; -export function snapshotChanges(query: DatabaseQuery, events?: ChildEvent[], scheduler?: SchedulerLike): Observable[]> { +export function snapshotChanges( + query: DatabaseQuery, + events?: ChildEvent[], + scheduler?: SchedulerLike +): Observable[]> { events = validateEventsArray(events); - return listChanges(query, events!, scheduler); + return listChanges(query, events, scheduler); } diff --git a/src/database/list/state-changes.spec.ts b/src/database/list/state-changes.spec.ts index ccc84f01e..b6d3c2711 100644 --- a/src/database/list/state-changes.spec.ts +++ b/src/database/list/state-changes.spec.ts @@ -1,7 +1,7 @@ import { database } from 'firebase/app'; -import { FirebaseApp, AngularFireModule } from '@angular/fire'; -import { AngularFireDatabase, AngularFireDatabaseModule, stateChanges, ChildEvent, URL } from '../public_api'; -import { TestBed, inject } from '@angular/core/testing'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; +import { AngularFireDatabase, AngularFireDatabaseModule, ChildEvent, stateChanges, URL } from '../public_api'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; import { skip } from 'rxjs/operators'; import 'firebase/database'; @@ -12,10 +12,9 @@ describe('stateChanges', () => { let db: AngularFireDatabase; let createRef: (path: string) => database.Reference; let batch = {}; - const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ( { key: i.toString(), ...item } )); - Object.keys(items).forEach(function (key, i) { - const itemValue = items[key]; - batch[i] = itemValue; + const items = [{ name: 'zero' }, { name: 'one' }, { name: 'two' }].map((item, i) => ({ key: i.toString(), ...item })); + Object.keys(items).forEach((key, i) => { + batch[i] = items[key]; }); // make batch immutable to preserve integrity batch = Object.freeze(batch); @@ -30,11 +29,10 @@ describe('stateChanges', () => { { provide: URL, useValue: 'http://localhost:9000' } ] }); - inject([FirebaseApp, AngularFireDatabase], (app_: FirebaseApp, _db: AngularFireDatabase) => { - app = app_; - db = _db; - createRef = (path: string) => db.database.ref(path); - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); + createRef = (path: string) => db.database.ref(path); }); afterEach(() => { diff --git a/src/database/list/state-changes.ts b/src/database/list/state-changes.ts index 26c460869..192043e3b 100644 --- a/src/database/list/state-changes.ts +++ b/src/database/list/state-changes.ts @@ -1,11 +1,10 @@ -import { DatabaseQuery, ChildEvent, AngularFireAction, SnapshotAction } from '../interfaces'; +import { ChildEvent, DatabaseQuery } from '../interfaces'; import { fromRef } from '../observable/fromRef'; import { validateEventsArray } from './utils'; -import { SchedulerLike, Observable, merge } from 'rxjs'; -import { DatabaseSnapshot } from '../interfaces'; +import { merge, SchedulerLike } from 'rxjs'; export function stateChanges(query: DatabaseQuery, events?: ChildEvent[], scheduler?: SchedulerLike) { - events = validateEventsArray(events)!; + events = validateEventsArray(events); const childEvent$ = events.map(event => fromRef(query, event, 'on', scheduler)); return merge(...childEvent$); } diff --git a/src/database/list/utils.ts b/src/database/list/utils.ts index 2f1c30647..35404600c 100644 --- a/src/database/list/utils.ts +++ b/src/database/list/utils.ts @@ -1,8 +1,8 @@ import { isNil } from '../utils'; export function validateEventsArray(events?: any[]) { - if(isNil(events) || events!.length === 0) { + if (isNil(events) || events.length === 0) { events = ['child_added', 'child_removed', 'child_changed', 'child_moved']; } return events; -} \ No newline at end of file +} diff --git a/src/database/object/create-reference.ts b/src/database/object/create-reference.ts index 8603029e5..cede58f97 100644 --- a/src/database/object/create-reference.ts +++ b/src/database/object/create-reference.ts @@ -1,14 +1,14 @@ import { map } from 'rxjs/operators'; -import { DatabaseQuery, AngularFireObject } from '../interfaces'; +import { AngularFireObject, DatabaseQuery } from '../interfaces'; import { createObjectSnapshotChanges } from './snapshot-changes'; import { AngularFireDatabase } from '../database'; -export function createObjectReference(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireObject { +export function createObjectReference(query: DatabaseQuery, afDatabase: AngularFireDatabase): AngularFireObject { return { query, snapshotChanges() { return createObjectSnapshotChanges(query, afDatabase.schedulers.outsideAngular)().pipe( - afDatabase.keepUnstableUntilFirst! + afDatabase.keepUnstableUntilFirst ); }, update(data: Partial) { return query.ref.update(data as any) as Promise; }, @@ -19,7 +19,7 @@ export function createObjectReference(query: DatabaseQuery, afDatabase: A return snapshotChanges$.pipe( afDatabase.keepUnstableUntilFirst, map(action => action.payload.exists() ? action.payload.val() as T : null) - ) + ); }, - } + }; } diff --git a/src/database/object/snapshot-changes.ts b/src/database/object/snapshot-changes.ts index 8da9a34d4..66ae6ef3c 100644 --- a/src/database/object/snapshot-changes.ts +++ b/src/database/object/snapshot-changes.ts @@ -5,5 +5,5 @@ import { DatabaseQuery, SnapshotAction } from '../interfaces'; export function createObjectSnapshotChanges(query: DatabaseQuery, scheduler?: SchedulerLike) { return function snapshotChanges(): Observable> { return fromRef(query, 'value', 'on', scheduler); - } + }; } diff --git a/src/database/observable/fromRef.spec.ts b/src/database/observable/fromRef.spec.ts index 69b17ed49..e7a1f966e 100644 --- a/src/database/observable/fromRef.spec.ts +++ b/src/database/observable/fromRef.spec.ts @@ -1,7 +1,7 @@ import { DatabaseReference } from '../interfaces'; -import { FirebaseApp, AngularFireModule, ɵZoneScheduler } from '@angular/fire'; +import { AngularFireModule, FirebaseApp, ɵZoneScheduler } from '@angular/fire'; import { AngularFireDatabase, AngularFireDatabaseModule, fromRef } from '../public_api'; -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; import { take } from 'rxjs/operators'; import { TestScheduler } from 'rxjs/testing'; @@ -13,7 +13,7 @@ describe('fromRef', () => { let ref: (path: string) => DatabaseReference; let batch = {}; const items = [{ name: 'one' }, { name: 'two' }, { name: 'three' }].map(item => ({ key: rando(), ...item })); - Object.keys(items).forEach(function (key) { + Object.keys(items).forEach((key) => { const itemValue = items[key]; batch[itemValue.key] = itemValue; }); @@ -27,14 +27,13 @@ describe('fromRef', () => { AngularFireDatabaseModule ], providers: [ - { provide: URL, useValue: 'http://localhost:9000'} + { provide: URL, useValue: 'http://localhost:9000' } ] }); - inject([FirebaseApp, AngularFireDatabase], (app_: FirebaseApp, db_: AngularFireDatabase) => { - app = app_; - db = db_; - ref = (path: string) => db.database.ref(path); - })(); + + app = TestBed.inject(FirebaseApp); + db = TestBed.inject(AngularFireDatabase); + ref = (path: string) => db.database.ref(path); }); afterEach(() => { @@ -47,7 +46,7 @@ describe('fromRef', () => { const obs = fromRef(itemRef, 'value'); let count = 0; expect(count).toEqual(0); - const sub = obs.subscribe(change => { + const sub = obs.subscribe(() => { count = count + 1; expect(count).toEqual(1); sub.unsubscribe(); @@ -73,11 +72,11 @@ describe('fromRef', () => { done(); }, err => { console.error(err); - expect(false).toEqual(true, "Shouldnt error"); + expect(false).toEqual(true, 'Shouldnt error'); done(); }, () => { expect(testScheduler.schedule).toHaveBeenCalled(); - done() + done(); }); testScheduler.flush(); }); @@ -90,18 +89,18 @@ describe('fromRef', () => { // Error const errorObservable = fromRef({ - once: (event, snap, err) => err() - } as any, + once: (event, snap, err) => err() + } as any, 'value', 'once', testScheduler ); errorObservable.subscribe(() => { - fail("Should not emit"); + fail('Should not emit'); }, () => { expect(testScheduler.schedule).toHaveBeenCalled(); }, () => { - fail("Should not complete"); + fail('Should not complete'); }); testScheduler.flush(); @@ -120,9 +119,10 @@ describe('fromRef', () => { scheduler ); completeObservable.subscribe( - () => { }, - () => fail("Should not error"), - () => expect(Zone.current.name).toEqual("ExpectedZone") + () => { + }, + () => fail('Should not error'), + () => expect(Zone.current.name).toEqual('ExpectedZone') ); testScheduler.flush(); done(); @@ -133,7 +133,7 @@ describe('fromRef', () => { const itemRef = ref(rando()); itemRef.set({}); const obs = fromRef(itemRef, 'value'); - const sub = obs.pipe(take(1)).subscribe(change => { + obs.pipe(take(1)).subscribe(change => { expect(change.payload.exists()).toEqual(false); expect(change.payload.val()).toEqual(null); }).add(done); @@ -143,7 +143,9 @@ describe('fromRef', () => { const itemRef = ref(rando()); itemRef.set(batch); const obs = fromRef(itemRef, 'value', 'once'); - obs.subscribe(change => { }, () => { }, done); + obs.subscribe(() => { + }, () => { + }, done); }); it('it should listen and then unsubscribe', (done) => { @@ -151,7 +153,7 @@ describe('fromRef', () => { itemRef.set(batch); const obs = fromRef(itemRef, 'value'); let count = 0; - const sub = obs.subscribe(change => { + const sub = obs.subscribe(() => { count = count + 1; // hard coding count to one will fail if the unsub // doesn't actually unsub @@ -173,7 +175,7 @@ describe('fromRef', () => { count = count + 1; const { type, payload } = change; expect(type).toEqual('child_added'); - expect(payload.val()).toEqual(batch[payload.key!]); + expect(payload.val()).toEqual(batch[payload.key]); if (count === items.length) { done(); sub.unsubscribe(); @@ -230,7 +232,8 @@ describe('fromRef', () => { sub.unsubscribe(); done(); }); - itemRef.child(key).setPriority(-100, () => { }); + itemRef.child(key).setPriority(-100, () => { + }); }); it('should stream back a value event', (done: any) => { @@ -252,9 +255,12 @@ describe('fromRef', () => { itemRef.set(batch); const query = itemRef.orderByChild('name').equalTo(items[0].name); const obs = fromRef(query, 'value'); - const sub = obs.subscribe(change => { - let child; - change.payload.forEach(snap => { child = snap.val(); return true; }); + obs.subscribe(change => { + let child = null; + change.payload.forEach(snap => { + child = snap.val(); + return true; + }); expect(child).toEqual(items[0]); done(); }); diff --git a/src/database/observable/fromRef.ts b/src/database/observable/fromRef.ts index aac8e2ecc..d08283235 100644 --- a/src/database/observable/fromRef.ts +++ b/src/database/observable/fromRef.ts @@ -1,5 +1,5 @@ -import { DatabaseQuery, DatabaseSnapshot, ListenEvent, AngularFireAction } from '../interfaces'; -import { Observable, SchedulerLike, queueScheduler, asyncScheduler } from 'rxjs'; +import { AngularFireAction, DatabaseQuery, DatabaseSnapshot, ListenEvent } from '../interfaces'; +import { asyncScheduler, Observable, SchedulerLike } from 'rxjs'; import { map, share } from 'rxjs/operators'; interface SnapshotPrevKey { @@ -11,22 +11,28 @@ interface SnapshotPrevKey { * Create an observable from a Database Reference or Database Query. * @param ref Database Reference * @param event Listen event type ('value', 'added', 'changed', 'removed', 'moved') + * @param listenType 'on' or 'once' + * @param scheduler - Rxjs scheduler */ -export function fromRef(ref: DatabaseQuery, event: ListenEvent, listenType = 'on', scheduler: SchedulerLike = asyncScheduler): Observable>> { +export function fromRef(ref: DatabaseQuery, + event: ListenEvent, + listenType = 'on', + scheduler: SchedulerLike = asyncScheduler +): Observable>> { return new Observable>(subscriber => { let fn: any | null = null; fn = ref[listenType](event, (snapshot, prevKey) => { scheduler.schedule(() => { subscriber.next({ snapshot, prevKey }); }); - if (listenType == 'once') { + if (listenType === 'once') { scheduler.schedule(() => subscriber.complete()); } }, err => { - scheduler.schedule(() => subscriber.error(err)) + scheduler.schedule(() => subscriber.error(err)); }); - if (listenType == 'on') { + if (listenType === 'on') { return { unsubscribe() { if (fn != null) { @@ -35,13 +41,18 @@ export function fromRef(ref: DatabaseQuery, event: ListenEvent, listenType = } }; } else { - return { unsubscribe() { } }; + return { + unsubscribe() { + } + }; } }).pipe( map(payload => { const { snapshot, prevKey } = payload; let key: string | null = null; - if (snapshot.exists()) { key = snapshot.key; } + if (snapshot.exists()) { + key = snapshot.key; + } return { type: event, payload: snapshot, prevKey, key }; }), share() diff --git a/src/database/public_api.ts b/src/database/public_api.ts index bac23e359..b1f0ab756 100644 --- a/src/database/public_api.ts +++ b/src/database/public_api.ts @@ -5,4 +5,4 @@ export * from './list/snapshot-changes'; export * from './list/state-changes'; export * from './list/audit-trail'; export * from './observable/fromRef'; -export * from './database.module' +export * from './database.module'; diff --git a/src/database/utils.spec.ts b/src/database/utils.spec.ts index 0bc3c87c7..b437b0700 100644 --- a/src/database/utils.spec.ts +++ b/src/database/utils.spec.ts @@ -1,4 +1,3 @@ -import { TestBed, inject } from '@angular/core/testing'; import * as utils from './utils'; describe('utils', () => { @@ -12,11 +11,12 @@ describe('utils', () => { const nul = null; const obj = {}; const fn = () => { }; - let undef; + const undef = undefined; expect(utils.isString(str)).toBe(true); expect(utils.isString(notStr)).toBe(false); expect(utils.isString(bool)).toBe(false); expect(utils.isString(nul)).toBe(false); + expect(utils.isString(obj)).toBe(false); expect(utils.isString(fn)).toBe(false); expect(utils.isString(undef)).toBe(false); }); diff --git a/src/database/utils.ts b/src/database/utils.ts index 4c0275864..8811bdbfa 100644 --- a/src/database/utils.ts +++ b/src/database/utils.ts @@ -1,5 +1,4 @@ -import { Subscription, Scheduler } from 'rxjs'; -import { PathReference, DatabaseReference, FirebaseOperation, FirebaseOperationCases } from './interfaces'; +import { DatabaseReference, FirebaseOperation, FirebaseOperationCases, PathReference } from './interfaces'; import { database } from 'firebase/app'; export function isString(value: any): boolean { @@ -21,8 +20,8 @@ export function isFirebaseRef(value: any): boolean { /** * Returns a database reference given a Firebase App and an * absolute or relative path. - * @param app - Firebase App - * @param path - Database path, relative or absolute + * @param database - Firebase Database + * @param pathRef - Database path, relative or absolute */ export function getRef(database: database.Database, pathRef: PathReference): DatabaseReference { // if a db ref was passed in, just return it @@ -30,13 +29,13 @@ export function getRef(database: database.Database, pathRef: PathReference): Dat : database.ref(pathRef as string); } -export function checkOperationCases(item: FirebaseOperation, cases: FirebaseOperationCases) : Promise { +export function checkOperationCases(item: FirebaseOperation, cases: FirebaseOperationCases): Promise { if (isString(item)) { return cases.stringCase(); } else if (isFirebaseRef(item)) { - return cases.firebaseCase!(); + return cases.firebaseCase(); } else if (isFirebaseDataSnapshot(item)) { - return cases.snapshotCase!(); + return cases.snapshotCase(); } throw new Error(`Expects a string, snapshot, or reference. Got: ${typeof item}`); } diff --git a/src/firestore/collection-group/collection-group.spec.ts b/src/firestore/collection-group/collection-group.spec.ts index 24d9fdf25..4c199fb17 100644 --- a/src/firestore/collection-group/collection-group.spec.ts +++ b/src/firestore/collection-group/collection-group.spec.ts @@ -1,13 +1,23 @@ -import { FirebaseApp, AngularFireModule } from '@angular/fire'; -import { AngularFirestore, AngularFirestoreModule, AngularFirestoreDocument, AngularFirestoreCollectionGroup, SETTINGS } from '../public_api'; -import { QueryGroupFn, Query } from '../interfaces'; -import { Observable, BehaviorSubject, Subscription } from 'rxjs'; -import { skip, take, switchMap } from 'rxjs/operators'; -import { TestBed, inject } from '@angular/core/testing'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; +import { AngularFirestore, AngularFirestoreCollectionGroup, AngularFirestoreModule, SETTINGS } from '../public_api'; +import { Query, QueryGroupFn } from '../interfaces'; +import { BehaviorSubject } from 'rxjs'; +import { skip, switchMap, take } from 'rxjs/operators'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; import 'firebase/firestore'; -import { Stock, randomName, FAKE_STOCK_DATA, createRandomStocks, delayAdd, delayDelete, delayUpdate, deleteThemAll, rando } from '../utils.spec'; +import { + createRandomStocks, + delayAdd, + delayDelete, + delayUpdate, + deleteThemAll, + FAKE_STOCK_DATA, + rando, + randomName, + Stock +} from '../utils.spec'; async function collectionHarness(afs: AngularFirestore, items: number, queryGroupFn?: QueryGroupFn) { const randomCollectionName = randomName(afs.firestore); @@ -16,14 +26,13 @@ async function collectionHarness(afs: AngularFirestore, items: number, queryGrou const collectionGroup: Query = firestore.collectionGroup(randomCollectionName); const queryFn = queryGroupFn || (ref => ref); const stocks = new AngularFirestoreCollectionGroup(queryFn(collectionGroup), afs); - let names = await createRandomStocks(afs.firestore, ref, items); + const names = await createRandomStocks(afs.firestore, ref, items); return { randomCollectionName, ref, stocks, names }; } describe('AngularFirestoreCollectionGroup', () => { let app: FirebaseApp; let afs: AngularFirestore; - let sub: Subscription; beforeEach(() => { TestBed.configureTestingModule({ @@ -35,10 +44,9 @@ describe('AngularFirestoreCollectionGroup', () => { { provide: SETTINGS, useValue: { host: 'localhost:8080', ssl: false } } ] }); - inject([FirebaseApp, AngularFirestore], (_app: FirebaseApp, _afs: AngularFirestore) => { - app = _app; - afs = _afs; - })(); + + app = TestBed.inject(FirebaseApp); + afs = TestBed.inject(AngularFirestore); }); afterEach(() => { @@ -49,7 +57,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should get unwrapped snapshot', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.valueChanges().subscribe(data => { // unsub immediately as we will be deleting data at the bottom @@ -73,9 +81,10 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle multiple subscriptions (hot)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.valueChanges(); - const sub = changes.subscribe(() => {}).add( + const sub = changes.subscribe(() => { + }).add( changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); sub.unsubscribe(); @@ -87,10 +96,11 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle multiple subscriptions (warm)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.valueChanges(); - changes.pipe(take(1)).subscribe(() => {}).add(() => { - const sub = changes.pipe(take(1)).subscribe(data => { + changes.pipe(take(1)).subscribe(() => { + }).add(() => { + changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); }).add(() => { deleteThemAll(names, ref).then(done).catch(done.fail); @@ -101,22 +111,22 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle dynamic queries that return empty sets', async (done) => { const ITEMS = 10; let count = 0; - let firstIndex = 0; - let pricefilter$ = new BehaviorSubject(null); + + const pricefilter$ = new BehaviorSubject(null); const randomCollectionName = randomName(afs.firestore); const ref = afs.firestore.collection(`${randomCollectionName}`); - let names = await createRandomStocks(afs.firestore, ref, ITEMS); + const names = await createRandomStocks(afs.firestore, ref, ITEMS); const sub = pricefilter$.pipe(switchMap(price => { - return afs.collection(randomCollectionName, ref => price ? ref.where('price', '==', price) : ref).valueChanges() + return afs.collection(randomCollectionName, ref => price ? ref.where('price', '==', price) : ref).valueChanges(); })).subscribe(data => { count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { expect(data.length).toEqual(ITEMS); pricefilter$.next(-1); } // on the second round, we should have filtered out everything - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(0); sub.unsubscribe(); deleteThemAll(names, ref).then(done).catch(done.fail); @@ -131,18 +141,17 @@ describe('AngularFirestoreCollectionGroup', () => { it('should listen to all snapshotChanges() by default', async (done) => { const ITEMS = 10; let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.snapshotChanges().subscribe(data => { - const ids = data.map(d => d.payload.doc.id); count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { // make an update - ref.doc(names[0]).update({ price: 2}); + ref.doc(names[0]).update({ price: 2 }); } // on the second round, make sure the array is still the same // length but the updated item is now modified - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(ITEMS); const change = data.filter(x => x.payload.doc.id === names[0])[0]; expect(change.type).toEqual('modified'); @@ -154,9 +163,10 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle multiple subscriptions (hot)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.snapshotChanges(); - const sub = changes.subscribe(() => {}).add( + const sub = changes.subscribe(() => { + }).add( changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); sub.unsubscribe(); @@ -168,10 +178,11 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle multiple subscriptions (warm)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.snapshotChanges(); - changes.pipe(take(1)).subscribe(() => {}).add(() => { - const sub = changes.pipe(take(1)).subscribe(data => { + changes.pipe(take(1)).subscribe(() => { + }).add(() => { + changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); }).add(() => { deleteThemAll(names, ref).then(done).catch(done.fail); @@ -183,19 +194,19 @@ describe('AngularFirestoreCollectionGroup', () => { const ITEMS = 10; let count = 0; let firstIndex = 0; - const { randomCollectionName, ref, stocks, names } = + const { ref, stocks, names } = await collectionHarness(afs, ITEMS, ref => ref.orderBy('price', 'desc')); const sub = stocks.snapshotChanges().subscribe(data => { count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { // make an update firstIndex = data.filter(d => d.payload.doc.id === names[0])[0].payload.newIndex; ref.doc(names[0]).update({ price: 2 }); } // on the second round, make sure the array is still the same // length but the updated item is now modified - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(ITEMS); const change = data.filter(x => x.payload.doc.id === names[0])[0]; expect(change.type).toEqual('modified'); @@ -208,7 +219,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter snapshotChanges() types - modified', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.snapshotChanges(['modified']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); @@ -224,7 +235,9 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter snapshotChanges() types - added', async (done) => { const ITEMS = 10; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const harness = await collectionHarness(afs, ITEMS); + const { randomCollectionName, ref, stocks } = harness; + let { names } = harness; const nextId = ref.doc('a').id; const sub = stocks.snapshotChanges(['added']).pipe(skip(1)).subscribe(data => { @@ -246,8 +259,8 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter snapshotChanges() types - added w/same id', async (done) => { const ITEMS = 10; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); - + const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const sub = stocks.snapshotChanges(['added']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); const change = data.filter(x => x.payload.doc.id === names[0])[1]; @@ -265,20 +278,24 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter snapshotChanges() types - added/modified', async (done) => { const ITEMS = 10; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + + const harness = await collectionHarness(afs, ITEMS); + const { ref, stocks } = harness; + let { names } = harness; + const nextId = ref.doc('a').id; let count = 0; - const sub = stocks.snapshotChanges(['added', 'modified']).pipe(skip(1),take(2)).subscribe(data => { + stocks.snapshotChanges(['added', 'modified']).pipe(skip(1), take(2)).subscribe(data => { count += 1; - if (count == 1) { + if (count === 1) { const change = data.filter(x => x.payload.doc.id === nextId)[0]; expect(data.length).toEqual(ITEMS + 1); expect(change.payload.doc.data().price).toEqual(2); expect(change.type).toEqual('added'); delayUpdate(ref, names[0], { price: 2 }); } - if (count == 2) { + if (count === 2) { const change = data.filter(x => x.payload.doc.id === names[0])[0]; expect(data.length).toEqual(ITEMS + 1); expect(change.payload.doc.data().price).toEqual(2); @@ -294,7 +311,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter snapshotChanges() types - removed', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.snapshotChanges(['added', 'removed']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); @@ -314,7 +331,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should get stateChanges() updates', async (done: any) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.stateChanges().subscribe(data => { // unsub immediately as we will be deleting data at the bottom @@ -337,13 +354,13 @@ describe('AngularFirestoreCollectionGroup', () => { it('should listen to all stateChanges() by default', async (done) => { const ITEMS = 10; let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); - const sub = stocks.stateChanges().subscribe(data => { + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); + stocks.stateChanges().subscribe(data => { count = count + 1; - if(count === 1) { - ref.doc(names[0]).update({ price: 2}); + if (count === 1) { + ref.doc(names[0]).update({ price: 2 }); } - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(1); expect(data[0].type).toEqual('modified'); deleteThemAll(names, ref).then(done).catch(done.fail); @@ -353,9 +370,10 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle multiple subscriptions (hot)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.stateChanges(); - const sub = changes.subscribe(() => {}).add( + const sub = changes.subscribe(() => { + }).add( changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); sub.unsubscribe(); @@ -367,10 +385,11 @@ describe('AngularFirestoreCollectionGroup', () => { it('should handle multiple subscriptions (warm)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.stateChanges(); - changes.pipe(take(1)).subscribe(() => {}).add(() => { - const sub = changes.pipe(take(1)).subscribe(data => { + changes.pipe(take(1)).subscribe(() => { + }).add(() => { + changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); }).add(() => { deleteThemAll(names, ref).then(done).catch(done.fail); @@ -380,8 +399,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter stateChanges() types - modified', async (done) => { const ITEMS = 10; - let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.stateChanges(['modified']).subscribe(data => { sub.unsubscribe(); @@ -397,8 +415,11 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter stateChanges() types - added', async (done) => { const ITEMS = 10; - let count = 0; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + + const harness = await collectionHarness(afs, ITEMS); + const { ref, stocks } = harness; + let { names } = harness; + const sub = stocks.stateChanges(['added']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); @@ -416,7 +437,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter stateChanges() types - removed', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.stateChanges(['removed']).subscribe(data => { sub.unsubscribe(); @@ -434,13 +455,13 @@ describe('AngularFirestoreCollectionGroup', () => { it('should listen to all events for auditTrail() by default', async (done) => { const ITEMS = 10; let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.auditTrail().subscribe(data => { count = count + 1; - if(count === 1) { - ref.doc(names[0]).update({ price: 2}); + if (count === 1) { + ref.doc(names[0]).update({ price: 2 }); } - if(count === 2) { + if (count === 2) { sub.unsubscribe(); expect(data.length).toEqual(ITEMS + 1); expect(data[data.length - 1].type).toEqual('modified'); @@ -451,7 +472,7 @@ describe('AngularFirestoreCollectionGroup', () => { it('should be able to filter auditTrail() types - removed', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.auditTrail(['removed']).subscribe(data => { sub.unsubscribe(); diff --git a/src/firestore/collection-group/collection-group.ts b/src/firestore/collection-group/collection-group.ts index b20942d14..1c3aff9fd 100644 --- a/src/firestore/collection-group/collection-group.ts +++ b/src/firestore/collection-group/collection-group.ts @@ -1,9 +1,9 @@ -import { Observable, from } from 'rxjs'; +import { from, Observable } from 'rxjs'; import { fromCollectionRef } from '../observable/fromRef'; -import { map, filter, scan, observeOn } from 'rxjs/operators'; +import { filter, map, observeOn, scan } from 'rxjs/operators'; import { firestore } from 'firebase/app'; -import { DocumentChangeType, Query, DocumentData, DocumentChangeAction } from '../interfaces'; +import { DocumentChangeAction, DocumentChangeType, DocumentData, Query } from '../interfaces'; import { validateEventsArray } from '../collection/collection'; import { docChanges, sortedChanges } from '../collection/changes'; import { AngularFirestore } from '../firestore'; @@ -26,12 +26,10 @@ import { AngularFirestore } from '../firestore'; * // Subscribe to changes as snapshots. This provides you data updates as well as delta updates. * fakeStock.valueChanges().subscribe(value => console.log(value)); */ -export class AngularFirestoreCollectionGroup { +export class AngularFirestoreCollectionGroup { /** * The constructor takes in a CollectionGroupQuery to provide wrapper methods * for data operations and data streaming. - * @param query - * @param afs */ constructor( private readonly query: Query, @@ -41,10 +39,9 @@ export class AngularFirestoreCollectionGroup { * Listen to the latest change in the stream. This method returns changes * as they occur and they are not sorted by query order. This allows you to construct * your own data structure. - * @param events */ stateChanges(events?: DocumentChangeType[]): Observable[]> { - if(!events || events.length === 0) { + if (!events || events.length === 0) { return docChanges(this.query, this.afs.schedulers.outsideAngular).pipe( this.afs.keepUnstableUntilFirst ); @@ -60,7 +57,6 @@ export class AngularFirestoreCollectionGroup { /** * Create a stream of changes as they occur it time. This method is similar to stateChanges() * but it collects each event in an array over time. - * @param events */ auditTrail(events?: DocumentChangeType[]): Observable[]> { return this.stateChanges(events).pipe(scan((current, action) => [...current, ...action], [])); @@ -69,7 +65,6 @@ export class AngularFirestoreCollectionGroup { /** * Create a stream of synchronized changes. This method keeps the local array in sorted * query order. - * @param events */ snapshotChanges(events?: DocumentChangeType[]): Observable[]> { const validatedEvents = validateEventsArray(events); @@ -93,7 +88,6 @@ export class AngularFirestoreCollectionGroup { /** * Retrieve the results of the query once. - * @param options */ get(options?: firestore.GetOptions) { return from(this.query.get(options)).pipe( diff --git a/src/firestore/collection/changes.ts b/src/firestore/collection/changes.ts index d42ab0b86..07f0d12ba 100644 --- a/src/firestore/collection/changes.ts +++ b/src/firestore/collection/changes.ts @@ -2,12 +2,11 @@ import { fromCollectionRef } from '../observable/fromRef'; import { Observable, SchedulerLike } from 'rxjs'; import { map, scan } from 'rxjs/operators'; -import { Query, DocumentChangeType, DocumentChange, DocumentChangeAction } from '../interfaces'; +import { DocumentChange, DocumentChangeAction, DocumentChangeType, Query } from '../interfaces'; /** * Return a stream of document changes on a query. These results are not in sort order but in * order of occurence. - * @param query */ export function docChanges(query: Query, scheduler?: SchedulerLike): Observable[]> { return fromCollectionRef(query, scheduler) @@ -19,9 +18,11 @@ export function docChanges(query: Query, scheduler?: SchedulerLike): Observab /** * Return a stream of document changes on a query. These results are in sort order. - * @param query */ -export function sortedChanges(query: Query, events: DocumentChangeType[], scheduler?: SchedulerLike): Observable[]> { +export function sortedChanges( + query: Query, + events: DocumentChangeType[], + scheduler?: SchedulerLike): Observable[]> { return fromCollectionRef(query, scheduler) .pipe( map(changes => changes.payload.docChanges()), @@ -32,14 +33,11 @@ export function sortedChanges(query: Query, events: DocumentChangeType[], sch /** * Combines the total result set from the current set of changes from an incoming set * of changes. - * @param current - * @param changes - * @param events */ export function combineChanges(current: DocumentChange[], changes: DocumentChange[], events: DocumentChangeType[]) { changes.forEach(change => { // skip unwanted change types - if(events.indexOf(change.type) > -1) { + if (events.indexOf(change.type) > -1) { current = combineChange(current, change); } }); @@ -48,11 +46,9 @@ export function combineChanges(current: DocumentChange[], changes: Documen /** * Creates a new sorted array from a new change. - * @param combined - * @param change */ export function combineChange(combined: DocumentChange[], change: DocumentChange): DocumentChange[] { - switch(change.type) { + switch (change.type) { case 'added': if (combined[change.newIndex] && combined[change.newIndex].doc.ref.isEqual(change.doc.ref)) { // Not sure why the duplicates are getting fired @@ -64,7 +60,7 @@ export function combineChange(combined: DocumentChange[], change: Document if (combined[change.oldIndex] == null || combined[change.oldIndex].doc.ref.isEqual(change.doc.ref)) { // When an item changes position we first remove it // and then add it's new position - if(change.oldIndex !== change.newIndex) { + if (change.oldIndex !== change.newIndex) { combined.splice(change.oldIndex, 1); combined.splice(change.newIndex, 0, change); } else { diff --git a/src/firestore/collection/collection.spec.ts b/src/firestore/collection/collection.spec.ts index 864b22ba4..5d1951a59 100644 --- a/src/firestore/collection/collection.spec.ts +++ b/src/firestore/collection/collection.spec.ts @@ -1,30 +1,41 @@ -import { FirebaseApp, AngularFireModule } from '@angular/fire'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; import { AngularFirestore, SETTINGS } from '../firestore'; import { AngularFirestoreModule } from '../firestore.module'; import { AngularFirestoreCollection } from './collection'; import { QueryFn } from '../interfaces'; -import { Observable, BehaviorSubject, Subscription } from 'rxjs'; -import { skip, take, switchMap } from 'rxjs/operators'; +import { BehaviorSubject } from 'rxjs'; +import { skip, switchMap, take } from 'rxjs/operators'; import 'firebase/firestore'; -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; -import { Stock, randomName, FAKE_STOCK_DATA, createRandomStocks, delayAdd, delayDelete, delayUpdate, deleteThemAll, rando } from '../utils.spec'; +import { + createRandomStocks, + delayAdd, + delayDelete, + delayUpdate, + deleteThemAll, + FAKE_STOCK_DATA, + rando, + randomName, + Stock +} from '../utils.spec'; async function collectionHarness(afs: AngularFirestore, items: number, queryFn?: QueryFn) { const randomCollectionName = randomName(afs.firestore); const ref = afs.firestore.collection(`${randomCollectionName}`); - if(!queryFn) { queryFn = (ref) => ref; } + if (!queryFn) { + queryFn = (ref) => ref; + } const stocks = new AngularFirestoreCollection(ref, queryFn(ref), afs); - let names = await createRandomStocks(afs.firestore, ref, items); + const names = await createRandomStocks(afs.firestore, ref, items); return { randomCollectionName, ref, stocks, names }; } describe('AngularFirestoreCollection', () => { let app: FirebaseApp; let afs: AngularFirestore; - let sub: Subscription; beforeEach(() => { TestBed.configureTestingModule({ @@ -36,10 +47,9 @@ describe('AngularFirestoreCollection', () => { { provide: SETTINGS, useValue: { host: 'localhost:8080', ssl: false } } ] }); - inject([FirebaseApp, AngularFirestore], (_app: FirebaseApp, _afs: AngularFirestore) => { - app = _app; - afs = _afs; - })(); + + app = TestBed.inject(FirebaseApp); + afs = TestBed.inject(AngularFirestore); }); afterEach(() => { @@ -50,7 +60,7 @@ describe('AngularFirestoreCollection', () => { it('should get unwrapped snapshot', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.valueChanges().subscribe(data => { // unsub immediately as we will be deleting data at the bottom @@ -72,25 +82,26 @@ describe('AngularFirestoreCollection', () => { }); -/* FLAKE? timing out - it('should optionally map the doc ID to the emitted data object', async (done: any) => { - const ITEMS = 1; - const { ref, stocks, names } = await collectionHarness(afs, ITEMS); - const idField = 'myCustomID'; - const sub = stocks.valueChanges({idField}).subscribe(data => { - sub.unsubscribe(); - const stock = data[0]; - expect(stock[idField]).toBeDefined(); - expect(stock).toEqual(jasmine.objectContaining(FAKE_STOCK_DATA)); - deleteThemAll(names, ref).then(done).catch(fail); - }) - });*/ + /* FLAKE? timing out + it('should optionally map the doc ID to the emitted data object', async (done: any) => { + const ITEMS = 1; + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); + const idField = 'myCustomID'; + const sub = stocks.valueChanges({idField}).subscribe(data => { + sub.unsubscribe(); + const stock = data[0]; + expect(stock[idField]).toBeDefined(); + expect(stock).toEqual(jasmine.objectContaining(FAKE_STOCK_DATA)); + deleteThemAll(names, ref).then(done).catch(fail); + }) + });*/ it('should handle multiple subscriptions (hot)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.valueChanges(); - const sub = changes.subscribe(() => {}).add( + const sub = changes.subscribe(() => { + }).add( changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); sub.unsubscribe(); @@ -102,10 +113,11 @@ describe('AngularFirestoreCollection', () => { it('should handle multiple subscriptions (warm)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.valueChanges(); - changes.pipe(take(1)).subscribe(() => {}).add(() => { - const sub = changes.pipe(take(1)).subscribe(data => { + changes.pipe(take(1)).subscribe(() => { + }).add(() => { + changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); }).add(() => { deleteThemAll(names, ref).then(done).catch(done.fail); @@ -116,22 +128,22 @@ describe('AngularFirestoreCollection', () => { it('should handle dynamic queries that return empty sets', async (done) => { const ITEMS = 10; let count = 0; - let firstIndex = 0; - let pricefilter$ = new BehaviorSubject(null); + + const pricefilter$ = new BehaviorSubject(null); const randomCollectionName = randomName(afs.firestore); const ref = afs.firestore.collection(`${randomCollectionName}`); - let names = await createRandomStocks(afs.firestore, ref, ITEMS); + const names = await createRandomStocks(afs.firestore, ref, ITEMS); const sub = pricefilter$.pipe(switchMap(price => { - return afs.collection(randomCollectionName, ref => price ? ref.where('price', '==', price) : ref).valueChanges() + return afs.collection(randomCollectionName, ref => price ? ref.where('price', '==', price) : ref).valueChanges(); })).subscribe(data => { count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { expect(data.length).toEqual(ITEMS); pricefilter$.next(-1); } // on the second round, we should have filtered out everything - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(0); sub.unsubscribe(); deleteThemAll(names, ref).then(done).catch(done.fail); @@ -146,18 +158,17 @@ describe('AngularFirestoreCollection', () => { it('should listen to all snapshotChanges() by default', async (done) => { const ITEMS = 10; let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.snapshotChanges().subscribe(data => { - const ids = data.map(d => d.payload.doc.id); count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { // make an update - stocks.doc(names[0]).update({ price: 2}); + stocks.doc(names[0]).update({ price: 2 }); } // on the second round, make sure the array is still the same // length but the updated item is now modified - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(ITEMS); const change = data.filter(x => x.payload.doc.id === names[0])[0]; expect(change.type).toEqual('modified'); @@ -169,9 +180,10 @@ describe('AngularFirestoreCollection', () => { it('should handle multiple subscriptions (hot)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.snapshotChanges(); - const sub = changes.subscribe(() => {}).add( + const sub = changes.subscribe(() => { + }).add( changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); sub.unsubscribe(); @@ -183,10 +195,11 @@ describe('AngularFirestoreCollection', () => { it('should handle multiple subscriptions (warm)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.snapshotChanges(); - changes.pipe(take(1)).subscribe(() => {}).add(() => { - const sub = changes.pipe(take(1)).subscribe(data => { + changes.pipe(take(1)).subscribe(() => { + }).add(() => { + changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); }).add(() => { deleteThemAll(names, ref).then(done).catch(done.fail); @@ -198,19 +211,19 @@ describe('AngularFirestoreCollection', () => { const ITEMS = 10; let count = 0; let firstIndex = 0; - const { randomCollectionName, ref, stocks, names } = + const { ref, stocks, names } = await collectionHarness(afs, ITEMS, ref => ref.orderBy('price', 'desc')); const sub = stocks.snapshotChanges().subscribe(data => { count = count + 1; // the first time should all be 'added' - if(count === 1) { + if (count === 1) { // make an update firstIndex = data.filter(d => d.payload.doc.id === names[0])[0].payload.newIndex; stocks.doc(names[0]).update({ price: 2 }); } // on the second round, make sure the array is still the same // length but the updated item is now modified - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(ITEMS); const change = data.filter(x => x.payload.doc.id === names[0])[0]; expect(change.type).toEqual('modified'); @@ -223,7 +236,7 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter snapshotChanges() types - modified', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.snapshotChanges(['modified']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); @@ -239,7 +252,10 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter snapshotChanges() types - added', async (done) => { const ITEMS = 10; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const harness = await collectionHarness(afs, ITEMS); + const { ref, stocks } = harness; + let names = harness.names; + const nextId = ref.doc('a').id; const sub = stocks.snapshotChanges(['added']).pipe(skip(1)).subscribe(data => { @@ -259,20 +275,23 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter snapshotChanges() types - added/modified', async (done) => { const ITEMS = 10; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const harness = await collectionHarness(afs, ITEMS); + const { ref, stocks } = harness; + let names = harness.names; + const nextId = ref.doc('a').id; let count = 0; - const sub = stocks.snapshotChanges(['added', 'modified']).pipe(skip(1),take(2)).subscribe(data => { + stocks.snapshotChanges(['added', 'modified']).pipe(skip(1), take(2)).subscribe(data => { count += 1; - if (count == 1) { + if (count === 1) { const change = data.filter(x => x.payload.doc.id === nextId)[0]; expect(data.length).toEqual(ITEMS + 1); expect(change.payload.doc.data().price).toEqual(2); expect(change.type).toEqual('added'); delayUpdate(stocks, names[0], { price: 2 }); } - if (count == 2) { + if (count === 2) { const change = data.filter(x => x.payload.doc.id === names[0])[0]; expect(data.length).toEqual(ITEMS + 1); expect(change.payload.doc.data().price).toEqual(2); @@ -288,7 +307,7 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter snapshotChanges() types - removed', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.snapshotChanges(['added', 'removed']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); @@ -308,7 +327,7 @@ describe('AngularFirestoreCollection', () => { it('should get stateChanges() updates', async (done: any) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.stateChanges().subscribe(data => { // unsub immediately as we will be deleting data at the bottom @@ -331,13 +350,13 @@ describe('AngularFirestoreCollection', () => { it('should listen to all stateChanges() by default', async (done) => { const ITEMS = 10; let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); - const sub = stocks.stateChanges().subscribe(data => { + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); + stocks.stateChanges().subscribe(data => { count = count + 1; - if(count === 1) { - stocks.doc(names[0]).update({ price: 2}); + if (count === 1) { + stocks.doc(names[0]).update({ price: 2 }); } - if(count === 2) { + if (count === 2) { expect(data.length).toEqual(1); expect(data[0].type).toEqual('modified'); deleteThemAll(names, ref).then(done).catch(done.fail); @@ -347,9 +366,10 @@ describe('AngularFirestoreCollection', () => { it('should handle multiple subscriptions (hot)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.stateChanges(); - const sub = changes.subscribe(() => {}).add( + const sub = changes.subscribe(() => { + }).add( changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); sub.unsubscribe(); @@ -361,10 +381,11 @@ describe('AngularFirestoreCollection', () => { it('should handle multiple subscriptions (warm)', async (done: any) => { const ITEMS = 4; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const changes = stocks.stateChanges(); - changes.pipe(take(1)).subscribe(() => {}).add(() => { - const sub = changes.pipe(take(1)).subscribe(data => { + changes.pipe(take(1)).subscribe(() => { + }).add(() => { + changes.pipe(take(1)).subscribe(data => { expect(data.length).toEqual(ITEMS); }).add(() => { deleteThemAll(names, ref).then(done).catch(done.fail); @@ -374,8 +395,7 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter stateChanges() types - modified', async (done) => { const ITEMS = 10; - let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.stateChanges(['modified']).subscribe(data => { sub.unsubscribe(); @@ -391,8 +411,10 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter stateChanges() types - added', async (done) => { const ITEMS = 10; - let count = 0; - let { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + + const harness = await collectionHarness(afs, ITEMS); + const { ref, stocks } = harness; + let names = harness.names; const sub = stocks.stateChanges(['added']).pipe(skip(1)).subscribe(data => { sub.unsubscribe(); @@ -410,7 +432,7 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter stateChanges() types - removed', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.stateChanges(['removed']).subscribe(data => { sub.unsubscribe(); @@ -428,13 +450,13 @@ describe('AngularFirestoreCollection', () => { it('should listen to all events for auditTrail() by default', async (done) => { const ITEMS = 10; let count = 0; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.auditTrail().subscribe(data => { count = count + 1; - if(count === 1) { - stocks.doc(names[0]).update({ price: 2}); + if (count === 1) { + stocks.doc(names[0]).update({ price: 2 }); } - if(count === 2) { + if (count === 2) { sub.unsubscribe(); expect(data.length).toEqual(ITEMS + 1); expect(data[data.length - 1].type).toEqual('modified'); @@ -445,7 +467,7 @@ describe('AngularFirestoreCollection', () => { it('should be able to filter auditTrail() types - removed', async (done) => { const ITEMS = 10; - const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS); + const { ref, stocks, names } = await collectionHarness(afs, ITEMS); const sub = stocks.auditTrail(['removed']).subscribe(data => { sub.unsubscribe(); diff --git a/src/firestore/collection/collection.ts b/src/firestore/collection/collection.ts index b816480ff..94a953577 100644 --- a/src/firestore/collection/collection.ts +++ b/src/firestore/collection/collection.ts @@ -1,15 +1,15 @@ -import { Observable, from } from 'rxjs'; +import { from, Observable } from 'rxjs'; import { fromCollectionRef } from '../observable/fromRef'; -import { map, filter, scan, observeOn } from 'rxjs/operators'; +import { filter, map, observeOn, scan } from 'rxjs/operators'; import { firestore } from 'firebase/app'; -import { DocumentChangeType, CollectionReference, Query, DocumentReference, DocumentData, DocumentChangeAction } from '../interfaces'; +import { CollectionReference, DocumentChangeAction, DocumentChangeType, DocumentData, DocumentReference, Query } from '../interfaces'; import { docChanges, sortedChanges } from './changes'; import { AngularFirestoreDocument } from '../document/document'; import { AngularFirestore } from '../firestore'; export function validateEventsArray(events?: DocumentChangeType[]) { - if(!events || events!.length === 0) { + if (!events || events.length === 0) { events = ['added', 'removed', 'modified']; } return events; @@ -38,7 +38,7 @@ export function validateEventsArray(events?: DocumentChangeType[]) { * // Subscribe to changes as snapshots. This provides you data updates as well as delta updates. * fakeStock.valueChanges().subscribe(value => console.log(value)); */ -export class AngularFirestoreCollection { +export class AngularFirestoreCollection { /** * The constructor takes in a CollectionReference and Query to provide wrapper methods * for data operations and data streaming. @@ -47,7 +47,6 @@ export class AngularFirestoreCollection { * when you update data it is not updating data to the window of your query unless * the data fits the criteria of the query. See the AssociatedRefence type for details * on this implication. - * @param ref */ constructor( public readonly ref: CollectionReference, @@ -58,10 +57,9 @@ export class AngularFirestoreCollection { * Listen to the latest change in the stream. This method returns changes * as they occur and they are not sorted by query order. This allows you to construct * your own data structure. - * @param events */ stateChanges(events?: DocumentChangeType[]): Observable[]> { - if(!events || events.length === 0) { + if (!events || events.length === 0) { return docChanges(this.query, this.afs.schedulers.outsideAngular).pipe( this.afs.keepUnstableUntilFirst ); @@ -76,7 +74,6 @@ export class AngularFirestoreCollection { /** * Create a stream of changes as they occur it time. This method is similar to stateChanges() * but it collects each event in an array over time. - * @param events */ auditTrail(events?: DocumentChangeType[]): Observable[]> { return this.stateChanges(events).pipe(scan((current, action) => [...current, ...action], [])); @@ -85,7 +82,6 @@ export class AngularFirestoreCollection { /** * Create a stream of synchronized changes. This method keeps the local array in sorted * query order. - * @param events */ snapshotChanges(events?: DocumentChangeType[]): Observable[]> { const validatedEvents = validateEventsArray(events); @@ -100,22 +96,22 @@ export class AngularFirestoreCollection { * * If the `idField` option is provided, document IDs are included and mapped to the * provided `idField` property name. - * @param options */ - valueChanges(): Observable - valueChanges({}): Observable - valueChanges(options: {idField: K}): Observable<(T & { [T in K]: string })[]> + valueChanges(): Observable; + // tslint:disable-next-line:unified-signatures + valueChanges({}): Observable; + valueChanges(options: {idField: K}): Observable<(T & { [T in K]: string })[]>; valueChanges(options: {idField?: K} = {}): Observable { return fromCollectionRef(this.query, this.afs.schedulers.outsideAngular) .pipe( map(actions => actions.payload.docs.map(a => { if (options.idField) { return { - ...a.data() as Object, + ...a.data() as {}, ...{ [options.idField]: a.id } } as T & { [T in K]: string }; } else { - return a.data() + return a.data(); } })), this.afs.keepUnstableUntilFirst @@ -124,7 +120,6 @@ export class AngularFirestoreCollection { /** * Retrieve the results of the query once. - * @param options */ get(options?: firestore.GetOptions) { return from(this.query.get(options)).pipe( @@ -145,7 +140,6 @@ export class AngularFirestoreCollection { /** * Create a reference to a single document in a collection. - * @param path */ doc(path?: string): AngularFirestoreDocument { return new AngularFirestoreDocument(this.ref.doc(path), this.afs); diff --git a/src/firestore/document/document.spec.ts b/src/firestore/document/document.spec.ts index b05eb516a..a6acc0b52 100644 --- a/src/firestore/document/document.spec.ts +++ b/src/firestore/document/document.spec.ts @@ -1,20 +1,18 @@ -import { FirebaseApp, AngularFireModule } from '@angular/fire'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; import { AngularFirestore, SETTINGS } from '../firestore'; import { AngularFirestoreModule } from '../firestore.module'; -import { AngularFirestoreDocument } from '../document/document'; -import { Observable, Subscription } from 'rxjs'; +import { AngularFirestoreDocument } from './document'; import { take } from 'rxjs/operators'; -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../../test-config'; -import { Stock, randomName, FAKE_STOCK_DATA, rando } from '../utils.spec'; +import { FAKE_STOCK_DATA, rando, randomName, Stock } from '../utils.spec'; import 'firebase/firestore'; describe('AngularFirestoreDocument', () => { let app: FirebaseApp; let afs: AngularFirestore; - let sub: Subscription; beforeEach(() => { TestBed.configureTestingModule({ @@ -26,10 +24,9 @@ describe('AngularFirestoreDocument', () => { { provide: SETTINGS, useValue: { host: 'localhost:8080', ssl: false } } ] }); - inject([FirebaseApp, AngularFirestore], (_app: FirebaseApp, _afs: AngularFirestore) => { - app = _app; - afs = _afs; - })(); + + app = TestBed.inject(FirebaseApp); + afs = TestBed.inject(AngularFirestore); }); afterEach(() => { @@ -59,7 +56,7 @@ describe('AngularFirestoreDocument', () => { await stock.set(FAKE_STOCK_DATA); const obs$ = stock.valueChanges(); obs$.pipe(take(1)).subscribe(async data => { - expect(JSON.stringify(data)).toBe(JSON.stringify(FAKE_STOCK_DATA)); + expect(data).toEqual(FAKE_STOCK_DATA); stock.delete().then(done).catch(done.fail); }); }); diff --git a/src/firestore/document/document.ts b/src/firestore/document/document.ts index 62c854936..8592c5a5f 100644 --- a/src/firestore/document/document.ts +++ b/src/firestore/document/document.ts @@ -1,5 +1,5 @@ -import { Observable, from } from 'rxjs'; -import { DocumentReference, SetOptions, DocumentData, QueryFn, Action, DocumentSnapshot } from '../interfaces'; +import { from, Observable } from 'rxjs'; +import { Action, DocumentData, DocumentReference, DocumentSnapshot, QueryFn, SetOptions } from '../interfaces'; import { fromDocRef } from '../observable/fromRef'; import { map, observeOn } from 'rxjs/operators'; import { AngularFirestore, associateQuery } from '../firestore'; @@ -28,19 +28,16 @@ import { firestore } from 'firebase/app'; * // OR! Transform using Observable.from() and the data is unwrapped for you * Observable.from(fakeStock).subscribe(value => console.log(value)); */ -export class AngularFirestoreDocument { +export class AngularFirestoreDocument { /** * The contstuctor takes in a DocumentReference to provide wrapper methods * for data operations, data streaming, and Symbol.observable. - * @param ref */ constructor(public ref: DocumentReference, private afs: AngularFirestore) { } /** * Create or overwrite a single document. - * @param data - * @param options */ set(data: T, options?: SetOptions): Promise { return this.ref.set(data, options); @@ -48,7 +45,6 @@ export class AngularFirestoreDocument { /** * Update some fields of a document without overwriting the entire document. - * @param data */ update(data: Partial): Promise { return this.ref.update(data); @@ -64,10 +60,8 @@ export class AngularFirestoreDocument { /** * Create a reference to a sub-collection given a path and an optional query * function. - * @param path - * @param queryFn */ - collection(path: string, queryFn?: QueryFn): AngularFirestoreCollection { + collection(path: string, queryFn?: QueryFn): AngularFirestoreCollection { const collectionRef = this.ref.collection(path); const { ref, query } = associateQuery(collectionRef, queryFn); return new AngularFirestoreCollection(ref, query, this.afs); @@ -80,7 +74,7 @@ export class AngularFirestoreDocument { const scheduledFromDocRef$ = fromDocRef(this.ref, this.afs.schedulers.outsideAngular); return scheduledFromDocRef$.pipe( this.afs.keepUnstableUntilFirst - ) + ); } /** @@ -96,7 +90,6 @@ export class AngularFirestoreDocument { /** * Retrieve the document once. - * @param options */ get(options?: firestore.GetOptions) { return from(this.ref.get(options)).pipe( diff --git a/src/firestore/firestore.module.ts b/src/firestore/firestore.module.ts index 8d0468863..0e1b673b8 100644 --- a/src/firestore/firestore.module.ts +++ b/src/firestore/firestore.module.ts @@ -16,6 +16,6 @@ export class AngularFirestoreModule { { provide: ENABLE_PERSISTENCE, useValue: true }, { provide: PERSISTENCE_SETTINGS, useValue: persistenceSettings }, ] - } + }; } } diff --git a/src/firestore/firestore.spec.ts b/src/firestore/firestore.spec.ts index c97c160af..be957cd4b 100644 --- a/src/firestore/firestore.spec.ts +++ b/src/firestore/firestore.spec.ts @@ -1,25 +1,17 @@ -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; import { AngularFirestore, SETTINGS } from './firestore'; import { AngularFirestoreModule } from './firestore.module'; import { AngularFirestoreDocument } from './document/document'; import { AngularFirestoreCollection } from './collection/collection'; -import { Observable, Subscription } from 'rxjs'; - -import { TestBed, inject } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { COMMON_CONFIG } from '../test-config'; import 'firebase/firestore'; import { rando } from './utils.spec'; -interface Stock { - name: string; - price: number; -} - describe('AngularFirestore', () => { let app: FirebaseApp; let afs: AngularFirestore; - let sub: Subscription; beforeEach(() => { TestBed.configureTestingModule({ @@ -31,10 +23,9 @@ describe('AngularFirestore', () => { { provide: SETTINGS, useValue: { host: 'localhost:8080', ssl: false } } ] }); - inject([FirebaseApp, AngularFirestore], (_app: FirebaseApp, _afs: AngularFirestore) => { - app = _app; - afs = _afs; - })(); + + app = TestBed.inject(FirebaseApp); + afs = TestBed.inject(AngularFirestore); }); afterEach(() => { @@ -55,8 +46,7 @@ describe('AngularFirestore', () => { }); it('should create an AngularFirestoreDocument from a string path', () => { - const ref = afs.doc('a/doc').ref; - const doc = afs.doc(ref); + const doc = afs.doc(afs.doc('a/doc').ref); expect(doc instanceof AngularFirestoreDocument).toBe(true); }); @@ -66,8 +56,7 @@ describe('AngularFirestore', () => { }); it('should create an AngularFirestoreCollection from a reference', () => { - const ref = afs.collection('stuffs').ref; - const collection = afs.collection(ref); + const collection = afs.collection(afs.collection('stuffs').ref); expect(collection instanceof AngularFirestoreCollection).toBe(true); }); @@ -85,19 +74,19 @@ describe('AngularFirestore', () => { expect(quadWrapper).toThrowError(); }); - if (typeof window == 'undefined') { - + if (typeof window === 'undefined') { + it('should not enable persistence (Node.js)', (done) => { - const sub = afs.persistenceEnabled$.subscribe(isEnabled => { + afs.persistenceEnabled$.subscribe(isEnabled => { expect(isEnabled).toBe(false); done(); }); }); } else { - + it('should enable persistence', (done) => { - const sub = afs.persistenceEnabled$.subscribe(isEnabled => { + afs.persistenceEnabled$.subscribe(isEnabled => { expect(isEnabled).toBe(true); done(); }); @@ -125,10 +114,10 @@ describe('AngularFirestore with different app', () => { { provide: SETTINGS, useValue: { host: 'localhost:8080', ssl: false } } ] }); - inject([FirebaseApp, AngularFirestore], (app_: FirebaseApp, _afs: AngularFirestore) => { - app = app_; - afs = _afs; - })(); + + + app = TestBed.inject(FirebaseApp); + afs = TestBed.inject(AngularFirestore); }); afterEach(() => { @@ -167,10 +156,9 @@ describe('AngularFirestore without persistance', () => { { provide: SETTINGS, useValue: { host: 'localhost:8080', ssl: false } } ] }); - inject([FirebaseApp, AngularFirestore], (_app: FirebaseApp, _afs: AngularFirestore) => { - app = _app; - afs = _afs; - })(); + + app = TestBed.inject(FirebaseApp); + afs = TestBed.inject(AngularFirestore); }); afterEach(() => { diff --git a/src/firestore/firestore.ts b/src/firestore/firestore.ts index 0ef5b2ee2..7dbddc33f 100644 --- a/src/firestore/firestore.ts +++ b/src/firestore/firestore.ts @@ -1,10 +1,27 @@ -import { InjectionToken, NgZone, PLATFORM_ID, Injectable, Inject, Optional } from '@angular/core'; -import { Observable, of, from } from 'rxjs'; -import { Settings, PersistenceSettings, CollectionReference, DocumentReference, QueryFn, Query, QueryGroupFn, AssociatedReference } from './interfaces'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { from, Observable, of } from 'rxjs'; +import { + AssociatedReference, + CollectionReference, + DocumentReference, + PersistenceSettings, + Query, + QueryFn, + QueryGroupFn, + Settings +} from './interfaces'; import { AngularFirestoreDocument } from './document/document'; import { AngularFirestoreCollection } from './collection/collection'; import { AngularFirestoreCollectionGroup } from './collection-group/collection-group'; -import { FirebaseOptions, FirebaseAppConfig, FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵfirebaseAppFactory, ɵAngularFireSchedulers, ɵkeepUnstableUntilFirstFactory } from '@angular/fire'; +import { + FIREBASE_APP_NAME, + FIREBASE_OPTIONS, + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵfirebaseAppFactory, + ɵkeepUnstableUntilFirstFactory +} from '@angular/fire'; import { isPlatformServer } from '@angular/common'; import { firestore } from 'firebase/app'; import firebase from '@firebase/app'; @@ -15,7 +32,7 @@ import 'firebase/firestore'; * The value of this token determines whether or not the firestore will have persistance enabled */ export const ENABLE_PERSISTENCE = new InjectionToken('angularfire2.enableFirestorePersistence'); -export const PERSISTENCE_SETTINGS = new InjectionToken('angularfire2.firestore.persistenceSettings'); +export const PERSISTENCE_SETTINGS = new InjectionToken('angularfire2.firestore.persistenceSettings'); export const SETTINGS = new InjectionToken('angularfire2.firestore.settings'); /** @@ -104,28 +121,32 @@ export class AngularFirestore { * Each Feature of AngularFire has a FirebaseApp injected. This way we * don't rely on the main Firebase App instance and we can create named * apps and use multiple apps. - * @param app */ constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, - @Optional() @Inject(ENABLE_PERSISTENCE) shouldEnablePersistence: boolean|null, - @Optional() @Inject(SETTINGS) settings: Settings|null, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, + @Optional() @Inject(ENABLE_PERSISTENCE) shouldEnablePersistence: boolean | null, + @Optional() @Inject(SETTINGS) settings: Settings | null, + // tslint:disable-next-line:ban-types @Inject(PLATFORM_ID) platformId: Object, zone: NgZone, - @Optional() @Inject(PERSISTENCE_SETTINGS) persistenceSettings: PersistenceSettings|null, + @Optional() @Inject(PERSISTENCE_SETTINGS) persistenceSettings: PersistenceSettings | null ) { this.schedulers = new ɵAngularFireSchedulers(zone); - this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers, platformId); + this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers); this.firestore = zone.runOutsideAngular(() => { const app = ɵfirebaseAppFactory(options, zone, nameOrConfig); // INVESTIGATE this seems to be required because in the browser build registerFirestore is an Object? // seems like we're fighting ngcc. In the server firestore() isn't available, so I have to register // in the browser registerFirestore is not a function... maybe this is an underlying firebase-js-sdk issue - if (registerFirestore) { registerFirestore(firebase) } + if (registerFirestore) { + registerFirestore(firebase); + } const firestore = app.firestore(); - if (settings) { firestore.settings(settings) } + if (settings) { + firestore.settings(settings); + } return firestore; }); @@ -135,7 +156,7 @@ export class AngularFirestore { const enablePersistence = () => { try { return from(this.firestore.enablePersistence(persistenceSettings || undefined).then(() => true, () => false)); - } catch(e) { + } catch (e) { return of(false); } }; @@ -149,11 +170,10 @@ export class AngularFirestore { * Create a reference to a Firestore Collection based on a path or * CollectionReference and an optional query function to narrow the result * set. - * @param pathOrRef - * @param queryFn */ - collection(path: string, queryFn?: QueryFn): AngularFirestoreCollection - collection(ref: CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection + collection(path: string, queryFn?: QueryFn): AngularFirestoreCollection; + // tslint:disable-next-line:unified-signatures + collection(ref: CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection; collection(pathOrRef: string | CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection { let collectionRef: CollectionReference; if (typeof pathOrRef === 'string') { @@ -162,15 +182,14 @@ export class AngularFirestore { collectionRef = pathOrRef; } const { ref, query } = associateQuery(collectionRef, queryFn); - return new AngularFirestoreCollection(ref, query, this); + const refInZone = this.schedulers.ngZone.run(() => ref); + return new AngularFirestoreCollection(refInZone, query, this); } /** * Create a reference to a Firestore Collection Group based on a collectionId * and an optional query function to narrow the result * set. - * @param collectionId - * @param queryGroupFn */ collectionGroup(collectionId: string, queryGroupFn?: QueryGroupFn): AngularFirestoreCollectionGroup { const queryFn = queryGroupFn || (ref => ref); @@ -183,10 +202,10 @@ export class AngularFirestore { * DocumentReference. Note that documents are not queryable because they are * simply objects. However, documents have sub-collections that return a * Collection reference and can be queried. - * @param pathOrRef */ - doc(path: string): AngularFirestoreDocument - doc(ref: DocumentReference): AngularFirestoreDocument + doc(path: string): AngularFirestoreDocument; + // tslint:disable-next-line:unified-signatures + doc(ref: DocumentReference): AngularFirestoreDocument; doc(pathOrRef: string | DocumentReference): AngularFirestoreDocument { let ref: DocumentReference; if (typeof pathOrRef === 'string') { @@ -194,13 +213,14 @@ export class AngularFirestore { } else { ref = pathOrRef; } - return new AngularFirestoreDocument(ref, this); + const refInZone = this.schedulers.ngZone.run(() => ref); + return new AngularFirestoreDocument(refInZone, this); } /** * Returns a generated Firestore Document Id. */ createId() { - return this.firestore.collection('_').doc().id + return this.firestore.collection('_').doc().id; } } diff --git a/src/firestore/interfaces.ts b/src/firestore/interfaces.ts index 549022742..8a8461fdd 100644 --- a/src/firestore/interfaces.ts +++ b/src/firestore/interfaces.ts @@ -46,7 +46,7 @@ export interface DocumentChangeAction { export interface Action { type: string; payload: T; -}; +} export interface Reference { onSnapshot: (sub: Subscriber) => any; diff --git a/src/firestore/observable/fromRef.ts b/src/firestore/observable/fromRef.ts index 2f87f629a..bfdd345e1 100644 --- a/src/firestore/observable/fromRef.ts +++ b/src/firestore/observable/fromRef.ts @@ -1,5 +1,5 @@ -import { Observable, SchedulerLike, asyncScheduler } from 'rxjs'; -import { DocumentReference, Query, Action, Reference, DocumentSnapshot, QuerySnapshot } from '../interfaces'; +import { asyncScheduler, Observable, SchedulerLike } from 'rxjs'; +import { Action, DocumentReference, DocumentSnapshot, Query, QuerySnapshot, Reference } from '../interfaces'; import { map } from 'rxjs/operators'; function _fromRef(ref: Reference, scheduler: SchedulerLike = asyncScheduler): Observable { @@ -13,11 +13,11 @@ function _fromRef(ref: Reference, scheduler: SchedulerLike = asyncSched unsubscribe = ref.onSnapshot(subscriber); } - return function() { + return () => { if (unsubscribe != null) { unsubscribe(); } - } + }; }); } @@ -25,7 +25,7 @@ export function fromRef(ref: DocumentReference | Query, scheduler?: Scheduler return _fromRef(ref, scheduler); } -export function fromDocRef(ref: DocumentReference, scheduler?: SchedulerLike): Observable>>{ +export function fromDocRef(ref: DocumentReference, scheduler?: SchedulerLike): Observable>> { return fromRef>(ref, scheduler) .pipe( map(payload => ({ payload, type: 'value' })) diff --git a/src/firestore/public_api.ts b/src/firestore/public_api.ts index dbfa0fdaa..1670f1451 100644 --- a/src/firestore/public_api.ts +++ b/src/firestore/public_api.ts @@ -5,4 +5,4 @@ export * from './collection-group/collection-group'; export * from './document/document'; export * from './collection/changes'; export * from './observable/fromRef'; -export * from './interfaces' +export * from './interfaces'; diff --git a/src/firestore/utils.spec.ts b/src/firestore/utils.spec.ts index 5f68df978..e0bfa187d 100644 --- a/src/firestore/utils.spec.ts +++ b/src/firestore/utils.spec.ts @@ -14,7 +14,7 @@ export const createRandomStocks = async (firestore: firestore.Firestore, collect // Create a batch to update everything at once const batch = firestore.batch(); // Store the random names to delete them later - let count = 0; + const count = 0; let names: string[] = []; Array.from(Array(numberOfItems)).forEach((a, i) => { const name = randomName(firestore); @@ -25,7 +25,7 @@ export const createRandomStocks = async (firestore: firestore.Firestore, collect // Commit! await batch.commit(); return names; -} +}; export function deleteThemAll(names, ref) { const promises = names.map(name => ref.doc(name).delete()); @@ -50,4 +50,4 @@ export function delayDelete(collection: AngularFirestoreCollection|firesto }, delay); } -export const rando = () => (Math.random() + 1).toString(36).substring(7); \ No newline at end of file +export const rando = () => (Math.random() + 1).toString(36).substring(7); diff --git a/src/functions/functions.spec.ts b/src/functions/functions.spec.ts index 08b333e3e..f316f6ddf 100644 --- a/src/functions/functions.spec.ts +++ b/src/functions/functions.spec.ts @@ -1,6 +1,6 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; -import { AngularFireFunctions, AngularFireFunctionsModule, REGION, ORIGIN } from './public_api'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; +import { AngularFireFunctions, AngularFireFunctionsModule, ORIGIN, REGION } from './public_api'; import { COMMON_CONFIG } from '../test-config'; import 'firebase/functions'; import { rando } from '../firestore/utils.spec'; @@ -16,10 +16,9 @@ describe('AngularFireFunctions', () => { AngularFireFunctionsModule ] }); - inject([FirebaseApp, AngularFireFunctions], (app_: FirebaseApp, _fn: AngularFireFunctions) => { - app = app_; - afFns = _fn; - })(); + + app = TestBed.inject(FirebaseApp); + afFns = TestBed.inject(AngularFireFunctions); }); afterEach(() => { @@ -55,10 +54,9 @@ describe('AngularFireFunctions with different app', () => { { provide: REGION, useValue: 'asia-northeast1' } ] }); - inject([FirebaseApp, AngularFireFunctions], (app_: FirebaseApp, _fns: AngularFireFunctions) => { - app = app_; - afFns = _fns; - })(); + + app = TestBed.inject(FirebaseApp); + afFns = TestBed.inject(AngularFireFunctions); }); afterEach(() => { diff --git a/src/functions/functions.ts b/src/functions/functions.ts index d767577a7..d2d2476b9 100644 --- a/src/functions/functions.ts +++ b/src/functions/functions.ts @@ -1,29 +1,38 @@ -import { Injectable, Inject, Optional, NgZone, InjectionToken } from '@angular/core'; -import { of, from, Observable } from 'rxjs'; -import { map, switchMap, shareReplay, tap, observeOn } from 'rxjs/operators'; -import { FirebaseOptions, FirebaseAppConfig, FIREBASE_APP_NAME, ɵlazySDKProxy, ɵPromiseProxy, ɵAngularFireSchedulers } from '@angular/fire'; -import { FIREBASE_OPTIONS, ɵfirebaseAppFactory } from '@angular/fire'; +import { Inject, Injectable, InjectionToken, NgZone, Optional } from '@angular/core'; +import { from, Observable, of } from 'rxjs'; +import { map, observeOn, shareReplay, switchMap, tap } from 'rxjs/operators'; +import { + FIREBASE_APP_NAME, + FIREBASE_OPTIONS, + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵfirebaseAppFactory, + ɵlazySDKProxy, + ɵPromiseProxy +} from '@angular/fire'; import { functions } from 'firebase/app'; export const ORIGIN = new InjectionToken('angularfire2.functions.origin'); export const REGION = new InjectionToken('angularfire2.functions.region'); // override httpsCallable for compatibility with 5.x -export interface AngularFireFunctions extends Omit<ɵPromiseProxy, 'httpsCallable'> { }; +export interface AngularFireFunctions extends Omit<ɵPromiseProxy, 'httpsCallable'> { +} @Injectable({ providedIn: 'any' }) export class AngularFireFunctions { - public readonly httpsCallable: (name: string) => (data: T) => Observable + public readonly httpsCallable: (name: string) => (data: T) => Observable; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, zone: NgZone, - @Optional() @Inject(REGION) region:string|null, - @Optional() @Inject(ORIGIN) origin:string|null + @Optional() @Inject(REGION) region: string | null, + @Optional() @Inject(ORIGIN) origin: string | null ) { const schedulers = new ɵAngularFireSchedulers(zone); @@ -33,17 +42,19 @@ export class AngularFireFunctions { map(() => ɵfirebaseAppFactory(options, zone, nameOrConfig)), map(app => app.functions(region || undefined)), tap(functions => { - if (origin) { functions.useFunctionsEmulator(origin) } + if (origin) { + functions.useFunctionsEmulator(origin); + } }), - shareReplay({ bufferSize: 1, refCount: false }), + shareReplay({ bufferSize: 1, refCount: false }) ); - this.httpsCallable = (name: string) => + this.httpsCallable = (name: string) => (data: T) => from(functions).pipe( observeOn(schedulers.outsideAngular), switchMap(functions => functions.httpsCallable(name)(data)), map(r => r.data as R) - ) + ); return ɵlazySDKProxy(this, functions, zone); diff --git a/src/messaging/messaging.spec.ts b/src/messaging/messaging.spec.ts index 9210fff58..8ff1fdc72 100644 --- a/src/messaging/messaging.spec.ts +++ b/src/messaging/messaging.spec.ts @@ -1,6 +1,5 @@ -import { ReflectiveInjector, Provider } from '@angular/core'; -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; import { AngularFireMessaging, AngularFireMessagingModule } from './public_api'; import { COMMON_CONFIG } from '../test-config'; import { rando } from '../firestore/utils.spec'; @@ -16,10 +15,9 @@ describe('AngularFireMessaging', () => { AngularFireMessagingModule ] }); - inject([FirebaseApp, AngularFireMessaging], (app_: FirebaseApp, _afm: AngularFireMessaging) => { - app = app_; - afm = _afm; - })(); + + app = TestBed.inject(FirebaseApp); + afm = TestBed.inject(AngularFireMessaging); }); afterEach(() => { @@ -53,10 +51,9 @@ describe('AngularFireMessaging with different app', () => { { provide: FIREBASE_OPTIONS, useValue: COMMON_CONFIG } ] }); - inject([FirebaseApp, AngularFireMessaging], (app_: FirebaseApp, _afm: AngularFireMessaging) => { - app = app_; - afm = _afm; - })(); + + app = TestBed.inject(FirebaseApp); + afm = TestBed.inject(AngularFireMessaging); }); afterEach(() => { diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts index 4f993ff31..30c070a75 100644 --- a/src/messaging/messaging.ts +++ b/src/messaging/messaging.ts @@ -1,12 +1,21 @@ -import { Injectable, Inject, Optional, NgZone, PLATFORM_ID } from '@angular/core'; +import { Inject, Injectable, NgZone, Optional, PLATFORM_ID } from '@angular/core'; import { messaging } from 'firebase/app'; -import { Observable, empty, of, throwError } from 'rxjs'; -import { mergeMap, catchError, map, switchMap, concat, observeOn, defaultIfEmpty } from 'rxjs/operators'; -import { FirebaseOptions, FirebaseAppConfig, ɵAngularFireSchedulers, FIREBASE_APP_NAME, FIREBASE_OPTIONS, ɵlazySDKProxy, ɵPromiseProxy } from '@angular/fire'; -import { ɵfirebaseAppFactory } from '@angular/fire'; +import { concat, EMPTY, Observable, of, throwError } from 'rxjs'; +import { catchError, defaultIfEmpty, map, mergeMap, observeOn, switchMap } from 'rxjs/operators'; +import { + FIREBASE_APP_NAME, + FIREBASE_OPTIONS, + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵfirebaseAppFactory, + ɵlazySDKProxy, + ɵPromiseProxy +} from '@angular/fire'; import { isPlatformServer } from '@angular/common'; -export interface AngularFireMessaging extends Omit<ɵPromiseProxy, 'deleteToken'|'getToken'|'requestPermission'> {}; +export interface AngularFireMessaging extends Omit<ɵPromiseProxy, 'deleteToken' | 'getToken' | 'requestPermission'> { +} @Injectable({ providedIn: 'any' @@ -14,15 +23,16 @@ export interface AngularFireMessaging extends Omit<ɵPromiseProxy; - public readonly getToken: Observable; - public readonly tokenChanges: Observable; + public readonly getToken: Observable; + public readonly tokenChanges: Observable; public readonly messages: Observable<{}>; - public readonly requestToken: Observable; + public readonly requestToken: Observable; public readonly deleteToken: (token: string) => Observable; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, + // tslint:disable-next-line:ban-types @Inject(PLATFORM_ID) platformId: Object, zone: NgZone ) { @@ -30,7 +40,7 @@ export class AngularFireMessaging { const messaging = of(undefined).pipe( observeOn(schedulers.outsideAngular), - switchMap(() => isPlatformServer(platformId) ? empty() : import('firebase/messaging')), + switchMap(() => isPlatformServer(platformId) ? EMPTY : import('firebase/messaging')), map(() => ɵfirebaseAppFactory(options, zone, nameOrConfig)), map(app => app.messaging()) ); @@ -39,20 +49,21 @@ export class AngularFireMessaging { this.requestPermission = messaging.pipe( observeOn(schedulers.outsideAngular), - switchMap(messaging => messaging.requestPermission()), + // tslint:disable-next-line + switchMap(messaging => messaging.requestPermission()) ); - + } else { - + this.requestPermission = throwError('Not available on server platform.'); - + } this.getToken = messaging.pipe( observeOn(schedulers.outsideAngular), switchMap(messaging => messaging.getToken()), defaultIfEmpty(null) - ) + ); const tokenChanges = messaging.pipe( observeOn(schedulers.outsideAngular), @@ -61,10 +72,12 @@ export class AngularFireMessaging { )) ); - this.tokenChanges = messaging.pipe( - observeOn(schedulers.outsideAngular), - switchMap(messaging => messaging.getToken()), - concat(tokenChanges) + this.tokenChanges = concat( + messaging.pipe( + observeOn(schedulers.outsideAngular), + switchMap(messaging => messaging.getToken()) + ), + tokenChanges ); this.messages = messaging.pipe( diff --git a/src/performance/performance.module.ts b/src/performance/performance.module.ts index 1a414e9cf..da1ac7d78 100644 --- a/src/performance/performance.module.ts +++ b/src/performance/performance.module.ts @@ -11,6 +11,7 @@ export class AngularFirePerformanceModule { @Optional() _: PerformanceMonitoringService ) { // call anything here to get perf loading - perf.dataCollectionEnabled + // tslint:disable-next-line:no-unused-expression + perf.dataCollectionEnabled; } } diff --git a/src/performance/performance.service.ts b/src/performance/performance.service.ts index 04d24d01d..4f1c6bc2f 100644 --- a/src/performance/performance.service.ts +++ b/src/performance/performance.service.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy, ApplicationRef } from '@angular/core'; +import { ApplicationRef, Injectable, OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs'; import { first, tap } from 'rxjs/operators'; @@ -6,7 +6,7 @@ const IS_STABLE_START_MARK = '_isStableStart'; const IS_STABLE_END_MARK = '_isStableEnd'; function markStarts() { - if (typeof(window) !== "undefined" && window.performance) { + if (typeof(window) !== 'undefined' && window.performance) { window.performance.mark(IS_STABLE_START_MARK); return true; } else { @@ -39,4 +39,4 @@ export class PerformanceMonitoringService implements OnDestroy { if (this.disposable) { this.disposable.unsubscribe(); } } -} \ No newline at end of file +} diff --git a/src/performance/performance.spec.ts b/src/performance/performance.spec.ts index 3f064be8f..c07832f3e 100644 --- a/src/performance/performance.spec.ts +++ b/src/performance/performance.spec.ts @@ -1,5 +1,5 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, AngularFireModule } from '@angular/fire'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FirebaseApp } from '@angular/fire'; import { AngularFirePerformance, AngularFirePerformanceModule } from './public_api'; import { COMMON_CONFIG } from '../test-config'; import { rando } from '../firestore/utils.spec'; @@ -15,10 +15,9 @@ describe('AngularFirePerformance', () => { AngularFirePerformanceModule ] }); - inject([FirebaseApp, AngularFirePerformance], (app_: FirebaseApp, _perf: AngularFirePerformance) => { - app = app_; - afp = _perf; - })(); + + app = TestBed.inject(FirebaseApp); + afp = TestBed.inject(AngularFirePerformance); }); afterEach(() => { diff --git a/src/performance/performance.ts b/src/performance/performance.ts index 0869cf8bd..aee6caf21 100644 --- a/src/performance/performance.ts +++ b/src/performance/performance.ts @@ -1,8 +1,8 @@ -import { Injectable, NgZone, InjectionToken, Inject, Optional, PLATFORM_ID } from '@angular/core'; -import { Observable, Subscription, of, empty } from 'rxjs'; -import { tap, map, shareReplay, switchMap } from 'rxjs/operators'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { EMPTY, Observable, of, Subscription } from 'rxjs'; +import { map, shareReplay, switchMap, tap } from 'rxjs/operators'; import { performance } from 'firebase/app'; -import { FirebaseApp, ɵPromiseProxy, ɵlazySDKProxy } from '@angular/fire'; +import { FirebaseApp, ɵlazySDKProxy, ɵPromiseProxy } from '@angular/fire'; import { isPlatformBrowser } from '@angular/common'; // SEMVER @ v6, drop and move core ng metrics to a service @@ -10,31 +10,37 @@ export const AUTOMATICALLY_TRACE_CORE_NG_METRICS = new InjectionToken(' export const INSTRUMENTATION_ENABLED = new InjectionToken('angularfire2.performance.instrumentationEnabled'); export const DATA_COLLECTION_ENABLED = new InjectionToken('angularfire2.performance.dataCollectionEnabled'); -export interface AngularFirePerformance extends ɵPromiseProxy {}; +export interface AngularFirePerformance extends ɵPromiseProxy { +} @Injectable({ providedIn: 'any' }) export class AngularFirePerformance { - + private readonly performance: Observable; constructor( app: FirebaseApp, - @Optional() @Inject(INSTRUMENTATION_ENABLED) instrumentationEnabled:boolean|null, - @Optional() @Inject(DATA_COLLECTION_ENABLED) dataCollectionEnabled:boolean|null, + @Optional() @Inject(INSTRUMENTATION_ENABLED) instrumentationEnabled: boolean | null, + @Optional() @Inject(DATA_COLLECTION_ENABLED) dataCollectionEnabled: boolean | null, private zone: NgZone, - @Inject(PLATFORM_ID) platformId:Object + // tslint:disable-next-line:ban-types + @Inject(PLATFORM_ID) platformId: Object ) { this.performance = of(undefined).pipe( - switchMap(() => isPlatformBrowser(platformId) ? zone.runOutsideAngular(() => import('firebase/performance')) : empty()), + switchMap(() => isPlatformBrowser(platformId) ? zone.runOutsideAngular(() => import('firebase/performance')) : EMPTY), map(() => zone.runOutsideAngular(() => app.performance())), tap(performance => { - if (instrumentationEnabled == false) { performance.instrumentationEnabled = false } - if (dataCollectionEnabled == false) { performance.dataCollectionEnabled = false } + if (instrumentationEnabled !== true) { + performance.instrumentationEnabled = false; + } + if (dataCollectionEnabled !== true) { + performance.dataCollectionEnabled = false; + } }), - shareReplay({ bufferSize: 1, refCount: false }), + shareReplay({ bufferSize: 1, refCount: false }) ); return ɵlazySDKProxy(this, this.performance, zone); @@ -43,7 +49,7 @@ export class AngularFirePerformance { } -const trace$ = (traceId:string) => { +const trace$ = (traceId: string) => { if (typeof window !== 'undefined' && window.performance) { const entries = window.performance.getEntriesByName(traceId, 'measure') || []; const startMarkName = `_${traceId}Start[${entries.length}]`; @@ -51,73 +57,93 @@ const trace$ = (traceId:string) => { return new Observable(emitter => { window.performance.mark(startMarkName); emitter.next(); - return { unsubscribe: () => { - window.performance.mark(endMarkName); - window.performance.measure(traceId, startMarkName, endMarkName); - }}; + return { + unsubscribe: () => { + window.performance.mark(endMarkName); + window.performance.measure(traceId, startMarkName, endMarkName); + } + }; }); } else { - return empty(); + return EMPTY; } -} +}; -export const traceUntil = (name:string, test: (a:T) => boolean, options?: { orComplete?: boolean }) => (source$: Observable) => new Observable(subscriber => { +export const traceUntil = ( + name: string, + test: (a: T) => boolean, + options?: { orComplete?: boolean } +) => (source$: Observable) => new Observable(subscriber => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( tap( - a => test(a) && traceSubscription.unsubscribe(), - () => {}, + a => test(a) && traceSubscription.unsubscribe(), + () => { + }, () => options && options.orComplete && traceSubscription.unsubscribe() ) ).subscribe(subscriber); }); -export const traceWhile = (name:string, test: (a:T) => boolean, options?: { orComplete?: boolean}) => (source$: Observable) => new Observable(subscriber => { - let traceSubscription: Subscription|undefined; +export const traceWhile = ( + name: string, + test: (a: T) => boolean, + options?: { orComplete?: boolean } +) => (source$: Observable) => new Observable(subscriber => { + let traceSubscription: Subscription | undefined; return source$.pipe( tap( - a => { + a => { if (test(a)) { traceSubscription = traceSubscription || trace$(name).subscribe(); } else { - traceSubscription && traceSubscription.unsubscribe(); + if (traceSubscription) { + traceSubscription.unsubscribe(); + } + traceSubscription = undefined; } }, - () => {}, + () => { + }, () => options && options.orComplete && traceSubscription && traceSubscription.unsubscribe() ) ).subscribe(subscriber); }); -export const traceUntilComplete = (name:string) => (source$: Observable) => new Observable(subscriber => { +export const traceUntilComplete = (name: string) => (source$: Observable) => new Observable(subscriber => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( tap( - () => {}, - () => {}, + () => { + }, + () => { + }, () => traceSubscription.unsubscribe() ) ).subscribe(subscriber); }); -export const traceUntilFirst = (name:string) => (source$: Observable) => new Observable(subscriber => { +export const traceUntilFirst = (name: string) => (source$: Observable) => new Observable(subscriber => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( tap( () => traceSubscription.unsubscribe(), - () => {}, - () => {} + () => { + }, + () => { + } ) ).subscribe(subscriber); }); -export const trace = (name:string) => (source$: Observable) => new Observable(subscriber => { +export const trace = (name: string) => (source$: Observable) => new Observable(subscriber => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( tap( () => traceSubscription.unsubscribe(), - () => {}, + () => { + }, () => traceSubscription.unsubscribe() ) ).subscribe(subscriber); diff --git a/src/remote-config/public_api.ts b/src/remote-config/public_api.ts index af5b96822..f3239f665 100644 --- a/src/remote-config/public_api.ts +++ b/src/remote-config/public_api.ts @@ -1,2 +1,2 @@ export * from './remote-config'; -export * from './remote-config.module'; \ No newline at end of file +export * from './remote-config.module'; diff --git a/src/remote-config/remote-config.spec.ts b/src/remote-config/remote-config.spec.ts index b8e969176..aa3a87924 100644 --- a/src/remote-config/remote-config.spec.ts +++ b/src/remote-config/remote-config.spec.ts @@ -1,7 +1,6 @@ -import { ReflectiveInjector, Provider } from '@angular/core'; -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; -import { AngularFireRemoteConfig, AngularFireRemoteConfigModule, SETTINGS, DEFAULTS } from './public_api'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; +import { AngularFireRemoteConfig, AngularFireRemoteConfigModule, DEFAULTS, SETTINGS } from './public_api'; import { COMMON_CONFIG } from '../test-config'; import { rando } from '../firestore/utils.spec'; @@ -16,10 +15,9 @@ describe('AngularFireRemoteConfig', () => { AngularFireRemoteConfigModule ] }); - inject([FirebaseApp, AngularFireRemoteConfig], (app_: FirebaseApp, _rc: AngularFireRemoteConfig) => { - app = app_; - rc = _rc; - })(); + + app = TestBed.inject(FirebaseApp); + rc = TestBed.inject(AngularFireRemoteConfig); }); afterEach(() => { @@ -55,10 +53,9 @@ describe('AngularFireRemoteConfig with different app', () => { { provide: DEFAULTS, useValue: {} } ] }); - inject([FirebaseApp, AngularFireRemoteConfig], (app_: FirebaseApp, _rc: AngularFireRemoteConfig) => { - app = app_; - rc = _rc; - })(); + + app = TestBed.inject(FirebaseApp); + rc = TestBed.inject(AngularFireRemoteConfig); }); afterEach(() => { diff --git a/src/remote-config/remote-config.ts b/src/remote-config/remote-config.ts index 92601ffb7..9833a7452 100644 --- a/src/remote-config/remote-config.ts +++ b/src/remote-config/remote-config.ts @@ -1,24 +1,79 @@ -import { Injectable, Inject, Optional, NgZone, InjectionToken, PLATFORM_ID } from '@angular/core'; -import { Observable, concat, of, pipe, OperatorFunction, MonoTypeOperatorFunction, empty, throwError } from 'rxjs'; -import { map, switchMap, tap, shareReplay, distinctUntilChanged, filter, groupBy, mergeMap, scan, withLatestFrom, startWith, debounceTime, observeOn, catchError } from 'rxjs/operators'; -import { ɵPromiseProxy, ɵfirebaseAppFactory, ɵAngularFireSchedulers, FirebaseAppConfig, FirebaseOptions, ɵlazySDKProxy, FIREBASE_OPTIONS, FIREBASE_APP_NAME } from '@angular/fire'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { concat, EMPTY, MonoTypeOperatorFunction, Observable, of, OperatorFunction, pipe } from 'rxjs'; +import { + debounceTime, + distinctUntilChanged, + filter, + groupBy, + map, + mergeMap, + observeOn, + scan, + shareReplay, + startWith, + switchMap, + tap, + withLatestFrom +} from 'rxjs/operators'; +import { + FIREBASE_APP_NAME, + FIREBASE_OPTIONS, + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵfirebaseAppFactory, + ɵkeepUnstableUntilFirstFactory, + ɵlazySDKProxy, + ɵPromiseProxy +} from '@angular/fire'; import { remoteConfig } from 'firebase/app'; import { isPlatformBrowser } from '@angular/common'; -export interface ConfigTemplate {[key:string]: string|number|boolean}; +export interface ConfigTemplate { + [key: string]: string | number | boolean; +} export const SETTINGS = new InjectionToken('angularfire2.remoteConfig.settings'); export const DEFAULTS = new InjectionToken('angularfire2.remoteConfig.defaultConfig'); -export interface AngularFireRemoteConfig extends ɵPromiseProxy {}; +export interface AngularFireRemoteConfig extends ɵPromiseProxy { +} + +const AS_TO_FN = { strings: 'asString', numbers: 'asNumber', booleans: 'asBoolean' }; +const STATIC_VALUES = { numbers: 0, booleans: false, strings: undefined }; + +// TODO look into the types here, I don't like the anys +const proxyAll = (observable: Observable, as: 'numbers' | 'booleans' | 'strings') => new Proxy( + observable.pipe(mapToObject(as as any)), { + get: (self, name: string) => self[name] || observable.pipe( + map(all => all.find(p => p.key === name)), + map(param => param ? param[AS_TO_FN[as]]() : STATIC_VALUES[as]), + distinctUntilChanged() + ) + } +) as any; // TODO export as implements Partial<...> so minor doesn't break us export class Value implements remoteConfig.Value { - asBoolean() { return ['1', 'true', 't', 'y', 'yes', 'on'].indexOf(this._value.toLowerCase()) > -1 } - asString() { return this._value } - asNumber() { return Number(this._value) || 0 } - getSource() { return this._source; } - constructor(public _source: remoteConfig.ValueSource, public _value: string) { } + asBoolean() { + return ['1', 'true', 't', 'y', 'yes', 'on'].indexOf(this._value.toLowerCase()) > -1; + } + + asString() { + return this._value; + } + + asNumber() { + return Number(this._value) || 0; + } + + getSource() { + return this._source; + } + + // tslint:disable-next-line:variable-name + constructor(public _source: remoteConfig.ValueSource, public _value: string) { + } } // SEMVER use ConstructorParameters when we can support Typescript 3.6 @@ -29,7 +84,7 @@ export class Parameter extends Value { } // If it's a Parameter array, test any, else test the individual Parameter -const filterTest = (fn: (param:Parameter) => boolean) => filter(it => Array.isArray(it) ? it.some(fn) : fn(it)) +const filterTest = (fn: (param: Parameter) => boolean) => filter(it => Array.isArray(it) ? it.some(fn) : fn(it)); // Allow the user to bypass the default values and wait till they get something from the server, even if it's a cached copy; // if used in conjuntion with first() it will only fetch RC values from the server if they aren't cached locally @@ -38,37 +93,67 @@ export const filterRemote = () => filterTest(p => p.getSource() === 'remote'); // filterFresh allows the developer to effectively set up a maximum cache time export const filterFresh = (howRecentInMillis: number) => filterTest(p => p.fetchTimeMillis + howRecentInMillis >= new Date().getTime()); + +// I ditched loading the defaults into RC and a simple map for scan since we already have our own defaults implementation. +// The idea here being that if they have a default that never loads from the server, they will be able to tell via fetchTimeMillis +// on the Parameter. Also if it doesn't come from the server it won't emit again in .changes, due to the distinctUntilChanged, +// which we can simplify to === rather than deep comparison +const scanToParametersArray = ( + remoteConfig: Observable +): OperatorFunction<{ [key: string]: remoteConfig.Value }, Parameter[]> => pipe( + withLatestFrom(remoteConfig), + scan((existing, [all, rc]) => { + // SEMVER use "new Set" to unique once we're only targeting es6 + // at the scale we expect remote config to be at, we probably won't see a performance hit from this unoptimized uniqueness + // implementation. + // const allKeys = [...new Set([...existing.map(p => p.key), ...Object.keys(all)])]; + const allKeys = [...existing.map(p => p.key), ...Object.keys(all)].filter((v, i, a) => a.indexOf(v) === i); + return allKeys.map(key => { + const updatedValue = all[key]; + return updatedValue ? new Parameter(key, rc ? rc.fetchTimeMillis : -1, updatedValue.getSource(), updatedValue.asString()) + : existing.find(p => p.key === key); + }); + }, [] as Array) +); + + @Injectable({ providedIn: 'any' }) export class AngularFireRemoteConfig { - readonly changes: Observable; + readonly changes: Observable; readonly parameters: Observable; - readonly numbers: Observable<{[key:string]: number|undefined}> & {[key:string]: Observable}; - readonly booleans: Observable<{[key:string]: boolean|undefined}> & {[key:string]: Observable}; - readonly strings: Observable<{[key:string]: string|undefined}> & {[key:string]: Observable}; + readonly numbers: Observable<{ [key: string]: number | undefined }> & { [key: string]: Observable }; + readonly booleans: Observable<{ [key: string]: boolean | undefined }> & { [key: string]: Observable }; + readonly strings: Observable<{ [key: string]: string | undefined }> & { [key: string]: Observable }; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, - @Optional() @Inject(SETTINGS) settings:remoteConfig.Settings|null, - @Optional() @Inject(DEFAULTS) defaultConfig:ConfigTemplate|null, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, + @Optional() @Inject(SETTINGS) settings: remoteConfig.Settings | null, + @Optional() @Inject(DEFAULTS) defaultConfig: ConfigTemplate | null, private zone: NgZone, - @Inject(PLATFORM_ID) platformId:Object + // tslint:disable-next-line:ban-types + @Inject(PLATFORM_ID) platformId: Object ) { const schedulers = new ɵAngularFireSchedulers(zone); - + const remoteConfig$ = of(undefined).pipe( observeOn(schedulers.outsideAngular), - switchMap(() => isPlatformBrowser(platformId) ? import('firebase/remote-config') : empty()), + switchMap(() => isPlatformBrowser(platformId) ? import('firebase/remote-config') : EMPTY), map(() => ɵfirebaseAppFactory(options, zone, nameOrConfig)), map(app => app.remoteConfig()), tap(rc => { - if (settings) { rc.settings = settings } - if (defaultConfig) { rc.defaultConfig = defaultConfig } + if (settings) { + rc.settings = settings; + } + if (defaultConfig) { + rc.defaultConfig = defaultConfig; + } }), + // tslint:disable-next-line startWith(undefined), shareReplay({ bufferSize: 1, refCount: false }) ); @@ -77,16 +162,16 @@ export class AngularFireRemoteConfig { filter(rc => !!rc) ); - let default$: Observable<{[key:string]: remoteConfig.Value}> = of(Object.keys(defaultConfig || {}).reduce( - (c, k) => ({...c, [k]: new Value("default", defaultConfig![k].toString()) }), {} + const default$: Observable<{ [key: string]: remoteConfig.Value }> = of(Object.keys(defaultConfig || {}).reduce( + (c, k) => ({ ...c, [k]: new Value('default', defaultConfig[k].toString()) }), {} )); // we should filter out the defaults we provided to RC, since we have our own implementation // that gives us a -1 for fetchTimeMillis (so filterFresh can filter them out) - const filterOutDefaults = map<{[key: string]: remoteConfig.Value}, {[key: string]: remoteConfig.Value}>(all => + const filterOutDefaults = map<{ [key: string]: remoteConfig.Value }, { [key: string]: remoteConfig.Value }>(all => Object.keys(all) - .filter(key => all[key].getSource() != 'default') - .reduce((acc, key) => ({...acc, [key]: all[key]}), {}) + .filter(key => all[key].getSource() !== 'default') + .reduce((acc, key) => ({ ...acc, [key]: all[key] }), {}) ); const existing$ = loadedRemoteConfig$.pipe( @@ -109,6 +194,7 @@ export class AngularFireRemoteConfig { this.parameters = concat(default$, existing$, fresh$).pipe( scanToParametersArray(remoteConfig$), + ɵkeepUnstableUntilFirstFactory(schedulers), shareReplay({ bufferSize: 1, refCount: true }) ); @@ -120,108 +206,104 @@ export class AngularFireRemoteConfig { )) ); - this.strings = proxyAll(this.parameters, 'strings'); + this.strings = proxyAll(this.parameters, 'strings'); this.booleans = proxyAll(this.parameters, 'booleans'); - this.numbers = proxyAll(this.parameters, 'numbers'); + this.numbers = proxyAll(this.parameters, 'numbers'); return ɵlazySDKProxy(this, loadedRemoteConfig$, zone); } } -// I ditched loading the defaults into RC and a simple map for scan since we already have our own defaults implementation. -// The idea here being that if they have a default that never loads from the server, they will be able to tell via fetchTimeMillis on the Parameter. -// Also if it doesn't come from the server it won't emit again in .changes, due to the distinctUntilChanged, which we can simplify to === rather than deep comparison -const scanToParametersArray = (remoteConfig: Observable): OperatorFunction<{[key:string]: remoteConfig.Value}, Parameter[]> => pipe( - withLatestFrom(remoteConfig), - scan((existing, [all, rc]) => { - // SEMVER use "new Set" to unique once we're only targeting es6 - // at the scale we expect remote config to be at, we probably won't see a performance hit from this unoptimized uniqueness implementation - // const allKeys = [...new Set([...existing.map(p => p.key), ...Object.keys(all)])]; - const allKeys = [...existing.map(p => p.key), ...Object.keys(all)].filter((v, i, a) => a.indexOf(v) === i); - return allKeys.map(key => { - const updatedValue = all[key]; - return updatedValue ? new Parameter(key, rc ? rc.fetchTimeMillis : -1, updatedValue.getSource(), updatedValue.asString()) - : existing.find(p => p.key === key)! - }); - }, [] as Array) -); - -const AS_TO_FN = { 'strings': 'asString', 'numbers': 'asNumber', 'booleans': 'asBoolean' }; -const STATIC_VALUES = { 'numbers': 0, 'booleans': false, 'strings': undefined }; export const budget = (interval: number): MonoTypeOperatorFunction => (source: Observable) => new Observable(observer => { - let timedOut = false; - // TODO use scheduler task rather than settimeout - const timeout = setTimeout(() => { - observer.complete(); - timedOut = true; - }, interval); - return source.subscribe({ - next(val) { if (!timedOut) { observer.next(val); } }, - error(err) { if (!timedOut) { clearTimeout(timeout); observer.error(err); } }, - complete() { if (!timedOut) { clearTimeout(timeout); observer.complete(); } } - }) + let timedOut = false; + // TODO use scheduler task rather than settimeout + const timeout = setTimeout(() => { + observer.complete(); + timedOut = true; + }, interval); + return source.subscribe({ + next(val) { + if (!timedOut) { + observer.next(val); + } + }, + error(err) { + if (!timedOut) { + clearTimeout(timeout); + observer.error(err); + } + }, + complete() { + if (!timedOut) { + clearTimeout(timeout); + observer.complete(); + } + } }); +}); -const typedMethod = (it:any) => { - switch(typeof it) { - case 'string': return 'asString'; - case 'boolean': return 'asBoolean'; - case 'number': return 'asNumber'; - default: return 'asString'; +const typedMethod = (it: any) => { + switch (typeof it) { + case 'string': + return 'asString'; + case 'boolean': + return 'asBoolean'; + case 'number': + return 'asNumber'; + default: + return 'asString'; } }; -export function scanToObject(): OperatorFunction; -export function scanToObject(to: 'numbers'): OperatorFunction; -export function scanToObject(to: 'booleans'): OperatorFunction; -export function scanToObject(to: 'strings'): OperatorFunction; -export function scanToObject(template: T): OperatorFunction; -export function scanToObject(to: 'numbers'|'booleans'|'strings'|T = 'strings') { + +export function scanToObject(): OperatorFunction; +export function scanToObject(to: 'numbers'): OperatorFunction; +export function scanToObject(to: 'booleans'): OperatorFunction; +// tslint:disable-next-line:unified-signatures +export function scanToObject(to: 'strings'): OperatorFunction; +export function scanToObject(template: T): OperatorFunction; +export function scanToObject(to: 'numbers' | 'booleans' | 'strings' | T = 'strings') { return pipe( // TODO cleanup scan( - (c, p: Parameter) => ({...c, [p.key]: typeof to === 'object' ? - p[typedMethod(to[p.key])]() : - p[AS_TO_FN[to]]() }), + (c, p: Parameter) => ({ + ...c, [p.key]: typeof to === 'object' ? + p[typedMethod(to[p.key])]() : + p[AS_TO_FN[to]]() + }), typeof to === 'object' ? - to as T & {[key:string]: string|undefined}: - {} as {[key:string]: number|boolean|string} + to as T & { [key: string]: string | undefined } : + {} as { [key: string]: number | boolean | string } ), debounceTime(1), budget(10), - distinctUntilChanged((a,b) => JSON.stringify(a) === JSON.stringify(b)) + distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)) ); -}; +} -export function mapToObject(): OperatorFunction; -export function mapToObject(to: 'numbers'): OperatorFunction; -export function mapToObject(to: 'booleans'): OperatorFunction; -export function mapToObject(to: 'strings'): OperatorFunction; -export function mapToObject(template: T): OperatorFunction; -export function mapToObject(to: 'numbers'|'booleans'|'strings'|T = 'strings') { +export function mapToObject(): OperatorFunction; +export function mapToObject(to: 'numbers'): OperatorFunction; +export function mapToObject(to: 'booleans'): OperatorFunction; +// tslint:disable-next-line:unified-signatures +export function mapToObject(to: 'strings'): OperatorFunction; +export function mapToObject(template: T): + OperatorFunction; +export function mapToObject(to: 'numbers' | 'booleans' | 'strings' | T = 'strings') { return pipe( // TODO this is getting a little long, cleanup map((params: Parameter[]) => params.reduce( - (c, p) => ({...c, [p.key]: typeof to === 'object' ? - p[typedMethod(to[p.key])]() : - p[AS_TO_FN[to]]() }), + (c, p) => ({ + ...c, [p.key]: typeof to === 'object' ? + p[typedMethod(to[p.key])]() : + p[AS_TO_FN[to]]() + }), typeof to === 'object' ? - to as T & {[key:string]: string|undefined} : - {} as {[key:string]: number|boolean|string} + to as T & { [key: string]: string | undefined } : + {} as { [key: string]: number | boolean | string } )), - distinctUntilChanged((a,b) => JSON.stringify(a) === JSON.stringify(b)) + distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)) ); -}; +} -// TODO look into the types here, I don't like the anys -const proxyAll = (observable: Observable, as: 'numbers'|'booleans'|'strings') => new Proxy( - observable.pipe(mapToObject(as as any)), { - get: (self, name:string) => self[name] || observable.pipe( - map(all => all.find(p => p.key === name)), - map(param => param ? param[AS_TO_FN[as]]() : STATIC_VALUES[as]), - distinctUntilChanged() - ) - } -) as any; \ No newline at end of file diff --git a/src/schematics/deploy/actions.jasmine.ts b/src/schematics/deploy/actions.jasmine.ts index 9298784dc..c723f07ab 100644 --- a/src/schematics/deploy/actions.jasmine.ts +++ b/src/schematics/deploy/actions.jasmine.ts @@ -1,8 +1,8 @@ -import {experimental, JsonObject, logging} from '@angular-devkit/core'; -import { BuilderContext, BuilderRun, ScheduleOptions, Target, } from '@angular-devkit/architect'; -import {FirebaseTools, FirebaseDeployConfig, BuildTarget, FSHost} from '../interfaces'; -import deploy, {deployToFunction} from './actions'; - +import { experimental, JsonObject, logging } from '@angular-devkit/core'; +import { BuilderContext, BuilderRun, ScheduleOptions, Target } from '@angular-devkit/architect'; +import { BuildTarget, FirebaseDeployConfig, FirebaseTools, FSHost } from '../interfaces'; +import deploy, { deployToFunction } from './actions'; +import 'jasmine'; let context: BuilderContext; let firebaseMock: FirebaseTools; @@ -14,6 +14,58 @@ const BUILD_TARGET: BuildTarget = { name: `${PROJECT}:build:production` }; +const initMocks = () => { + fsHost = { + moveSync(_: string, __: string) { + }, + renameSync(_: string, __: string) { + }, + writeFileSync(_: string, __: string) { + } + }; + + firebaseMock = { + login: () => Promise.resolve(), + projects: { + list: () => Promise.resolve([]) + }, + deploy: (_: FirebaseDeployConfig) => Promise.resolve(), + use: () => Promise.resolve(), + logger: { + add: () => { + } + }, + serve: () => Promise.resolve() + }; + + context = ({ + target: { + configuration: 'production', + project: PROJECT, + target: 'foo' + }, + builder: { + builderName: 'mock', + description: 'mock', + optionSchema: false + }, + currentDirectory: 'cwd', + id: 1, + logger: new logging.NullLogger() as any, + workspaceRoot: 'cwd', + getTargetOptions: (_: Target) => Promise.resolve({}), + reportProgress: (_: number, __?: number, ___?: string) => { + }, + reportStatus: (_: string) => { + }, + reportRunning: () => { + }, + scheduleBuilder: (_: string, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun), + scheduleTarget: (_: Target, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun) + } as any); +}; + + const projectTargets: experimental.workspace.WorkspaceTool = { build: { options: { @@ -68,7 +120,7 @@ describe('Deploy Angular apps', () => { }); }); - describe('error handling', () => { + describe('error handling', () => { it('throws if there is no firebase project', async () => { try { await deploy(firebaseMock, context, projectTargets, [BUILD_TARGET], undefined, false, false); @@ -81,7 +133,7 @@ describe('Deploy Angular apps', () => { it('throws if there is no target project', async () => { context.target = undefined; try { - await deploy(firebaseMock, context, projectTargets, [BUILD_TARGET], FIREBASE_PROJECT, false, false) + await deploy(firebaseMock, context, projectTargets, [BUILD_TARGET], FIREBASE_PROJECT, false, false); } catch (e) { expect(e.message).toMatch(/Cannot execute the build target/); } @@ -133,51 +185,3 @@ describe('universal deployment', () => { expect(spy).not.toHaveBeenCalled(); });*/ }); - -const initMocks = () => { - fsHost = { - moveSync(_: string, __: string) { - }, - renameSync(_: string, __: string) { - }, - writeFileSync(_: string, __: string) { - } - }; - - firebaseMock = { - login: () => Promise.resolve(), - projects: { - list: () => Promise.resolve([]), - }, - deploy: (_: FirebaseDeployConfig) => Promise.resolve(), - use: () => Promise.resolve(), - logger: { - add: () => {} - }, - serve: () => Promise.resolve() - }; - - context = { - target: { - configuration: 'production', - project: PROJECT, - target: 'foo' - }, - builder: { - builderName: 'mock', - description: 'mock', - optionSchema: false - }, - currentDirectory: 'cwd', - id: 1, - logger: new logging.NullLogger() as any, - workspaceRoot: 'cwd', - getTargetOptions: (_: Target) => Promise.resolve({}), - reportProgress: (_: number, __?: number, ___?: string) => { - }, - reportStatus: (_: string) => {}, - reportRunning: () => {}, - scheduleBuilder: (_: string, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun), - scheduleTarget: (_: Target, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun) - }; -}; diff --git a/src/schematics/deploy/actions.ts b/src/schematics/deploy/actions.ts index a76295b14..0a7bab9bf 100644 --- a/src/schematics/deploy/actions.ts +++ b/src/schematics/deploy/actions.ts @@ -1,22 +1,16 @@ -import { - BuilderContext, - targetFromTargetString -} from "@angular-devkit/architect"; -import { BuildTarget, FirebaseTools, FSHost } from "../interfaces"; -import { writeFileSync, renameSync, existsSync, readFileSync } from "fs"; -import { copySync, removeSync } from "fs-extra"; -import { join, dirname } from "path"; -import { execSync } from "child_process"; -import { - defaultFunction, - defaultPackage, - NodeVersion -} from "./functions-templates"; -import { experimental } from "@angular-devkit/core"; -import { SchematicsException } from "@angular-devkit/schematics"; -import { satisfies } from "semver"; - -const escapeRegExp = (str:String) => str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); +import { BuilderContext, targetFromTargetString } from '@angular-devkit/architect'; +import { BuildTarget, FirebaseTools, FSHost } from '../interfaces'; +import { existsSync, readFileSync, renameSync, writeFileSync } from 'fs'; +import { copySync, removeSync } from 'fs-extra'; +import { dirname, join } from 'path'; +import { execSync } from 'child_process'; +import { defaultFunction, defaultPackage, NODE_VERSION } from './functions-templates'; +import { experimental } from '@angular-devkit/core'; +import { SchematicsException } from '@angular-devkit/schematics'; +import { satisfies } from 'semver'; +import * as open from 'open'; + +const escapeRegExp = (str: string) => str.replace(/[\-\[\]\/{}()*+?.\\^$|]/g, '\\$&'); const moveSync = (src: string, dest: string) => { copySync(src, dest); @@ -34,20 +28,20 @@ const deployToHosting = ( const port = 5000; // TODO make this configurable setTimeout(() => { - execSync(`open http://localhost:${port} || true`); + open(`http://localhost:${port}`); }, 1500); - return firebaseTools.serve({ port, targets: ["hosting"]}).then(() => + return firebaseTools.serve({ port, targets: ['hosting'], host: 'localhost' }).then(() => require('inquirer').prompt({ type: 'confirm', name: 'deployProject', - message: "Would you like to deploy your application to Firebase Hosting?" + message: 'Would you like to deploy your application to Firebase Hosting?' }) ).then(({ deployProject }: { deployProject: boolean }) => { if (deployProject) { return firebaseTools.deploy({ // tslint:disable-next-line:no-non-null-assertion - only: "hosting:" + context.target!.project, + only: 'hosting:' + context.target!.project, cwd: workspaceRoot }); } else { @@ -59,7 +53,7 @@ const deployToHosting = ( return firebaseTools.deploy({ // tslint:disable-next-line:no-non-null-assertion - only: "hosting:" + context.target!.project, + only: 'hosting:' + context.target!.project, cwd: workspaceRoot }); @@ -74,6 +68,11 @@ const defaultFsHost: FSHost = { const getVersionRange = (v: number) => `^${v}.0.0`; +const findPackageVersion = (name: string) => { + const match = execSync(`npm list ${name}`).toString().match(` ${escapeRegExp(name)}@.+\\w`); + return match ? match[0].split(`${name}@`)[1] : null; +}; + const getPackageJson = (context: BuilderContext, workspaceRoot: string) => { const dependencies = { 'firebase-admin': 'latest', @@ -82,22 +81,22 @@ const getPackageJson = (context: BuilderContext, workspaceRoot: string) => { const devDependencies = { 'firebase-functions-test': 'latest' }; - const npmList = execSync('npm ls || true').toString(); Object.keys(dependencies).forEach((dependency: string) => { - const npmLsMatch = npmList.match(` ${escapeRegExp(dependency)}@.+\\w`); - if (npmLsMatch) { dependencies[dependency] = npmLsMatch[0].split(`${dependency}@`)[1] } + const packageVersion = findPackageVersion(dependency); + if (packageVersion) { dependencies[dependency] = packageVersion; } }); Object.keys(devDependencies).forEach((devDependency: string) => { - const npmLsMatch = npmList.match(` ${escapeRegExp(devDependency)}@.+\\w`); - if (npmLsMatch) { devDependencies[devDependency] = npmLsMatch[0].split(`${devDependency}@`)[1] } + const packageVersion = findPackageVersion(devDependency); + if (packageVersion) { devDependencies[devDependency] = packageVersion; } }); if (existsSync(join(workspaceRoot, 'angular.json'))) { const angularJson = JSON.parse(readFileSync(join(workspaceRoot, 'angular.json')).toString()); + // tslint:disable-next-line:no-non-null-assertion const server = angularJson.projects[context.target!.project].architect.server; const serverOptions = server && server.options; const externalDependencies = serverOptions && serverOptions.externalDependencies || []; const bundleDependencies = serverOptions && serverOptions.bundleDependencies; - if (bundleDependencies == false) { + if (bundleDependencies !== true) { if (existsSync(join(workspaceRoot, 'package.json'))) { const packageJson = JSON.parse(readFileSync(join(workspaceRoot, 'package.json')).toString()); Object.keys(packageJson.dependencies).forEach((dependency: string) => { @@ -106,8 +105,8 @@ const getPackageJson = (context: BuilderContext, workspaceRoot: string) => { } // TODO should we throw? } else { externalDependencies.forEach(externalDependency => { - const npmLsMatch = npmList.match(` ${escapeRegExp(externalDependency)}@.+\\w`); - if (npmLsMatch) { dependencies[externalDependency] = npmLsMatch[0].split(`${externalDependency}@`)[1] } + const packageVersion = findPackageVersion(externalDependency); + if (packageVersion) { dependencies[externalDependency] = packageVersion; } }); } } // TODO should we throw? @@ -122,9 +121,9 @@ export const deployToFunction = async ( preview: boolean, fsHost: FSHost = defaultFsHost ) => { - if (!satisfies(process.versions.node, getVersionRange(NodeVersion))) { + if (!satisfies(process.versions.node, getVersionRange(NODE_VERSION))) { context.logger.warn( - `⚠️ Your Node.js version (${process.versions.node}) does not match the Firebase Functions runtime (${NodeVersion}).` + `⚠️ Your Node.js version (${process.versions.node}) does not match the Firebase Functions runtime (${NODE_VERSION}).` ); } @@ -163,36 +162,37 @@ export const deployToFunction = async ( fsHost.moveSync(serverOut, newServerPath); fsHost.writeFileSync( - join(dirname(serverOut), "package.json"), + join(dirname(serverOut), 'package.json'), getPackageJson(context, workspaceRoot) ); fsHost.writeFileSync( - join(dirname(serverOut), "index.js"), + join(dirname(serverOut), 'index.js'), defaultFunction(serverOut) ); fsHost.renameSync( - join(newClientPath, "index.html"), - join(newClientPath, "index.original.html") + join(newClientPath, 'index.html'), + join(newClientPath, 'index.original.html') ); if (preview) { const port = 5000; // TODO make this configurable setTimeout(() => { - execSync(`open http://localhost:${port} || true`); + open(`http://localhost:${port}`); }, 1500); - return firebaseTools.serve({ port, targets: ["hosting", "functions"]}).then(() => + return firebaseTools.serve({ port, targets: ['hosting', 'functions'], host: 'localhost'}).then(() => require('inquirer').prompt({ type: 'confirm', name: 'deployProject', - message: "Would you like to deploy your application to Firebase Hosting & Cloud Functions?" + message: 'Would you like to deploy your application to Firebase Hosting & Cloud Functions?' }) ).then(({ deployProject }: { deployProject: boolean }) => { if (deployProject) { return firebaseTools.deploy({ + // tslint:disable-next-line:no-non-null-assertion only: `hosting:${context.target!.project},functions:ssr`, cwd: workspaceRoot }); @@ -202,6 +202,7 @@ export const deployToFunction = async ( }); } else { return firebaseTools.deploy({ + // tslint:disable-next-line:no-non-null-assertion only: `hosting:${context.target!.project},functions:ssr`, cwd: workspaceRoot }); @@ -220,7 +221,7 @@ export default async function deploy( await firebaseTools.login(); if (!context.target) { - throw new Error("Cannot execute the build target"); + throw new Error('Cannot execute the build target'); } context.logger.info(`📦 Building "${context.target.project}"`); @@ -240,24 +241,22 @@ export default async function deploy( } try { - let success: { hosting: string }; - const winston = require('winston'); const tripleBeam = require('triple-beam'); firebaseTools.logger.add( new winston.transports.Console({ - level: "info", + level: 'info', format: winston.format.printf((info) => [info.message, ...(info[tripleBeam.SPLAT] || [])] - .filter((chunk) => typeof chunk == "string") - .join(" ") - ), + .filter((chunk) => typeof chunk === 'string') + .join(' ') + ) }) ); if (ssr) { - success = await deployToFunction( + await deployToFunction( firebaseTools, context, context.workspaceRoot, @@ -265,7 +264,7 @@ export default async function deploy( preview ); } else { - success = await deployToHosting( + await deployToHosting( firebaseTools, context, context.workspaceRoot, diff --git a/src/schematics/deploy/builder.ts b/src/schematics/deploy/builder.ts index 19d328bdb..b47b9e130 100644 --- a/src/schematics/deploy/builder.ts +++ b/src/schematics/deploy/builder.ts @@ -1,12 +1,8 @@ -import { - BuilderContext, - BuilderOutput, - createBuilder -} from '@angular-devkit/architect'; +import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect'; import { NodeJsSyncHost } from '@angular-devkit/core/node'; import deploy from './actions'; -import { experimental, normalize, json } from '@angular-devkit/core'; -import {BuildTarget, DeployBuilderSchema} from '../interfaces'; +import { experimental, json, normalize } from '@angular-devkit/core'; +import { BuildTarget, DeployBuilderSchema } from '../interfaces'; import { getFirebaseProjectName } from '../utils'; type DeployBuilderOptions = DeployBuilderSchema & json.JsonObject; diff --git a/src/schematics/deploy/functions-templates.ts b/src/schematics/deploy/functions-templates.ts index 5ae63270b..6afe45cd8 100644 --- a/src/schematics/deploy/functions-templates.ts +++ b/src/schematics/deploy/functions-templates.ts @@ -1,15 +1,15 @@ // TODO allow these to be configured -export const NodeVersion = 10; +export const NODE_VERSION = 10; const FUNCTION_NAME = 'ssr'; const FUNCTION_REGION = 'us-central1'; const RUNTIME_OPTIONS = { timeoutSeconds: 60, memory: '1GB' -} +}; export const defaultPackage = ( - dependencies: {[key:string]: string}, - devDependencies: {[key:string]: string} + dependencies: {[key: string]: string}, + devDependencies: {[key: string]: string} ) => `{ "name": "functions", "description": "Angular Universal Application", @@ -22,7 +22,7 @@ export const defaultPackage = ( "logs": "firebase functions:log" }, "engines": { - "node": "${NodeVersion}" + "node": "${NODE_VERSION}" }, "dependencies": ${JSON.stringify(dependencies, null, 4)}, "devDependencies": ${JSON.stringify(devDependencies, null, 4)}, diff --git a/src/schematics/interfaces.ts b/src/schematics/interfaces.ts index 348669fc1..f3d2eda83 100644 --- a/src/schematics/interfaces.ts +++ b/src/schematics/interfaces.ts @@ -16,6 +16,10 @@ export interface FirebaseTools { list(): Promise; }; + logger: { + add(...args: any[]): any + }; + login(): Promise; deploy(config: FirebaseDeployConfig): Promise; @@ -23,10 +27,6 @@ export interface FirebaseTools { serve(options: any): Promise; use(options: any, lol: any): Promise; - - logger: { - add(...args: any[]): any - }; } export interface FirebaseHostingRewrite { @@ -42,7 +42,7 @@ export interface FirebaseHostingConfig { rewrites: FirebaseHostingRewrite[]; } -export interface FirebaseFunctionsConfig { [key:string]: any } +export interface FirebaseFunctionsConfig { [key: string]: any; } export interface FirebaseJSON { hosting?: FirebaseHostingConfig[] | FirebaseHostingConfig; diff --git a/src/schematics/ng-add-common.ts b/src/schematics/ng-add-common.ts index 3e4f9769f..813d146a1 100644 --- a/src/schematics/ng-add-common.ts +++ b/src/schematics/ng-add-common.ts @@ -1,6 +1,6 @@ -import { SchematicsException, Tree } from '@angular-devkit/schematics'; - +import { SchematicsException, Tree, SchematicContext } from '@angular-devkit/schematics'; import { FirebaseRc } from './interfaces'; +import * as semver from 'semver'; export interface NgAddOptions { firebaseProject: string; @@ -76,6 +76,7 @@ export function generateFirebaseRc( export function safeReadJSON(path: string, tree: Tree) { try { + // tslint:disable-next-line:no-non-null-assertion return JSON.parse(tree.read(path)!.toString()); } catch (e) { throw new SchematicsException(`Error when parsing ${path}: ${e.message}`); @@ -85,6 +86,7 @@ export function safeReadJSON(path: string, tree: Tree) { export const addDependencies = ( host: Tree, deps: { [name: string]: { dev?: boolean, version: string } }, + context: SchematicContext ) => { const packageJson = host.exists('package.json') && safeReadJSON('package.json', host); @@ -96,11 +98,25 @@ export const addDependencies = ( Object.keys(deps).forEach(depName => { const dep = deps[depName]; if (dep.dev) { - packageJson.devDependencies[depName] = - packageJson.devDependencies[depName] || dep.version; + const existingVersion = packageJson.devDependencies[depName]; + if (existingVersion) { + if (!semver.intersects(existingVersion, dep.version)) { + context.logger.warn(`⚠️ The ${depName} devDependency specified in your package.json (${existingVersion}) does not fulfill AngularFire's dependency (${dep.version})`); + // TODO offer to fix + } + } else { + packageJson.devDependencies[depName] = dep.version; + } } else { - packageJson.dependencies[depName] = - packageJson.dependencies[depName] || deps.version; + const existingVersion = packageJson.dependencies[depName]; + if (existingVersion) { + if (!semver.intersects(existingVersion, dep.version)) { + context.logger.warn(`⚠️ The ${depName} dependency specified in your package.json (${existingVersion}) does not fulfill AngularFire's dependency (${dep.version})`); + // TODO offer to fix + } + } else { + packageJson.dependencies[depName] = dep.version; + } } }); diff --git a/src/schematics/ng-add-ssr.ts b/src/schematics/ng-add-ssr.ts index 1a45752d3..6ce88216f 100644 --- a/src/schematics/ng-add-ssr.ts +++ b/src/schematics/ng-add-ssr.ts @@ -1,16 +1,17 @@ -import { SchematicsException, Tree } from '@angular-devkit/schematics'; +import { SchematicsException, Tree, SchematicContext } from '@angular-devkit/schematics'; import { experimental } from '@angular-devkit/core'; import { + addDependencies, generateFirebaseRc, - safeReadJSON, + NgAddNormalizedOptions, overwriteIfExists, - stringifyFormatted, - addDependencies, NgAddNormalizedOptions + safeReadJSON, + stringifyFormatted } from './ng-add-common'; -import { FirebaseJSON, FirebaseHostingConfig } from './interfaces'; +import { FirebaseJSON } from './interfaces'; import { default as defaultDependencies, firebaseFunctions as firebaseFunctionsDependencies } from './versions.json'; -import {dirname, join} from 'path'; +import { dirname, join } from 'path'; // We consider a project to be a universal project if it has a `server` architect // target. If it does, it knows how to build the application's server. @@ -31,7 +32,14 @@ function generateHostingConfig(project: string, dist: string) { return { target: project, public: join(dirname(dist), dist), - ignore: ['firebase.json', '**/.*', '**/node_modules/**'], + ignore: ['**/.*'], + headers: [{ + source: '*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)', + headers: [{ + key: 'Cache-Control', + value: 'public,max-age=31536000,immutable' + }] + }], rewrites: [ { source: '**', @@ -74,9 +82,14 @@ export function generateFirebaseJson( if (firebaseJson.hosting === undefined) { firebaseJson.hosting = newConfig; } else if (Array.isArray(firebaseJson.hosting)) { - firebaseJson.hosting.push(newConfig); + const existingConfigIndex = firebaseJson.hosting.findIndex(config => config.target === newConfig.target); + if (existingConfigIndex > -1) { + firebaseJson.hosting.splice(existingConfigIndex, 1, newConfig); + } else { + firebaseJson.hosting.push(newConfig); + } } else { - firebaseJson.hosting = [firebaseJson.hosting!, newConfig]; + firebaseJson.hosting = [firebaseJson.hosting, newConfig]; } firebaseJson.functions = generateFunctionsConfig(dist); @@ -84,10 +97,11 @@ export function generateFirebaseJson( overwriteIfExists(tree, path, stringifyFormatted(firebaseJson)); } -export const addFirebaseFunctionsDependencies = (tree: Tree) => { +export const addFirebaseFunctionsDependencies = (tree: Tree, context: SchematicContext) => { addDependencies( tree, {...defaultDependencies, ...firebaseFunctionsDependencies}, + context ); }; @@ -126,9 +140,9 @@ export const setupUniversalDeployment = (config: { const staticOutput = project.architect.build.options.outputPath; const serverOutput = project.architect.server.options.outputPath; - // Add @firebase/firestore to externalDependencies - const externalDependencies = project.architect.server.options.externalDependencies || []; - externalDependencies.push('@firebase/firestore'); + // Add @firebase/firestore to externalDependencies + const externalDependencies: string[] = project.architect.server.options.externalDependencies || []; + if (!externalDependencies.includes('@firebase/firestore')) { externalDependencies.push('@firebase/firestore'); } project.architect.server.options.externalDependencies = externalDependencies; project.architect.deploy = { diff --git a/src/schematics/ng-add-static.ts b/src/schematics/ng-add-static.ts index 12fe2e75e..3c6ff645a 100644 --- a/src/schematics/ng-add-static.ts +++ b/src/schematics/ng-add-static.ts @@ -1,17 +1,16 @@ -import { SchematicsException, Tree } from '@angular-devkit/schematics'; +import { SchematicsException, Tree, SchematicContext } from '@angular-devkit/schematics'; import { experimental } from '@angular-devkit/core'; import { + addDependencies, generateFirebaseRc, + NgAddNormalizedOptions, overwriteIfExists, safeReadJSON, - stringifyFormatted, - addDependencies, NgAddNormalizedOptions + stringifyFormatted } from './ng-add-common'; -import { FirebaseJSON, FirebaseHostingConfig } from './interfaces'; +import { FirebaseJSON } from './interfaces'; -import { - default as defaultDependencies -} from './versions.json'; +import { default as defaultDependencies } from './versions.json'; function emptyFirebaseJson() { return { @@ -23,7 +22,14 @@ function generateHostingConfig(project: string, dist: string) { return { target: project, public: dist, - ignore: ['firebase.json', '**/.*', '**/node_modules/**'], + ignore: ['**/.*'], + headers: [{ + source: '*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)', + headers: [{ + key: 'Cache-Control', + value: 'public,max-age=31536000,immutable' + }] + }], rewrites: [ { source: '**', @@ -67,10 +73,11 @@ export function generateFirebaseJson( overwriteIfExists(tree, path, stringifyFormatted(firebaseJson)); } -export const addFirebaseHostingDependencies = (tree: Tree) => { +export const addFirebaseHostingDependencies = (tree: Tree, context: SchematicContext) => { addDependencies( tree, - defaultDependencies + defaultDependencies, + context ); }; diff --git a/src/schematics/ng-add.jasmine.ts b/src/schematics/ng-add.jasmine.ts index 872911160..0f6c66b4b 100644 --- a/src/schematics/ng-add.jasmine.ts +++ b/src/schematics/ng-add.jasmine.ts @@ -1,272 +1,13 @@ -import {Tree} from '@angular-devkit/schematics'; -import {setupProject} from './ng-add'; +import { Tree } from '@angular-devkit/schematics'; +import { setupProject } from './ng-add'; +import 'jasmine'; const PROJECT_NAME = 'pie-ka-chu'; const PROJECT_ROOT = 'pirojok'; const FIREBASE_PROJECT = 'pirojok-111e3'; - const OTHER_PROJECT_NAME = 'pi-catch-you'; const OTHER_FIREBASE_PROJECT_NAME = 'bi-catch-you-77e7e'; -describe('ng-add', () => { - describe('generating files', () => { - let tree: Tree; - - beforeEach(() => { - tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - }); - - it('generates new files if starting from scratch', async () => { - const result = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }); - expect(result.read('firebase.json')!.toString()).toEqual(initialFirebaseJson); - expect(result.read('.firebaserc')!.toString()).toEqual(initialFirebaserc); - expect(result.read('angular.json')!.toString()).toEqual(initialAngularJson); - }); - - it('uses default project', async () => { - const result = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: undefined - }); - expect(result.read('firebase.json')!.toString()).toEqual(overwriteFirebaseJson); - expect(result.read('.firebaserc')!.toString()).toEqual(overwriteFirebaserc); - expect(result.read('angular.json')!.toString()).toEqual(overwriteAngularJson); - }); - - it('overrides existing files', async () => { - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, project: PROJECT_NAME - }); - const result = await setupProject(tempTree, { - firebaseProject: OTHER_FIREBASE_PROJECT_NAME, - project: OTHER_PROJECT_NAME, - isUniversalProject: false - }); - expect(result.read('firebase.json')!.toString()).toEqual(projectFirebaseJson); - expect(result.read('.firebaserc')!.toString()).toEqual(projectFirebaserc); - expect(result.read('angular.json')!.toString()).toEqual(projectAngularJson); - }); - }); - - describe('error handling', () => { - it('fails if project not defined', () => { - const tree = Tree.empty(); - const angularJSON = generateAngularJson(); - delete angularJSON.defaultProject; - tree.create('angular.json', JSON.stringify(angularJSON)); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: undefined - }) - ).toThrowError( - /No Angular project selected and no default project in the workspace/ - ); - }); - - it('Should throw if angular.json not found', async () => { - expect(() => - setupProject(Tree.empty(), { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/Could not find angular.json/); - }); - - it('Should throw if angular.json can not be parsed', async () => { - const tree = Tree.empty(); - tree.create('angular.json', 'hi'); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/Could not parse angular.json/); - }); - - it('Should throw if specified project does not exist ', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify({projects: {}})); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/The specified Angular project is not defined in this workspace/); - }); - - it('Should throw if specified project is not application', async () => { - const tree = Tree.empty(); - tree.create( - 'angular.json', - JSON.stringify({ - projects: {[PROJECT_NAME]: {projectType: 'pokemon'}} - }) - ); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/Deploy requires an Angular project type of "application" in angular.json/); - }); - - it('Should throw if app does not have architect configured', async () => { - const tree = Tree.empty(); - tree.create( - 'angular.json', - JSON.stringify({ - projects: {[PROJECT_NAME]: {projectType: 'application'}} - }) - ); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/Cannot read the output path/); - }); - - /* TODO do something other than throw - it('Should throw if firebase.json has the project already', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }); - - expect(() => - setupProject(tempTree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/already exists in firebase.json/); - }); - - it('Should throw if firebase.json is broken', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - tree.create('firebase.json', `I'm broken 😔`); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/firebase.json: Unexpected token/); - });*/ - - it('Should throw if .firebaserc is broken', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - tree.create('.firebaserc', `I'm broken 😔`); - expect(() => - setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }) - ).toThrowError(/.firebaserc: Unexpected token/); - }); - - /* TODO do something else - - it('Should throw if firebase.json has the project already', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }); - - expect(() => - setupProject(tempTree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: OTHER_PROJECT_NAME - }) - ).toThrowError(/ already defined in .firebaserc/); - }); - - it('Should throw if firebase.json is broken', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - - const tempTree = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: PROJECT_NAME - }); - - expect(() => - setupProject(tempTree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: false, - project: OTHER_PROJECT_NAME - }) - ).toThrowError(/ already defined in .firebaserc/); - }); */ - - describe('universal app', () => { - it('should fail without a server project', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJson())); - - expect(() => setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: true, - project: PROJECT_NAME - })).toThrowError(/\(architect.server.options.outputPath\) of the Angular project "pie-ka-chu" in angular.json/); - }); - - it('should add a @angular/fire builder', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJsonWithServer())); - - const result = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: true, - project: PROJECT_NAME - }); - - const workspace = JSON.parse((await result.read('angular.json'))!.toString()); - expect(workspace.projects['pie-ka-chu'].architect.deploy.options.ssr).toBeTrue(); - }); - - it('should configure firebase.json', async () => { - const tree = Tree.empty(); - tree.create('angular.json', JSON.stringify(generateAngularJsonWithServer())); - - const result = await setupProject(tree, { - firebaseProject: FIREBASE_PROJECT, - isUniversalProject: true, - project: PROJECT_NAME - }); - - const firebaseJson = JSON.parse((await result.read('firebase.json'))!.toString()); - expect(firebaseJson).toEqual(universalFirebaseJson); - }); - }); - }); -}); - function generateAngularJson() { return { defaultProject: PROJECT_NAME, @@ -343,9 +84,18 @@ const initialFirebaseJson = `{ \"target\": \"pie-ka-chu\", \"public\": \"dist/ikachu\", \"ignore\": [ - \"firebase.json\", - \"**/.*\", - \"**/node_modules/**\" + \"**/.*\" + ], + \"headers\": [ + { + \"source\": \"*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)\", + \"headers\": [ + { + \"key\": \"Cache-Control\", + \"value\": \"public,max-age=31536000,immutable\" + } + ] + } ], \"rewrites\": [ { @@ -407,9 +157,18 @@ const overwriteFirebaseJson = `{ \"target\": \"pie-ka-chu\", \"public\": \"dist/ikachu\", \"ignore\": [ - \"firebase.json\", - \"**/.*\", - \"**/node_modules/**\" + \"**/.*\" + ], + \"headers\": [ + { + \"source\": \"*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)\", + \"headers\": [ + { + \"key\": \"Cache-Control\", + \"value\": \"public,max-age=31536000,immutable\" + } + ] + } ], \"rewrites\": [ { @@ -471,9 +230,18 @@ const projectFirebaseJson = `{ \"target\": \"pie-ka-chu\", \"public\": \"dist/ikachu\", \"ignore\": [ - \"firebase.json\", - \"**/.*\", - \"**/node_modules/**\" + \"**/.*\" + ], + \"headers\": [ + { + \"source\": \"*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)\", + \"headers\": [ + { + \"key\": \"Cache-Control\", + \"value\": \"public,max-age=31536000,immutable\" + } + ] + } ], \"rewrites\": [ { @@ -486,9 +254,18 @@ const projectFirebaseJson = `{ \"target\": \"pi-catch-you\", \"public\": \"dist/ikachu\", \"ignore\": [ - \"firebase.json\", - \"**/.*\", - \"**/node_modules/**\" + \"**/.*\" + ], + \"headers\": [ + { + \"source\": \"*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)\", + \"headers\": [ + { + \"key\": \"Cache-Control\", + \"value\": \"public,max-age=31536000,immutable\" + } + ] + } ], \"rewrites\": [ { @@ -560,10 +337,15 @@ const universalFirebaseJson = { target: 'pie-ka-chu', public: 'dist/dist/ikachu', ignore: [ - 'firebase.json', - '**/.*', - '**/node_modules/**' + '**/.*' ], + headers: [{ + source: '*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)', + headers: [{ + key: 'Cache-Control', + value: 'public,max-age=31536000,immutable' + }] + }], rewrites: [ { source: '**', @@ -575,3 +357,262 @@ const universalFirebaseJson = { source: 'dist' } }; + +describe('ng-add', () => { + describe('generating files', () => { + let tree: Tree; + + beforeEach(() => { + tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + }); + + it('generates new files if starting from scratch', async () => { + const result = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }); + expect(result.read('firebase.json').toString()).toEqual(initialFirebaseJson); + expect(result.read('.firebaserc').toString()).toEqual(initialFirebaserc); + expect(result.read('angular.json').toString()).toEqual(initialAngularJson); + }); + + it('uses default project', async () => { + const result = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: undefined + }); + expect(result.read('firebase.json').toString()).toEqual(overwriteFirebaseJson); + expect(result.read('.firebaserc').toString()).toEqual(overwriteFirebaserc); + expect(result.read('angular.json').toString()).toEqual(overwriteAngularJson); + }); + + it('overrides existing files', async () => { + const tempTree = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, project: PROJECT_NAME + }); + const result = await setupProject(tempTree, { + firebaseProject: OTHER_FIREBASE_PROJECT_NAME, + project: OTHER_PROJECT_NAME, + isUniversalProject: false + }); + expect(result.read('firebase.json').toString()).toEqual(projectFirebaseJson); + expect(result.read('.firebaserc').toString()).toEqual(projectFirebaserc); + expect(result.read('angular.json').toString()).toEqual(projectAngularJson); + }); + }); + + describe('error handling', () => { + it('fails if project not defined', () => { + const tree = Tree.empty(); + const angularJSON = generateAngularJson(); + delete angularJSON.defaultProject; + tree.create('angular.json', JSON.stringify(angularJSON)); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: undefined + }) + ).toThrowError( + /No Angular project selected and no default project in the workspace/ + ); + }); + + it('Should throw if angular.json not found', async () => { + expect(() => + setupProject(Tree.empty(), { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/Could not find angular.json/); + }); + + it('Should throw if angular.json can not be parsed', async () => { + const tree = Tree.empty(); + tree.create('angular.json', 'hi'); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/Could not parse angular.json/); + }); + + it('Should throw if specified project does not exist ', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify({ projects: {} })); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/The specified Angular project is not defined in this workspace/); + }); + + it('Should throw if specified project is not application', async () => { + const tree = Tree.empty(); + tree.create( + 'angular.json', + JSON.stringify({ + projects: { [PROJECT_NAME]: { projectType: 'pokemon' } } + }) + ); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/Deploy requires an Angular project type of "application" in angular.json/); + }); + + it('Should throw if app does not have architect configured', async () => { + const tree = Tree.empty(); + tree.create( + 'angular.json', + JSON.stringify({ + projects: { [PROJECT_NAME]: { projectType: 'application' } } + }) + ); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/Cannot read the output path/); + }); + + /* TODO do something other than throw + it('Should throw if firebase.json has the project already', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + const tempTree = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }); + + expect(() => + setupProject(tempTree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/already exists in firebase.json/); + }); + + it('Should throw if firebase.json is broken', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + tree.create('firebase.json', `I'm broken 😔`); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/firebase.json: Unexpected token/); + });*/ + + it('Should throw if .firebaserc is broken', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + tree.create('.firebaserc', `I'm broken 😔`); + expect(() => + setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }) + ).toThrowError(/.firebaserc: Unexpected token/); + }); + + /* TODO do something else + + it('Should throw if firebase.json has the project already', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + const tempTree = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }); + + expect(() => + setupProject(tempTree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: OTHER_PROJECT_NAME + }) + ).toThrowError(/ already defined in .firebaserc/); + }); + + it('Should throw if firebase.json is broken', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + + const tempTree = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: PROJECT_NAME + }); + + expect(() => + setupProject(tempTree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: false, + project: OTHER_PROJECT_NAME + }) + ).toThrowError(/ already defined in .firebaserc/); + }); */ + + describe('universal app', () => { + it('should fail without a server project', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJson())); + + expect(() => setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: true, + project: PROJECT_NAME + })).toThrowError(/\(architect.server.options.outputPath\) of the Angular project "pie-ka-chu" in angular.json/); + }); + + it('should add a @angular/fire builder', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJsonWithServer())); + + const result = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: true, + project: PROJECT_NAME + }); + + const workspace = JSON.parse((await result.read('angular.json')).toString()); + expect(workspace.projects['pie-ka-chu'].architect.deploy.options.ssr).toBeTrue(); + }); + + it('should configure firebase.json', async () => { + const tree = Tree.empty(); + tree.create('angular.json', JSON.stringify(generateAngularJsonWithServer())); + + const result = await setupProject(tree, { + firebaseProject: FIREBASE_PROJECT, + isUniversalProject: true, + project: PROJECT_NAME + }); + + const firebaseJson = JSON.parse((await result.read('firebase.json')).toString()); + expect(firebaseJson).toEqual(universalFirebaseJson); + }); + }); + }); +}); diff --git a/src/schematics/ng-add.ts b/src/schematics/ng-add.ts index de9136b13..c06b8e673 100644 --- a/src/schematics/ng-add.ts +++ b/src/schematics/ng-add.ts @@ -1,26 +1,11 @@ -import { - SchematicsException, - Tree, - SchematicContext, - chain, - mergeWith -} from '@angular-devkit/schematics'; -import { - NodePackageInstallTask, - RunSchematicTask -} from '@angular-devkit/schematics/tasks'; +import { SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; +import { NodePackageInstallTask, RunSchematicTask } from '@angular-devkit/schematics/tasks'; import { experimental, JsonParseMode, parseJson } from '@angular-devkit/core'; import { listProjects, projectPrompt, projectTypePrompt } from './utils'; -import {DeployOptions, NgAddNormalizedOptions} from './ng-add-common'; -import { - setupUniversalDeployment, - addFirebaseFunctionsDependencies -} from './ng-add-ssr'; -import { - setupStaticDeployment, - addFirebaseHostingDependencies -} from './ng-add-static'; +import { DeployOptions, NgAddNormalizedOptions } from './ng-add-common'; +import { addFirebaseFunctionsDependencies, setupUniversalDeployment } from './ng-add-ssr'; +import { addFirebaseHostingDependencies, setupStaticDeployment } from './ng-add-static'; function getWorkspace( host: Tree @@ -123,9 +108,9 @@ export const ngAdd = (options: DeployOptions) => ( return projectTypePrompt(project).then( ({ universalProject }: { universalProject: boolean }) => { if (universalProject) { - addFirebaseFunctionsDependencies(host); + addFirebaseFunctionsDependencies(host, context); } else { - addFirebaseHostingDependencies(host); + addFirebaseHostingDependencies(host, context); } const projectOptions: DeployOptions & { isUniversalProject: boolean } = { ...options, diff --git a/src/schematics/utils.ts b/src/schematics/utils.ts index 8601af926..5ca1a61ea 100644 --- a/src/schematics/utils.ts +++ b/src/schematics/utils.ts @@ -13,7 +13,7 @@ export async function listProjects() { // `fuzzy` passes either the original list of projects or an internal object // which contains the project as a property. const isProject = (elem: Project | { original: Project }): elem is Project => { - return (<{ original: Project }>elem).original === undefined; + return (elem as { original: Project }).original === undefined; }; const searchProjects = (projects: Project[]) => { @@ -71,11 +71,12 @@ export function getFirebaseProjectName( workspaceRoot: string, target: string ): string | undefined { - const { targets }: FirebaseRc = JSON.parse( + const rc: FirebaseRc = JSON.parse( readFileSync(join(workspaceRoot, '.firebaserc'), 'UTF-8') ); - const projects = Object.keys(targets!); + const targets = rc.targets || {}; + const projects = Object.keys(targets || {}); return projects.find( - project => !!Object.keys(targets![project].hosting).find(t => t === target) + project => !!Object.keys(targets[project].hosting).find(t => t === target) ); } diff --git a/src/schematics/versions.json b/src/schematics/versions.json index 2b38cae20..fb87ebe05 100644 --- a/src/schematics/versions.json +++ b/src/schematics/versions.json @@ -5,7 +5,8 @@ "firebase-tools": { "dev": true, "version": "0.0.0" }, "fuzzy": { "dev": true, "version": "0.0.0"}, "inquirer": { "dev": true, "version": "0.0.0"}, - "inquirer-autocomplete-prompt": { "dev": true, "version": "0.0.0"} + "inquirer-autocomplete-prompt": { "dev": true, "version": "0.0.0"}, + "open": { "dev": true, "version": "0.0.0"} }, "firebaseFunctions": { "firebase-admin": { "dev": true, "version": "0.0.0" }, diff --git a/src/storage/observable/fromTask.ts b/src/storage/observable/fromTask.ts index 0aac5f2e6..3a8ae65f8 100644 --- a/src/storage/observable/fromTask.ts +++ b/src/storage/observable/fromTask.ts @@ -1,6 +1,5 @@ import { Observable } from 'rxjs'; import { UploadTask, UploadTaskSnapshot } from '../interfaces'; -import { storage } from 'firebase/app'; export function fromTask(task: UploadTask) { return new Observable(subscriber => { diff --git a/src/storage/ref.ts b/src/storage/ref.ts index 4afeaa0ae..06ef4862c 100644 --- a/src/storage/ref.ts +++ b/src/storage/ref.ts @@ -1,6 +1,6 @@ -import { SettableMetadata, UploadMetadata, Reference, StringFormat, ListResult} from './interfaces'; -import { createUploadTask, AngularFireUploadTask } from './task'; -import { Observable, from, of } from 'rxjs'; +import { ListResult, Reference, SettableMetadata, StringFormat, UploadMetadata } from './interfaces'; +import { AngularFireUploadTask, createUploadTask } from './task'; +import { from, Observable, of } from 'rxjs'; import { ɵAngularFireSchedulers } from '@angular/fire'; import { observeOn, switchMap } from 'rxjs/operators'; @@ -18,7 +18,6 @@ export interface AngularFireStorageReference { /** * Create an AngularFire wrapped Storage Reference. This object * creates observable methods from promise based methods. - * @param ref */ export function createStorageRef( ref: Reference, @@ -31,7 +30,7 @@ export function createStorageRef( switchMap(() => ref.getDownloadURL()), keepUnstableUntilFirst ), - getMetadata: () => of().pipe( + getMetadata: () => of(undefined).pipe( observeOn(schedulers.outsideAngular), switchMap(() => ref.getMetadata()), keepUnstableUntilFirst diff --git a/src/storage/storage.spec.ts b/src/storage/storage.spec.ts index cecda25dc..083d4b645 100644 --- a/src/storage/storage.spec.ts +++ b/src/storage/storage.spec.ts @@ -1,8 +1,8 @@ -import { Observable, forkJoin } from 'rxjs' -import { map, mergeMap, tap } from 'rxjs/operators'; -import { TestBed, inject } from '@angular/core/testing'; -import { FirebaseApp, FIREBASE_OPTIONS, AngularFireModule, FIREBASE_APP_NAME } from '@angular/fire'; -import { AngularFireStorageModule, AngularFireStorage, AngularFireUploadTask, BUCKET } from './public_api'; +import { forkJoin } from 'rxjs'; +import { mergeMap, tap } from 'rxjs/operators'; +import { TestBed } from '@angular/core/testing'; +import { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp } from '@angular/fire'; +import { AngularFireStorage, AngularFireStorageModule, AngularFireUploadTask, BUCKET } from './public_api'; import { COMMON_CONFIG } from '../test-config'; import 'firebase/storage'; import { rando } from '../firestore/utils.spec'; @@ -18,10 +18,9 @@ describe('AngularFireStorage', () => { AngularFireStorageModule ] }); - inject([FirebaseApp, AngularFireStorage], (app_: FirebaseApp, _storage: AngularFireStorage) => { - app = app_; - afStorage = _storage; - })(); + + app = TestBed.inject(FirebaseApp); + afStorage = TestBed.inject(AngularFireStorage); }); afterEach(() => { @@ -46,40 +45,46 @@ describe('AngularFireStorage', () => { describe('upload task', () => { it('should upload and delete a file', (done) => { - const data = { angular: "fire" }; - const blob = new Blob([JSON.stringify(data)], { type : 'application/json' }); + const data = { angular: 'fire' }; + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const ref = afStorage.ref('af.json'); const task = ref.put(blob); - const sub = task.snapshotChanges() + task.snapshotChanges() .subscribe( - snap => { expect(snap).toBeDefined() }, - e => { done.fail(); }, + snap => { + expect(snap).toBeDefined(); + }, + done.fail, () => { ref.delete().subscribe(done, done.fail); }); }); it('should upload a file and observe the download url', (done) => { - const data = { angular: "fire" }; - const blob = new Blob([JSON.stringify(data)], { type : 'application/json' }); + const data = { angular: 'fire' }; + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const ref = afStorage.ref('af.json'); - const task = ref.put(blob).then(() => {; + ref.put(blob).then(() => { const url$ = ref.getDownloadURL(); url$.subscribe( - url => { expect(url).toBeDefined(); }, - e => { done.fail(); }, - () => { ref.delete().subscribe(done, done.fail); } + url => { + expect(url).toBeDefined(); + }, + done.fail, + () => { + ref.delete().subscribe(done, done.fail); + } ); }); }); it('should resolve the task as a promise', (done) => { - const data = { angular: "promise" }; - const blob = new Blob([JSON.stringify(data)], { type : 'application/json' }); + const data = { angular: 'promise' }; + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const ref = afStorage.ref('af.json'); const task: AngularFireUploadTask = ref.put(blob); - task.then(snap => { - expect(snap).toBeDefined(); + task.then(snap => { + expect(snap).toBeDefined(); done(); }).catch(done.fail); }); @@ -89,38 +94,38 @@ describe('AngularFireStorage', () => { describe('reference', () => { it('it should upload, download, and delete', (done) => { - const data = { angular: "fire" }; - const blob = new Blob([JSON.stringify(data)], { type : 'application/json' }); + const data = { angular: 'fire' }; + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const ref = afStorage.ref('af.json'); const task = ref.put(blob); // Wait for the upload - const sub = forkJoin(task.snapshotChanges()) + forkJoin([task.snapshotChanges()]) .pipe( // get the url download mergeMap(() => ref.getDownloadURL()), // assert the URL tap(url => expect(url).toBeDefined()), // Delete the file - mergeMap(url => ref.delete()) + mergeMap(() => ref.delete()) ) // finish the test .subscribe(done, done.fail); }); it('should upload, get metadata, and delete', (done) => { - const data = { angular: "fire" }; - const blob = new Blob([JSON.stringify(data)], { type : 'application/json' }); + const data = { angular: 'fire' }; + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const ref = afStorage.ref('af.json'); const task = ref.put(blob, { customMetadata: { blah: 'blah' } }); // Wait for the upload - const sub = forkJoin(task.snapshotChanges()) + forkJoin([task.snapshotChanges()]) .pipe( // get the metadata download mergeMap(() => ref.getMetadata()), // assert the URL tap(meta => expect(meta.customMetadata).toEqual({ blah: 'blah' })), // Delete the file - mergeMap(meta => ref.delete()) + mergeMap(() => ref.delete()) ) // finish the test .subscribe(done, done.fail); @@ -148,14 +153,13 @@ describe('AngularFireStorage w/options', () => { ], providers: [ { provide: FIREBASE_APP_NAME, useValue: firebaseAppName }, - { provide: FIREBASE_OPTIONS, useValue: COMMON_CONFIG }, + { provide: FIREBASE_OPTIONS, useValue: COMMON_CONFIG }, { provide: BUCKET, useValue: storageBucket } ] }); - inject([FirebaseApp, AngularFireStorage], (app_: FirebaseApp, _storage: AngularFireStorage) => { - app = app_; - afStorage = _storage; - })(); + + app = TestBed.inject(FirebaseApp); + afStorage = TestBed.inject(AngularFireStorage); }); afterEach(() => { @@ -163,7 +167,7 @@ describe('AngularFireStorage w/options', () => { }); describe('', () => { - + it('should exist', () => { expect(afStorage instanceof AngularFireStorage).toBe(true); }); @@ -181,26 +185,26 @@ describe('AngularFireStorage w/options', () => { }); it('storage be pointing towards a different bucket', () => { - expect(afStorage.storage.ref().toString()).toEqual( `gs://${storageBucket}/`); + expect(afStorage.storage.ref().toString()).toEqual(`gs://${storageBucket}/`); }); // TODO tests for Node? if (typeof Blob !== 'undefined') { it('it should upload, download, and delete', (done) => { - const data = { angular: "fire" }; - const blob = new Blob([JSON.stringify(data)], { type : 'application/json' }); + const data = { angular: 'fire' }; + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); const ref = afStorage.ref('af.json'); const task = ref.put(blob); // Wait for the upload - const sub = forkJoin(task.snapshotChanges()) + forkJoin([task.snapshotChanges()]) .pipe( // get the url download mergeMap(() => ref.getDownloadURL()), // assert the URL tap(url => expect(url).toMatch(new RegExp(`https:\\/\\/firebasestorage\\.googleapis\\.com\\/v0\\/b\\/${storageBucket}\\/o\\/af\\.json`))), // Delete the file - mergeMap(url => ref.delete()) + mergeMap(() => ref.delete()) ) // finish the test .subscribe(done, done.fail); diff --git a/src/storage/storage.ts b/src/storage/storage.ts index 20607e0e5..df8a1301f 100644 --- a/src/storage/storage.ts +++ b/src/storage/storage.ts @@ -1,7 +1,15 @@ -import { Injectable, Inject, Optional, InjectionToken, NgZone, PLATFORM_ID } from '@angular/core'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; import { createStorageRef } from './ref'; import { Observable } from 'rxjs'; -import { FirebaseOptions, FirebaseAppConfig, ɵfirebaseAppFactory, FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵkeepUnstableUntilFirstFactory, ɵAngularFireSchedulers } from '@angular/fire'; +import { + FIREBASE_APP_NAME, + FIREBASE_OPTIONS, + FirebaseAppConfig, + FirebaseOptions, + ɵAngularFireSchedulers, + ɵfirebaseAppFactory, + ɵkeepUnstableUntilFirstFactory +} from '@angular/fire'; import { UploadMetadata } from './interfaces'; import { storage } from 'firebase/app'; import 'firebase/storage'; @@ -25,14 +33,15 @@ export class AngularFireStorage { public readonly schedulers: ɵAngularFireSchedulers; constructor( - @Inject(FIREBASE_OPTIONS) options:FirebaseOptions, - @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined, - @Optional() @Inject(BUCKET) storageBucket:string|null, + @Inject(FIREBASE_OPTIONS) options: FirebaseOptions, + @Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig: string | FirebaseAppConfig | null | undefined, + @Optional() @Inject(BUCKET) storageBucket: string | null, + // tslint:disable-next-line:ban-types @Inject(PLATFORM_ID) platformId: Object, zone: NgZone ) { this.schedulers = new ɵAngularFireSchedulers(zone); - this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers, platformId); + this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers); this.storage = zone.runOutsideAngular(() => { const app = ɵfirebaseAppFactory(options, zone, nameOrConfig); diff --git a/src/storage/task.ts b/src/storage/task.ts index 0aa83ac22..bccc7154c 100644 --- a/src/storage/task.ts +++ b/src/storage/task.ts @@ -1,17 +1,17 @@ -import { UploadTaskSnapshot, UploadTask } from './interfaces'; +import { UploadTask, UploadTaskSnapshot } from './interfaces'; import { fromTask } from './observable/fromTask'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; export interface AngularFireUploadTask { - task: UploadTask, + task: UploadTask; snapshotChanges(): Observable; percentageChanges(): Observable; pause(): boolean; cancel(): boolean; resume(): boolean; then( - onFulfilled?: ((a: UploadTaskSnapshot) => any) | null, + onFulfilled?: ((a: UploadTaskSnapshot) => any) | null, onRejected?: ((a: Error) => any) | null ): Promise; catch(onRejected: (a: Error) => any): Promise; @@ -21,12 +21,11 @@ export interface AngularFireUploadTask { * Create an AngularFireUploadTask from a regular UploadTask from the Storage SDK. * This method creates an observable of the upload and returns on object that provides * multiple methods for controlling and monitoring the file upload. - * @param task */ export function createUploadTask(task: UploadTask): AngularFireUploadTask { const inner$ = fromTask(task); return { - task: task, + task, then: task.then.bind(task), catch: task.catch.bind(task), pause: task.pause.bind(task), diff --git a/src/test-config.ts b/src/test-config.ts index bcbb118d7..4f1282c10 100644 --- a/src/test-config.ts +++ b/src/test-config.ts @@ -1,11 +1,11 @@ export const COMMON_CONFIG = { - apiKey: "AIzaSyBVSy3YpkVGiKXbbxeK0qBnu3-MNZ9UIjA", - authDomain: "angularfire2-test.firebaseapp.com", - databaseURL: "https://angularfire2-test.firebaseio.com", - projectId: "angularfire2-test", - storageBucket: "angularfire2-test.appspot.com", - messagingSenderId: "920323787688", - appId: "1:920323787688:web:2253a0e5eb5b9a8b", + apiKey: 'AIzaSyBVSy3YpkVGiKXbbxeK0qBnu3-MNZ9UIjA', + authDomain: 'angularfire2-test.firebaseapp.com', + databaseURL: 'https://angularfire2-test.firebaseio.com', + projectId: 'angularfire2-test', + storageBucket: 'angularfire2-test.appspot.com', + messagingSenderId: '920323787688', + appId: '1:920323787688:web:2253a0e5eb5b9a8b', databaseName: 'angularfire2-test', - measurementId: "G-W20QDV5CZP" + measurementId: 'G-W20QDV5CZP' }; diff --git a/src/test.ts b/src/test.ts index 65a7bc8c1..d967f7532 100644 --- a/src/test.ts +++ b/src/test.ts @@ -5,10 +5,7 @@ import 'zone.js/dist/zone-testing'; import 'zone.js/dist/task-tracking'; import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; declare const require: any; diff --git a/test/ng-build/ng9/src/app/app.component.ts b/test/ng-build/ng9/src/app/app.component.ts index 45812c902..719421471 100644 --- a/test/ng-build/ng9/src/app/app.component.ts +++ b/test/ng-build/ng9/src/app/app.component.ts @@ -37,6 +37,6 @@ export class AppComponent { ) { const authArgs = canActivate(() => loggedIn); console.log(analytics, app, db, auth, afStore, storage, messaging, functions, remoteConfig, performance, authArgs); - appRef.isStable.subscribe(it => console.log("isStable", it)); + appRef.isStable.subscribe(it => console.log('isStable', it)); } } diff --git a/test/ng-build/ng9/src/app/app.module.ts b/test/ng-build/ng9/src/app/app.module.ts index acd6df1ac..3f03371cc 100644 --- a/test/ng-build/ng9/src/app/app.module.ts +++ b/test/ng-build/ng9/src/app/app.module.ts @@ -23,15 +23,15 @@ import { AngularFireAuthGuardModule } from '@angular/fire/auth-guard'; imports: [ BrowserModule, AngularFireModule.initializeApp({ - apiKey: "AIzaSyBVSy3YpkVGiKXbbxeK0qBnu3-MNZ9UIjA", - authDomain: "angularfire2-test.firebaseapp.com", - databaseURL: "https://angularfire2-test.firebaseio.com", - projectId: "angularfire2-test", - storageBucket: "angularfire2-test.appspot.com", - messagingSenderId: "920323787688", - appId: "1:920323787688:web:2253a0e5eb5b9a8b", + apiKey: 'AIzaSyBVSy3YpkVGiKXbbxeK0qBnu3-MNZ9UIjA', + authDomain: 'angularfire2-test.firebaseapp.com', + databaseURL: 'https://angularfire2-test.firebaseio.com', + projectId: 'angularfire2-test', + storageBucket: 'angularfire2-test.appspot.com', + messagingSenderId: '920323787688', + appId: '1:920323787688:web:2253a0e5eb5b9a8b', databaseName: 'angularfire2-test', - measurementId: "G-W20QDV5CZP" + measurementId: 'G-W20QDV5CZP' }), AngularFireAnalyticsModule, AngularFireAuthModule, diff --git a/tools/build.ts b/tools/build.ts index fa2a88f96..ae2883156 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -1,8 +1,8 @@ import { spawn } from 'child_process'; -import { copy, writeFile, readFile } from 'fs-extra'; +import { copy, readFile, writeFile } from 'fs-extra'; import { prettySize } from 'pretty-size'; import { sync as gzipSync } from 'gzip-size'; -import { join, dirname } from 'path'; +import { dirname, join } from 'path'; // TODO infer these from the package.json const MODULES = [ @@ -13,8 +13,8 @@ const MODULES = [ const UMD_NAMES = MODULES.map(m => m === 'core' ? 'angular-fire' : `angular-fire-${m}`); const ENTRY_NAMES = MODULES.map(m => m === 'core' ? '@angular/fire' : `@angular/fire/${m}`); -const src = (...args:string[]) => join(process.cwd(), 'src', ...args); -const dest = (...args:string[]) => join(process.cwd(), 'dist', 'packages-dist', ...args); +const src = (...args: string[]) => join(process.cwd(), 'src', ...args); +const dest = (...args: string[]) => join(process.cwd(), 'dist', 'packages-dist', ...args); const rootPackage = import(join(process.cwd(), 'package.json')); @@ -31,7 +31,7 @@ async function replacePackageCoreVersion() { async function replacePackageJsonVersions() { const path = dest('package.json'); const root = await rootPackage; - var pkg = await import(path); + const pkg = await import(path); Object.keys(pkg.peerDependencies).forEach(peer => { pkg.peerDependencies[peer] = root.dependencies[peer]; }); @@ -53,7 +53,7 @@ async function replaceSchematicVersions() { } function spawnPromise(command: string, args: string[]) { - return new Promise(resolve => spawn(command, args, {stdio: 'inherit'}).on('close', resolve)); + return new Promise(resolve => spawn(command, args, { stdio: 'inherit' }).on('close', resolve)); } async function compileSchematics() { @@ -93,30 +93,30 @@ function measureLibrary() { async function buildDocs() { // INVESTIGATE json to stdout rather than FS? await Promise.all(MODULES.map(module => spawnPromise('npx', ['typedoc', `./src/${module}`, '--json', `./dist/typedocs/${module}.json`]))); - const entries = await Promise.all(MODULES.map(async (module, index) => { + const entries = await Promise.all(MODULES.map(async (module) => { const buffer = await readFile(`./dist/typedocs/${module}.json`); const typedoc = JSON.parse(buffer.toString()); // TODO infer the entryPoint from the package.json - const entryPoint = typedoc.children.find((c:any) => c.name === "\"public_api\""); + const entryPoint = typedoc.children.find((c: any) => c.name === '"public_api"'); const allChildren = [].concat(...typedoc.children.map(child => // TODO chop out the working directory and filename - child.children ? child.children.map(c => ({...c, path: dirname(child.originalName.split(process.cwd())[1])})) : [] + child.children ? child.children.map(c => ({ ...c, path: dirname(child.originalName.split(process.cwd())[1]) })) : [] )); return entryPoint.children .filter(c => c.name[0] !== 'ɵ' && c.name[0] !== '_' /* private */) - .map(child => ({...allChildren.find(c => child.target === c.id)})) - .reduce((acc, child) => ({...acc, [encodeURIComponent(child.name)]: child}), {}); + .map(child => ({ ...allChildren.find(c => child.target === c.id) })) + .reduce((acc, child) => ({ ...acc, [encodeURIComponent(child.name)]: child }), {}); })); const root = await rootPackage; const pipes = ['MonoTypeOperatorFunction', 'OperatorFunction', 'AuthPipe', 'UnaryFunction']; const tocType = child => { const decorators: string[] = child.decorators && child.decorators.map(d => d.name) || []; if (decorators.includes('NgModule')) { - return 'NgModule' + return 'NgModule'; } else if (child.kindString === 'Type alias') { return 'Type alias'; } else if (child.kindString === 'Variable' && child.defaultValue && child.defaultValue.startsWith('new InjectionToken')) { - return 'InjectionToken' + return 'InjectionToken'; } else if (child.type) { return pipes.includes(child.type.name) ? 'Pipe' : child.type.name; } else if (child.signatures && child.signatures[0] && child.signatures[0].type && pipes.includes(child.signatures[0].type.name)) { @@ -124,12 +124,17 @@ async function buildDocs() { } else { return child.kindString; } - } - const table_of_contents = entries.reduce((acc, entry, index) => - ({...acc, [MODULES[index]]: {name: ENTRY_NAMES[index], exports: Object.keys(entry).reduce((acc, key) => ({...acc, [key]: tocType(entry[key])}), {})}}), + }; + const tableOfContents = entries.reduce((acc, entry, index) => + ({ + ...acc, [MODULES[index]]: { + name: ENTRY_NAMES[index], + exports: Object.keys(entry).reduce((acc, key) => ({ ...acc, [key]: tocType(entry[key]) }), {}) + } + }), {} ); - const afdoc = entries.reduce((acc, entry, index) => ({...acc, [MODULES[index]]: entry }), { table_of_contents }); + const afdoc = entries.reduce((acc, entry, index) => ({ ...acc, [MODULES[index]]: entry }), { table_of_contents: tableOfContents }); return writeFile(`./api-${root.version}.json`, JSON.stringify(afdoc, null, 2)); } @@ -144,6 +149,6 @@ Promise.all([ console.log(` Package Size Gzipped ------------------------------------ -${stats.map((s, i) => [MODULES[i].padEnd(16), s.size.padEnd(8), s.gzip].join("")).join("\n")}` +${stats.map((s, i) => [MODULES[i].padEnd(16), s.size.padEnd(8), s.gzip].join('')).join('\n')}` ) ); diff --git a/tslint.json b/tslint.json index 0378acdc9..60559a052 100644 --- a/tslint.json +++ b/tslint.json @@ -9,6 +9,7 @@ "component-class-suffix": true, "contextual-lifecycle": true, "directive-class-suffix": true, + "no-shadowed-variable": false, "directive-selector": [ true, "attribute", @@ -60,7 +61,6 @@ "no-non-null-assertion": true, "no-redundant-jsdoc": true, "no-switch-case-fall-through": true, - "no-use-before-declare": true, "no-var-requires": false, "object-literal-key-quotes": [ true, @@ -84,9 +84,15 @@ "template-banana-in-box": true, "template-no-negated-async": true, "use-lifecycle-interface": true, - "use-pipe-transform-interface": true + "use-pipe-transform-interface": true, + "variable-name": [ + true, + "ban-keywords", + "check-format", + "allow-leading-underscore" + ] }, "rulesDirectory": [ "codelyzer" ] - } \ No newline at end of file + } diff --git a/yarn.lock b/yarn.lock index 1849f2740..6d12f6727 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,108 +2,108 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.900.5", "@angular-devkit/architect@~0.900": - version "0.900.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.900.5.tgz#c6de20d512cb4dbc1179ec236d310b5d6314164b" - integrity sha512-4du29cYI5awsZ34xoS9WWSbEv7HazIlsQWaee/fRdvv4WmyB1w6geLMLHveGT2cYL/lhxsMUdYyDMa6sXcYeFA== - dependencies: - "@angular-devkit/core" "9.0.5" - rxjs "6.5.3" - -"@angular-devkit/build-angular@~0.900": - version "0.900.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.900.5.tgz#7285fb7ec0186b7813d4368988620715f07d0832" - integrity sha512-WCfmQNTzQNgdh8baeNJm5uIhXbWp62e+upsZzh6eJ1ZrIeJSPJxE5mI1VvqBoAQH3hKjuAaAW3axpWGar4kJjw== - dependencies: - "@angular-devkit/architect" "0.900.5" - "@angular-devkit/build-optimizer" "0.900.5" - "@angular-devkit/build-webpack" "0.900.5" - "@angular-devkit/core" "9.0.5" - "@babel/core" "7.7.7" - "@babel/generator" "7.7.7" - "@babel/preset-env" "7.7.7" - "@ngtools/webpack" "9.0.5" - ajv "6.10.2" - autoprefixer "9.7.1" +"@angular-devkit/architect@0.901.9", "@angular-devkit/architect@>= 0.900 < 0.1100": + version "0.901.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.901.9.tgz#5d849a120449b2f91ec6eef44ddad74ffb7ad810" + integrity sha512-Xokyh7bv4qICHpb5Xui1jPTi6ZZvzR5tbTIxT0DFWqw16TEkFgkNubQsW6mFSR3g3CXdySMfOwWExfa/rE1ggA== + dependencies: + "@angular-devkit/core" "9.1.9" + rxjs "6.5.4" + +"@angular-devkit/build-angular@>= 0.900 < 0.1100": + version "0.901.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.901.9.tgz#a60c41497e69d663cf2c74778cc72dd262cc09a1" + integrity sha512-eC6iZQR5tr9dz/SkR3/3Y8Fau/2IzEfHlFCf2mqsOLkbc0MWyM/3RcuZQhRGdVOyzDCIbfzJGY0N3ejkEn2EUg== + dependencies: + "@angular-devkit/architect" "0.901.9" + "@angular-devkit/build-optimizer" "0.901.9" + "@angular-devkit/build-webpack" "0.901.9" + "@angular-devkit/core" "9.1.9" + "@babel/core" "7.9.0" + "@babel/generator" "7.9.3" + "@babel/preset-env" "7.9.0" + "@babel/template" "7.8.6" + "@jsdevtools/coverage-istanbul-loader" "3.0.3" + "@ngtools/webpack" "9.1.9" + ajv "6.12.0" + autoprefixer "9.7.4" babel-loader "8.0.6" - browserslist "4.8.3" - cacache "13.0.1" - caniuse-lite "1.0.30001020" + browserslist "^4.9.1" + cacache "15.0.0" + caniuse-lite "^1.0.30001032" circular-dependency-plugin "5.2.0" - copy-webpack-plugin "5.1.1" + copy-webpack-plugin "6.0.2" core-js "3.6.4" - coverage-istanbul-loader "2.0.3" + css-loader "3.5.1" cssnano "4.1.10" - file-loader "4.2.0" - find-cache-dir "3.0.0" - glob "7.1.5" - jest-worker "24.9.0" + file-loader "6.0.0" + find-cache-dir "3.3.1" + glob "7.1.6" + jest-worker "25.1.0" karma-source-map-support "1.4.0" - less "3.10.3" + less "3.11.3" less-loader "5.0.0" - license-webpack-plugin "2.1.3" - loader-utils "1.2.3" - magic-string "0.25.4" - mini-css-extract-plugin "0.8.0" + license-webpack-plugin "2.1.4" + loader-utils "2.0.0" + mini-css-extract-plugin "0.9.0" minimatch "3.0.4" - open "7.0.0" + open "7.0.3" parse5 "4.0.0" - postcss "7.0.21" + postcss "7.0.27" postcss-import "12.0.1" postcss-loader "3.0.0" - raw-loader "3.1.0" - regenerator-runtime "0.13.3" - rimraf "3.0.0" - rollup "1.25.2" - rxjs "6.5.3" - sass "1.23.3" - sass-loader "8.0.0" - semver "6.3.0" + raw-loader "4.0.0" + regenerator-runtime "0.13.5" + rimraf "3.0.2" + rollup "2.1.0" + rxjs "6.5.4" + sass "1.26.3" + sass-loader "8.0.2" + semver "7.1.3" source-map "0.7.3" source-map-loader "0.2.4" - source-map-support "0.5.16" speed-measure-webpack-plugin "1.3.1" - style-loader "1.0.0" + style-loader "1.1.3" stylus "0.54.7" stylus-loader "3.0.2" - terser "4.5.1" - terser-webpack-plugin "2.3.3" + terser "4.6.10" + terser-webpack-plugin "3.0.3" tree-kill "1.2.2" - webpack "4.41.2" + webpack "4.42.0" webpack-dev-middleware "3.7.2" - webpack-dev-server "3.9.0" + webpack-dev-server "3.11.0" webpack-merge "4.2.2" webpack-sources "1.4.3" - webpack-subresource-integrity "1.3.4" - worker-plugin "3.2.0" + webpack-subresource-integrity "1.4.0" + worker-plugin "4.0.3" -"@angular-devkit/build-ng-packagr@~0.900": - version "0.900.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-ng-packagr/-/build-ng-packagr-0.900.5.tgz#ce4cdaf59c73324f1cf78dba24233840570bbd5a" - integrity sha512-NAslDl/oXw+Tisk4Nx7PgzuTq1AOd7c/4vQ5uTPkTZ/XXqomMlN18wkSzhTlqyXs91wC1DE+B8/eVKwLbufyFA== +"@angular-devkit/build-ng-packagr@>= 0.900 < 0.1100": + version "0.901.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-ng-packagr/-/build-ng-packagr-0.901.9.tgz#ade174940ab11da292a773a2b8149f9c6f5e78c3" + integrity sha512-tZvRAJcBSvYEPcwRRdXtpklS/7pf5Y5QvsTuK34MiVZD7T/fBwMtIqGhIq3o0uxVqBnQdpBFxoRgE3DL1AdY7g== dependencies: - "@angular-devkit/architect" "0.900.5" - rxjs "6.5.3" + "@angular-devkit/architect" "0.901.9" + rxjs "6.5.4" -"@angular-devkit/build-optimizer@0.900.5": - version "0.900.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.900.5.tgz#7b105b7389d2f2cba7829b4816ea8a3cfda9c0e8" - integrity sha512-BdmvD58DnAAf6/o/fRzU2l+2g4IwuIJf8x/rd9AGWd7fHrcwgJDhB9rYetB7JqYR8uOWk+AFElDpvNOj8YUy0w== +"@angular-devkit/build-optimizer@0.901.9": + version "0.901.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.901.9.tgz#c8018de2406c8bbf32bf74cdacd6fa1df384a8d0" + integrity sha512-AcDhE7RHmaVEaDB02MHp1PR2gdUg3+G/12pDC3GeAlfP1GD/sVBpcqPL6DHFp0dMm/FsvSfVSaXpzD7jZBeIKQ== dependencies: - loader-utils "1.2.3" + loader-utils "2.0.0" source-map "0.7.3" - tslib "1.10.0" - typescript "3.6.4" + tslib "1.11.1" + typescript "3.6.5" webpack-sources "1.4.3" -"@angular-devkit/build-webpack@0.900.5": - version "0.900.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.900.5.tgz#bd8e2fecfb3b8ca119b8c152d5f459475ffdcd15" - integrity sha512-4fYZNg8X73wTjlXV37m0BRVMa27GSwhAupgv5cb9Q3Vys9sYxEUL+GJetXDxypA5YbMj5xX/xqyU9TPtvXhgRg== +"@angular-devkit/build-webpack@0.901.9": + version "0.901.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.901.9.tgz#19e783950b2f22ceaa0c33b07552bd225dcd412b" + integrity sha512-Bha9LruitixhtJm72FGzqfDfgsOsrMT3EbNSql2muyoELIYbLDOvNZjcDD06CPcOAWSg6/tH9caOTFS2Zj9yOw== dependencies: - "@angular-devkit/architect" "0.900.5" - "@angular-devkit/core" "9.0.5" - rxjs "6.5.3" + "@angular-devkit/architect" "0.901.9" + "@angular-devkit/core" "9.1.9" + rxjs "6.5.4" "@angular-devkit/core@8.3.24", "@angular-devkit/core@^8.3.21": version "8.3.24" @@ -116,15 +116,15 @@ rxjs "6.4.0" source-map "0.7.3" -"@angular-devkit/core@9.0.5", "@angular-devkit/core@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.5.tgz#4ac28d94af02a24e84165a36142efc0e8a88f76f" - integrity sha512-9TPQPzfSRbV5wVEnfo1d1CS+oVXROfE7VnBRuRMilFnNhuc29wX3zvBQRTreDVyxJetLBEb9sRlcKYGaJzpKPw== +"@angular-devkit/core@9.1.9", "@angular-devkit/core@^9.0.0 || ^10.0.0": + version "9.1.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.1.9.tgz#e6283912093179313ccfc69856841e9b6b318231" + integrity sha512-SWgBh4an/Vezjw2BZ5S+bKvuK5lH6gOtR8d5YjN9vxpJSZ0GimrGjfnLlWOkwWAsU8jfn4JzofECUHwX/7EW6Q== dependencies: - ajv "6.10.2" - fast-json-stable-stringify "2.0.0" - magic-string "0.25.4" - rxjs "6.5.3" + ajv "6.12.0" + fast-json-stable-stringify "2.1.0" + magic-string "0.25.7" + rxjs "6.5.4" source-map "0.7.3" "@angular-devkit/schematics@8.3.24", "@angular-devkit/schematics@^8.3.21": @@ -135,55 +135,55 @@ "@angular-devkit/core" "8.3.24" rxjs "6.4.0" -"@angular-devkit/schematics@9.0.5", "@angular-devkit/schematics@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.5.tgz#fd2b8d94de3e037e75c5221d4283fb57221d39db" - integrity sha512-PbOYoy4YyEbR6f1jO18Rt3fJuyaaTJ3bFmws5qWGGNK2yZiP/hnSaM3VffOwoL4sgyKkI2FNKSPiQZgTl8b0Tg== - dependencies: - "@angular-devkit/core" "9.0.5" - ora "4.0.2" - rxjs "6.5.3" - -"@angular/animations@ ^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.0.5.tgz#ac64c9f702e78d5e2d6bff645daf047c4865cc02" - integrity sha512-WGs4Jxw5sr8GCpxMcwEVuZnDIkdNp9qtmuI2j13v/XAaMjvJ7jssCj9+JG5uI8joCi7PFVAWokPT1DdPwWb13Q== - -"@angular/cli@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-9.0.5.tgz#ba3dc3051f1aa8884f037c7246256439ee2fe814" - integrity sha512-hRGpmIwnm908eW5sA4zrVkCGaIUHYLSNu5koaLulK0jj5Iy+vkieDiBuAkD2uVvG7M59s4s4u+L0DMetIpvZQg== - dependencies: - "@angular-devkit/architect" "0.900.5" - "@angular-devkit/core" "9.0.5" - "@angular-devkit/schematics" "9.0.5" - "@schematics/angular" "9.0.5" - "@schematics/update" "0.900.5" +"@angular-devkit/schematics@9.1.9", "@angular-devkit/schematics@^9.0.0 || ^10.0.0": + version "9.1.9" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.1.9.tgz#1369ee586cb91ffebf12673bb839d31ad5c00357" + integrity sha512-aKuMmS3wshOTl9+01jiB50ml09fRN1WfOOtoNqwvKTEi87DrT6Mn3l0eVQo8PJK/bIq/FBmPgsIl2nsETiBSxg== + dependencies: + "@angular-devkit/core" "9.1.9" + ora "4.0.3" + rxjs "6.5.4" + +"@angular/animations@ ^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-9.1.11.tgz#2c7b6e584df0ba0884d05f01fa7ab86c1fdd1c5e" + integrity sha512-VKAExUnEJfo1PDQKagpx2pn+QMZCsPLRiADzTdl4U0VPylK3ALbn4ZNY9UbdwyE2plitz++LkH7sEGGfh+PNrQ== + +"@angular/cli@^9.0.0 || ^10.0.0": + version "9.1.9" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-9.1.9.tgz#e9caced7c107c65075fe1b4c42a4712a5aeb992c" + integrity sha512-k8C0OY3oHoixd3buCgF8+VFe8YZGSGiprnbVMEF2WJHUUw87lPCu/d7dbID3AtVwdKdAB275rAt6IZEIzXInbw== + dependencies: + "@angular-devkit/architect" "0.901.9" + "@angular-devkit/core" "9.1.9" + "@angular-devkit/schematics" "9.1.9" + "@schematics/angular" "9.1.9" + "@schematics/update" "0.901.9" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" - debug "^4.1.1" + debug "4.1.1" ini "1.3.5" - inquirer "7.0.0" - npm-package-arg "6.1.1" - npm-pick-manifest "3.0.2" - open "7.0.0" - pacote "9.5.8" + inquirer "7.1.0" + npm-package-arg "8.0.1" + npm-pick-manifest "6.0.0" + open "7.0.3" + pacote "9.5.12" read-package-tree "5.3.1" - rimraf "3.0.0" - semver "6.3.0" + rimraf "3.0.2" + semver "7.1.3" symbol-observable "1.2.0" - universal-analytics "^0.4.20" - uuid "^3.3.2" + universal-analytics "0.4.20" + uuid "7.0.2" -"@angular/common@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.0.5.tgz#80e5ebbd5ec9b7f33bace0d6f70267b07cba9090" - integrity sha512-AwZKYK5M/3762woK+3290JnBdlBvZXqxX5vVze6wk23IiBlwIV+l79+Lyfjo/4s031kibq47taaZdC7qkkBkNA== +"@angular/common@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-9.1.11.tgz#1323f7b043410791bd2d0d71b0bbb1f862319c04" + integrity sha512-Vh5lF7zWwDK9RedmYXUc8vUXyrecR3j1mAWlTlnmcHYxxFThPzN/dr0slQcPi6nyJn0EmyRKUGvAoZx4rIb7wg== -"@angular/compiler-cli@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-9.0.5.tgz#b7b7dba46a9495e2ca7efd412f6555e2544fc59d" - integrity sha512-lFlasm8UBApTq4/MkxnYrRAMfpOvvg3YYBEMibuEGlaJjW/Xd1JcisUuFiooCxCIKF5phyORHmxjywGPhHqQgQ== +"@angular/compiler-cli@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-9.1.11.tgz#39da68ddadb52008fe5231141707bddd3aa790b2" + integrity sha512-9qIxbtpRXOQnRm6inxCa5HuH87MSuMzuceD0YBVzl8v+vLtewon9KXYMmF4kTBhWa/LEa8FrajljLh0azf3VLg== dependencies: canonical-path "1.0.0" chokidar "^3.0.0" @@ -196,63 +196,74 @@ semver "^6.3.0" source-map "^0.6.1" sourcemap-codec "^1.4.8" - yargs "13.1.0" + yargs "15.3.0" -"@angular/compiler@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.0.5.tgz#823dd4df25a9f1a641346712e7b7097ed1176105" - integrity sha512-TeyhRGefTOtA9N3udMrvheafoXcz/dvTTdZLcieeZQxm1SSeaQDUQ/rUH6QTOiHVNMtjOCrZ9J5rk1A4mPYuag== +"@angular/compiler@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-9.1.11.tgz#4c7100f53c87f47e793e149427b8bdee44302381" + integrity sha512-MbVheCG0U8gt6xtiipau20N26mD2sXjLChVmRKgO6rbDruxboNMZfEd94q9NP9JRaUsVnjXvY7GMDldoymdXig== -"@angular/core@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.0.5.tgz#71df41a45e60619fb7454ab9fe604d6ce7d0d8da" - integrity sha512-7VznrYjaAIzeq/zQ7v6tbeoOI7JJKgChKwG7s8jRoEpENu+w2pRlRdyQul88iJLsXgObR+/TfBNm/K+G4cqAFw== +"@angular/core@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-9.1.11.tgz#7a92d27292212ed381be15f9000d4019867f1c7c" + integrity sha512-KAlEedBo761O1aeoTJVziOSHi8Fttk9ipvbDZXYT/o0W/KdVwubxP34g9t5aD8LCcF8+L0z4VLw++HjdJAUpwg== -"@angular/platform-browser-dynamic@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.5.tgz#df569a99d9d077733e53d3323e9f88f410f5f3df" - integrity sha512-NRfsAwbgxOvEcpqlERDAG0wap5xJa0wKwnudTCnyvf4B0D6kLkT1Idjqv22NDW5rfM2oDWaZ/qpgpDnAo6/ZBQ== +"@angular/platform-browser-dynamic@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.11.tgz#82af336b05e0d7b7478a2ca7f6282825b211f340" + integrity sha512-Qw3rfVFF0Wtu+UwraqKPCgTA3uoNPGf4vKSfuCuXTrG0p7j+3mCP59aUv5gGH7GV1UQ++jZRx5pbWF43zrC8Hw== -"@angular/platform-browser@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.0.5.tgz#a760fa7d5921d7b58875b07dfe0a408c92abf143" - integrity sha512-24QGcQXthYXB/wT8okJjxqss/JOk4A6O1/Fmva79k0AvwtYkl2tikcyEc5T3xZtjoi8g32AN9nbZAobtkxlqTA== +"@angular/platform-browser@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-9.1.11.tgz#4da8e2a4231d5162304746a39f54cb2d3f241b7c" + integrity sha512-KDxoiFhW4UD+EqchcKpQVSLwg9Rd3JbWytZLchFV6nH8BFnshfJtw2tyPT8bMhFVG9n9zSR4QSGaozWgoDs9mw== -"@angular/platform-server@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-9.0.5.tgz#b6d233247c47444735ebaa80fb7b44267670ebe5" - integrity sha512-5iEugPj0oZgw6JHS5s8m4WejCnEoNeWgttzsCQuyCaVmIOQGCbTdqSsxD+AgBO7A5lrzxYQOgil/XCM/up5Smw== +"@angular/platform-server@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-9.1.11.tgz#c47144568fdafee4eae8f48a686568f19fc2c23b" + integrity sha512-eHqlbtDHvYZIxtY6iKYpuRg9vTw5JoEH1M5rna2YDPI1MOnDdNhmpupIF6M3jnNAzN6xsh4X4wxW3PYHJVJviA== dependencies: domino "^2.1.2" - xhr2 "^0.1.4" + xhr2 "^0.2.0" -"@angular/router@^9.0.0": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-9.0.5.tgz#97f23adc933e96ba04c0ef93b3a8f0c2e7777e77" - integrity sha512-Sz3DQUxlzAk9aZ9eVtZRh6xF5SMg/Gb3rc5I7dL1M+mycSNoFJ4HPTXleZkKM69mMkKQ5fEtza4x26MSlF+O9w== +"@angular/router@^9.0.0 || ^10.0.0": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-9.1.11.tgz#b6d28af55fe5631bbc46f306a0e7866253d4f3b1" + integrity sha512-D6CCDeSK/F6dWSB/a1g/zB072xG5LadLSV8afQ57oX1KHePx21LcoRG4tUtFMMHh/jZXRc9pMQIR1/9FrrXF3Q== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== dependencies: "@babel/highlight" "^7.8.3" -"@babel/core@7.7.7": - version "7.7.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.7.tgz#ee155d2e12300bcc0cff6a8ad46f2af5063803e9" - integrity sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ== +"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" + integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.7" - "@babel/helpers" "^7.7.4" - "@babel/parser" "^7.7.7" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + browserslist "^4.9.1" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" + integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.0" + "@babel/parser" "^7.9.0" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" convert-source-map "^1.7.0" debug "^4.1.0" - json5 "^2.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" lodash "^4.17.13" resolve "^1.3.2" semver "^5.4.1" @@ -279,17 +290,17 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@7.7.7": - version "7.7.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.7.tgz#859ac733c44c74148e1a72980a64ec84b85f4f45" - integrity sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ== +"@babel/generator@7.9.3": + version "7.9.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.3.tgz#7c8b2956c6f68b3ab732bd16305916fbba521d94" + integrity sha512-RpxM252EYsz9qLUIq6F7YJyK1sv0wWDBFuztfDGWaQKzHjqDHysxSiRUpA/X9jmfqo+WzkAVKFaUily5h+gDCQ== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.9.0" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" -"@babel/generator@^7.4.0", "@babel/generator@^7.7.7", "@babel/generator@^7.8.4": +"@babel/generator@^7.4.0", "@babel/generator@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== @@ -299,6 +310,16 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce" + integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA== + dependencies: + "@babel/types" "^7.9.0" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" @@ -314,14 +335,16 @@ "@babel/helper-explode-assignable-expression" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-call-delegate@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" - integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== +"@babel/helper-compilation-targets@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" + integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== dependencies: - "@babel/helper-hoist-variables" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/compat-data" "^7.8.6" + browserslist "^4.9.1" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" "@babel/helper-create-regexp-features-plugin@^7.8.3": version "7.8.3" @@ -331,6 +354,15 @@ "@babel/helper-regex" "^7.8.3" regexpu-core "^4.6.0" +"@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.7.0" + "@babel/helper-define-map@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" @@ -378,23 +410,24 @@ dependencies: "@babel/types" "^7.8.3" -"@babel/helper-module-imports@^7.7.4", "@babel/helper-module-imports@^7.8.3": +"@babel/helper-module-imports@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== dependencies: "@babel/types" "^7.8.3" -"@babel/helper-module-transforms@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" - integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== dependencies: "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-simple-access" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" lodash "^4.17.13" "@babel/helper-optimise-call-expression@^7.8.3": @@ -437,6 +470,16 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" + "@babel/helper-simple-access@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" @@ -452,6 +495,11 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-validator-identifier@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" + integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== + "@babel/helper-wrap-function@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" @@ -462,7 +510,7 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helpers@^7.7.4", "@babel/helpers@^7.8.4": +"@babel/helpers@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== @@ -471,6 +519,15 @@ "@babel/traverse" "^7.8.4" "@babel/types" "^7.8.3" +"@babel/helpers@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" + integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" + "@babel/highlight@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" @@ -480,12 +537,17 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.4.3", "@babel/parser@^7.7.5", "@babel/parser@^7.7.7", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": +"@babel/parser@^7.4.3", "@babel/parser@^7.7.5", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== -"@babel/plugin-proposal-async-generator-functions@^7.7.4": +"@babel/parser@^7.8.6", "@babel/parser@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" + integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== + +"@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== @@ -494,7 +556,7 @@ "@babel/helper-remap-async-to-generator" "^7.8.3" "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-dynamic-import@^7.7.4": +"@babel/plugin-proposal-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== @@ -502,7 +564,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-json-strings@^7.7.4": +"@babel/plugin-proposal-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== @@ -510,15 +572,31 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/plugin-proposal-object-rest-spread@^7.7.7": +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" - integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" + integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + +"@babel/plugin-proposal-object-rest-spread@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" + integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== dependencies: "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" -"@babel/plugin-proposal-optional-catch-binding@^7.7.4": +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== @@ -526,64 +604,93 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-unicode-property-regex@^7.7.7": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" - integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ== +"@babel/plugin-proposal-optional-chaining@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" + integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-syntax-async-generators@^7.7.4", "@babel/plugin-syntax-async-generators@^7.8.0": +"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.8" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-async-generators@^7.8.0": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-dynamic-import@^7.7.4", "@babel/plugin-syntax-dynamic-import@^7.8.0": +"@babel/plugin-syntax-dynamic-import@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-json-strings@^7.7.4", "@babel/plugin-syntax-json-strings@^7.8.0": +"@babel/plugin-syntax-json-strings@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-object-rest-spread@^7.7.4", "@babel/plugin-syntax-object-rest-spread@^7.8.0": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" + integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.7.4", "@babel/plugin-syntax-optional-catch-binding@^7.8.0": +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.7.4": +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-arrow-functions@^7.7.4": +"@babel/plugin-transform-arrow-functions@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-async-to-generator@^7.7.4": +"@babel/plugin-transform-async-to-generator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== @@ -592,14 +699,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-remap-async-to-generator" "^7.8.3" -"@babel/plugin-transform-block-scoped-functions@^7.7.4": +"@babel/plugin-transform-block-scoped-functions@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-block-scoping@^7.7.4": +"@babel/plugin-transform-block-scoping@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== @@ -607,35 +714,35 @@ "@babel/helper-plugin-utils" "^7.8.3" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" - integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== +"@babel/plugin-transform-classes@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" + integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== dependencies: "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-define-map" "^7.8.3" "@babel/helper-function-name" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.7.4": +"@babel/plugin-transform-computed-properties@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-destructuring@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b" - integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ== +"@babel/plugin-transform-destructuring@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" + integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-dotall-regex@^7.7.7": +"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== @@ -643,14 +750,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-duplicate-keys@^7.7.4": +"@babel/plugin-transform-duplicate-keys@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.7.4": +"@babel/plugin-transform-exponentiation-operator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== @@ -658,14 +765,14 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-for-of@^7.7.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" - integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== +"@babel/plugin-transform-for-of@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" + integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-function-name@^7.7.4": +"@babel/plugin-transform-function-name@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== @@ -673,72 +780,72 @@ "@babel/helper-function-name" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-literals@^7.7.4": +"@babel/plugin-transform-literals@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-member-expression-literals@^7.7.4": +"@babel/plugin-transform-member-expression-literals@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-modules-amd@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" - integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== +"@babel/plugin-transform-modules-amd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" + integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== dependencies: - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-commonjs@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" - integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== +"@babel/plugin-transform-modules-commonjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" + integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== dependencies: - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-simple-access" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-systemjs@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" - integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== +"@babel/plugin-transform-modules-systemjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" + integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== dependencies: "@babel/helper-hoist-variables" "^7.8.3" - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-umd@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" - integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== +"@babel/plugin-transform-modules-umd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" + integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== dependencies: - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.8.3" -"@babel/plugin-transform-new-target@^7.7.4": +"@babel/plugin-transform-new-target@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-object-super@^7.7.4": +"@babel/plugin-transform-object-super@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== @@ -746,51 +853,50 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.7.7": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" - integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== +"@babel/plugin-transform-parameters@^7.8.7": + version "7.9.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a" + integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg== dependencies: - "@babel/helper-call-delegate" "^7.8.3" "@babel/helper-get-function-arity" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-property-literals@^7.7.4": +"@babel/plugin-transform-property-literals@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" - integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== +"@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== dependencies: - regenerator-transform "^0.14.0" + regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.7.4": +"@babel/plugin-transform-reserved-words@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-shorthand-properties@^7.7.4": +"@babel/plugin-transform-shorthand-properties@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-spread@^7.7.4": +"@babel/plugin-transform-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-sticky-regex@^7.7.4": +"@babel/plugin-transform-sticky-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== @@ -798,7 +904,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-regex" "^7.8.3" -"@babel/plugin-transform-template-literals@^7.7.4": +"@babel/plugin-transform-template-literals@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== @@ -806,14 +912,14 @@ "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-typeof-symbol@^7.7.4": +"@babel/plugin-transform-typeof-symbol@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-unicode-regex@^7.7.4": +"@babel/plugin-transform-unicode-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== @@ -821,63 +927,99 @@ "@babel/helper-create-regexp-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/preset-env@7.7.7": - version "7.7.7" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.7.tgz#c294167b91e53e7e36d820e943ece8d0c7fe46ac" - integrity sha512-pCu0hrSSDVI7kCVUOdcMNQEbOPJ52E+LrQ14sN8uL2ALfSqePZQlKrOy+tM4uhEdYlCHi4imr8Zz2cZe9oSdIg== +"@babel/preset-env@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" + integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.7.4" - "@babel/plugin-proposal-dynamic-import" "^7.7.4" - "@babel/plugin-proposal-json-strings" "^7.7.4" - "@babel/plugin-proposal-object-rest-spread" "^7.7.7" - "@babel/plugin-proposal-optional-catch-binding" "^7.7.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.7.7" - "@babel/plugin-syntax-async-generators" "^7.7.4" - "@babel/plugin-syntax-dynamic-import" "^7.7.4" - "@babel/plugin-syntax-json-strings" "^7.7.4" - "@babel/plugin-syntax-object-rest-spread" "^7.7.4" - "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" - "@babel/plugin-syntax-top-level-await" "^7.7.4" - "@babel/plugin-transform-arrow-functions" "^7.7.4" - "@babel/plugin-transform-async-to-generator" "^7.7.4" - "@babel/plugin-transform-block-scoped-functions" "^7.7.4" - "@babel/plugin-transform-block-scoping" "^7.7.4" - "@babel/plugin-transform-classes" "^7.7.4" - "@babel/plugin-transform-computed-properties" "^7.7.4" - "@babel/plugin-transform-destructuring" "^7.7.4" - "@babel/plugin-transform-dotall-regex" "^7.7.7" - "@babel/plugin-transform-duplicate-keys" "^7.7.4" - "@babel/plugin-transform-exponentiation-operator" "^7.7.4" - "@babel/plugin-transform-for-of" "^7.7.4" - "@babel/plugin-transform-function-name" "^7.7.4" - "@babel/plugin-transform-literals" "^7.7.4" - "@babel/plugin-transform-member-expression-literals" "^7.7.4" - "@babel/plugin-transform-modules-amd" "^7.7.5" - "@babel/plugin-transform-modules-commonjs" "^7.7.5" - "@babel/plugin-transform-modules-systemjs" "^7.7.4" - "@babel/plugin-transform-modules-umd" "^7.7.4" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.4" - "@babel/plugin-transform-new-target" "^7.7.4" - "@babel/plugin-transform-object-super" "^7.7.4" - "@babel/plugin-transform-parameters" "^7.7.7" - "@babel/plugin-transform-property-literals" "^7.7.4" - "@babel/plugin-transform-regenerator" "^7.7.5" - "@babel/plugin-transform-reserved-words" "^7.7.4" - "@babel/plugin-transform-shorthand-properties" "^7.7.4" - "@babel/plugin-transform-spread" "^7.7.4" - "@babel/plugin-transform-sticky-regex" "^7.7.4" - "@babel/plugin-transform-template-literals" "^7.7.4" - "@babel/plugin-transform-typeof-symbol" "^7.7.4" - "@babel/plugin-transform-unicode-regex" "^7.7.4" - "@babel/types" "^7.7.4" - browserslist "^4.6.0" - core-js-compat "^3.6.0" + "@babel/compat-data" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.0" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.8.3" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-modules-commonjs" "^7.9.0" + "@babel/plugin-transform-modules-systemjs" "^7.9.0" + "@babel/plugin-transform-modules-umd" "^7.9.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.8.7" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.0" + browserslist "^4.9.1" + core-js-compat "^3.6.2" invariant "^2.2.2" - js-levenshtein "^1.1.3" + levenary "^1.1.1" semver "^5.5.0" +"@babel/preset-modules@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" + integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.8.4": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@7.8.6", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" + "@babel/template@^7.4.0", "@babel/template@^7.7.4", "@babel/template@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" @@ -902,7 +1044,22 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.4.0", "@babel/types@^7.7.4", "@babel/types@^7.8.3": +"@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" + integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.9.0" + "@babel/types" "^7.9.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.4.0", "@babel/types@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== @@ -911,6 +1068,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.4.4", "@babel/types@^7.8.6", "@babel/types@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" + integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@firebase/analytics-types@0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.3.0.tgz#33c3f695313b561d48d18d663a20f20362d3ee7c" @@ -1302,16 +1468,55 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@ngtools/webpack@9.0.5": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-9.0.5.tgz#efd6d40d87c685339b402bcc68eef9b0de95d2fa" - integrity sha512-xe0rGpme04MNRK/PpPOx8cza9k8F/XuAOmxC3Tk4dIgigqIzYsP6v6N/At8vPRDrf88X4ZyR94lL5RrUYf/KNQ== +"@jsdevtools/coverage-istanbul-loader@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.3.tgz#102e414b02ae2f0b3c7fd45a705601e1fd4867c5" + integrity sha512-TAdNkeGB5Fe4Og+ZkAr1Kvn9by2sfL44IAHFtxlh1BA1XJ5cLpO9iSNki5opWESv3l3vSHsZ9BNKuqFKbEbFaA== + dependencies: + convert-source-map "^1.7.0" + istanbul-lib-instrument "^4.0.1" + loader-utils "^1.4.0" + merge-source-map "^1.1.0" + schema-utils "^2.6.4" + +"@ngtools/webpack@9.1.9": + version "9.1.9" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-9.1.9.tgz#2098afd6f1f028238468262df2ad10afa81b82a5" + integrity sha512-7UzRL54JcK1m2PvgpchV26TF9OYipj/8+dygdjaidqOyQujWpHncdtq/ScbUsoJ44nHjIRJPhaGE00NLpWZvnA== dependencies: - "@angular-devkit/core" "9.0.5" + "@angular-devkit/core" "9.1.9" enhanced-resolve "4.1.1" - rxjs "6.5.3" + rxjs "6.5.4" webpack-sources "1.4.3" +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + +"@npmcli/move-file@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464" + integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw== + dependencies: + mkdirp "^1.0.4" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -1365,13 +1570,13 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= -"@schematics/angular@9.0.5": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.0.5.tgz#a40abc25e3da49dad539324e384a1b98ec6cf36b" - integrity sha512-OUCC5J5+9v2tc3O/GL+2E9LfIXeqYCo/gdOTgb+jSos0aQQ7wnXOmufuoOsgt0KrWpAt34MIBktLNUF1n+RgcQ== +"@schematics/angular@9.1.9": + version "9.1.9" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.1.9.tgz#df9f30dd7b63856121fbb9ab5dda57b443802a33" + integrity sha512-c8YGZ6pDfr8IDD1qaOjlEBAkEz14KFSxDj0hCWs0xIM0py513tu5sW8+ziYxGG4bgqpsgVR/KAxuY78iBfUVag== dependencies: - "@angular-devkit/core" "9.0.5" - "@angular-devkit/schematics" "9.0.5" + "@angular-devkit/core" "9.1.9" + "@angular-devkit/schematics" "9.1.9" "@schematics/angular@^8.3.21": version "8.3.24" @@ -1381,19 +1586,19 @@ "@angular-devkit/core" "8.3.24" "@angular-devkit/schematics" "8.3.24" -"@schematics/update@0.900.5": - version "0.900.5" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.900.5.tgz#97c9a3813e708b42ec4d516378b9ff7c8d34d4b6" - integrity sha512-Nte+9DfQHQkrgqZPX1viccs6UXL+FDGHkTIB/KTisJAvC4s+o9hjKAoCldWBsPi9/p5rXPNZ+EWmXx7vSLGSNQ== +"@schematics/update@0.901.9": + version "0.901.9" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.901.9.tgz#6285611910ebf8bb4078447d2ba32931595efcd4" + integrity sha512-VChX0VO/oyfCF3y+HjMTU2qN3vGgJYxEI1V+Q9aAlwl95t3GAufuaFY1CNW3YV4XkYIjD88e3yWl8d5yO4qf4w== dependencies: - "@angular-devkit/core" "9.0.5" - "@angular-devkit/schematics" "9.0.5" + "@angular-devkit/core" "9.1.9" + "@angular-devkit/schematics" "9.1.9" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" - npm-package-arg "^7.0.0" - pacote "9.5.8" - rxjs "6.5.3" - semver "6.3.0" + npm-package-arg "^8.0.0" + pacote "9.5.12" + rxjs "6.5.4" + semver "7.1.3" semver-intersect "1.4.0" "@schematics/update@^0.803.21": @@ -1540,6 +1745,11 @@ resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.2.tgz#9ff982e0ddca82f65e5d85a3f0584e9e6b92c47b" integrity sha512-7hrdBDFWlTb4EhrXYRyC7i3L2kKCV0TqYbzuV+gwyPNF2V4SSHw2Vs223ai26W4tEg+t4e9Wfi1vW6JLubYPiw== +"@types/json-schema@^7.0.4": + version "7.0.5" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" + integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -1595,6 +1805,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + "@types/q@^1.5.1": version "1.5.2" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" @@ -2045,6 +2260,16 @@ ajv@6.10.2: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@6.12.0, ajv@^6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" + integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: version "6.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" @@ -2055,6 +2280,16 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.2: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -2150,7 +2385,7 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -2302,6 +2537,11 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -2445,20 +2685,7 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@9.7.1: - version "9.7.1" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.1.tgz#9ffc44c55f5ca89253d9bb7186cefb01ef57747f" - integrity sha512-w3b5y1PXWlhYulevrTJ0lizkQ5CyqfeU6BIRDbuhsMupstHQOeb1Ur80tcB1zxSu7AwyY/qCQ7Vvqklh31ZBFw== - dependencies: - browserslist "^4.7.2" - caniuse-lite "^1.0.30001006" - chalk "^2.4.2" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.21" - postcss-value-parser "^4.0.2" - -autoprefixer@^9.6.5: +autoprefixer@9.7.4, autoprefixer@^9.6.5: version "9.7.4" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" integrity sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g== @@ -2927,7 +3154,7 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.2, braces@~3.0.2: +braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2998,16 +3225,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.3.tgz#65802fcd77177c878e015f0e3189f2c4f627ba44" - integrity sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg== - dependencies: - caniuse-lite "^1.0.30001017" - electron-to-chromium "^1.3.322" - node-releases "^1.1.44" - -browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.7.0, browserslist@^4.7.2, browserslist@^4.8.3: +browserslist@^4.0.0, browserslist@^4.7.0, browserslist@^4.8.3: version "4.8.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.6.tgz#96406f3f5f0755d272e27a66f4163ca821590a7e" integrity sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg== @@ -3016,6 +3234,16 @@ browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.7.0, browserslist@^4.7 electron-to-chromium "^1.3.341" node-releases "^1.1.47" +browserslist@^4.9.1: + version "4.11.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.1.tgz#92f855ee88d6e050e7e7311d987992014f1a1f1b" + integrity sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g== + dependencies: + caniuse-lite "^1.0.30001038" + electron-to-chromium "^1.3.390" + node-releases "^1.1.53" + pkg-up "^2.0.0" + buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -3138,31 +3366,30 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@13.0.1, cacache@^13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" - integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== +cacache@15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.0.tgz#133b59edbd2a37ea8ef2d54964c6f247e47e5059" + integrity sha512-L0JpXHhplbJSiDGzyJJnJCTL7er7NzbBgxzVqLswEb4bO91Zbv17OUMuUeu/q0ZwKn3V+1HM4wb9tO4eVE/K8g== dependencies: chownr "^1.1.2" - figgy-pudding "^3.5.1" fs-minipass "^2.0.0" glob "^7.1.4" - graceful-fs "^4.2.2" infer-owner "^1.0.4" lru-cache "^5.1.1" - minipass "^3.0.0" + minipass "^3.1.1" minipass-collect "^1.0.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.2" - mkdirp "^0.5.1" + mkdirp "^1.0.3" move-concurrently "^1.0.1" p-map "^3.0.0" promise-inflight "^1.0.1" rimraf "^2.7.1" - ssri "^7.0.0" + ssri "^8.0.0" + tar "^6.0.1" unique-filename "^1.1.1" -cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: +cacache@^12.0.0, cacache@^12.0.2: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -3183,6 +3410,29 @@ cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: unique-filename "^1.1.1" y18n "^4.0.0" +cacache@^15.0.4: + version "15.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.4.tgz#b2c23cf4ac4f5ead004fb15a0efb0a20340741f1" + integrity sha512-YlnKQqTbD/6iyoJvEY3KJftjrdBYroCbxxYXzhOzsFLWlp6KX4BOlEf4mTx0cMUfVaTS3ENL2QtDWeRYoGLkkw== + dependencies: + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^5.1.1" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.0" + tar "^6.0.2" + unique-filename "^1.1.1" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -3235,6 +3485,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -3282,16 +3537,16 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@1.0.30001020: - version "1.0.30001020" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001020.tgz#3f04c1737500ffda78be9beb0b5c1e2070e15926" - integrity sha512-yWIvwA68wRHKanAVS1GjN8vajAv7MBFshullKCeq/eKpK7pJBVDgFFEqvgWTkcP2+wIDeQGYFRXECjKZnLkUjA== - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001006, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001023: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001023: version "1.0.30001023" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz#b82155827f3f5009077bdd2df3d8968bcbcc6fc4" integrity sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA== +caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001038: + version "1.0.30001039" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001039.tgz#b3814a1c38ffeb23567f8323500c09526a577bbe" + integrity sha512-SezbWCTT34eyFoWHgx8UWso7YtvtM7oosmFoXbCkdC6qJzRfBTeTgE9REtKtiuKXuMwWTZEvdnFNGAyVMorv8Q== + canonical-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" @@ -3374,6 +3629,14 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/char-spinner/-/char-spinner-1.0.1.tgz#e6ea67bd247e107112983b7ab0479ed362800081" @@ -3423,6 +3686,16 @@ chownr@^1.1.1, chownr@^1.1.2: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== +chownr@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" @@ -3553,14 +3826,14 @@ cliui@^3.0.3: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" cliui@^6.0.0: version "6.0.0" @@ -3771,6 +4044,11 @@ compare-versions@^3.4.0: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.5.1.tgz#26e1f5cf0d48a77eced5046b9f67b6b61075a393" integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg== +compare-versions@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -4137,25 +4415,24 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" - integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg== - dependencies: - cacache "^12.0.3" - find-cache-dir "^2.1.0" - glob-parent "^3.1.0" - globby "^7.1.1" - is-glob "^4.0.1" - loader-utils "^1.2.3" - minimatch "^3.0.4" +copy-webpack-plugin@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.0.2.tgz#10efc6ad219a61acbf2f5fb50af83da38431bc34" + integrity sha512-9Gm8X0c6eXlKnmltMPFCBeGOKjtcRIyTt4VaO3k1TkNgVTe5Ov2lYsYVuyLp0kp8DItO3apewflM+1GYgh6V2Q== + dependencies: + cacache "^15.0.4" + fast-glob "^3.2.2" + find-cache-dir "^3.3.1" + glob-parent "^5.1.1" + globby "^11.0.1" + loader-utils "^2.0.0" normalize-path "^3.0.0" - p-limit "^2.2.1" - schema-utils "^1.0.0" - serialize-javascript "^2.1.2" - webpack-log "^2.0.0" + p-limit "^2.3.0" + schema-utils "^2.7.0" + serialize-javascript "^3.1.0" + webpack-sources "^1.4.3" -core-js-compat@^3.6.0: +core-js-compat@^3.6.2: version "3.6.4" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== @@ -4196,16 +4473,16 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" -coverage-istanbul-loader@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz#87d42f03fa0fd3fa8743ec76945d9d67f105722a" - integrity sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA== +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== dependencies: - convert-source-map "^1.7.0" - istanbul-lib-instrument "^4.0.0" - loader-utils "^1.2.3" - merge-source-map "^1.1.0" - schema-utils "^2.6.1" + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" crc32-stream@^3.0.1: version "3.0.1" @@ -4349,6 +4626,25 @@ css-declaration-sorter@^4.0.1: postcss "^7.0.1" timsort "^0.3.0" +css-loader@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.5.1.tgz#db2b2336f4169edb68e6a829ad4fd36552647b77" + integrity sha512-0G4CbcZzQ9D1Q6ndOfjFuMDo8uLYMu5vc9Abs5ztyHcKvmil6GJrMiNjzzi3tQvUF+mVRuDg7bE6Oc0Prolgig== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.27" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.2.0" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.0.3" + schema-utils "^2.6.5" + semver "^6.3.0" + css-parse@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" @@ -4425,6 +4721,11 @@ cssesc@^2.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + cssnano-preset-default@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" @@ -4595,7 +4896,7 @@ debug@3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1: +debug@4, debug@4.1.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -4858,12 +5159,12 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -dir-glob@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: - path-type "^3.0.0" + path-type "^4.0.0" dns-equal@^1.0.0: version "1.0.0" @@ -5019,11 +5320,16 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.322, electron-to-chromium@^1.3.341: +electron-to-chromium@^1.3.341: version "1.3.344" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.344.tgz#f1397a633c35e726730c24be1084cd25c3ee8148" integrity sha512-tvbx2Wl8WBR+ym3u492D0L6/jH+8NoQXqe46+QhbWH3voVPauGuZYeb1QAXYoOAWuiP2dbSvlBx0kQ1F3hu/Mw== +electron-to-chromium@^1.3.390: + version "1.3.397" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.397.tgz#db640c2e67b08d590a504c20b56904537aa2bafa" + integrity sha512-zcUd1p/7yzTSdWkCTrqGvbnEOASy96d0RJL/lc5BDJoO23Z3G/VHd0yIPbguDU9n8QNUTCigLO7oEdtOb7fp2A== + elliptic@^6.0.0: version "6.5.2" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" @@ -5052,6 +5358,11 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + enabled@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" @@ -5507,12 +5818,24 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== +fast-glob@^3.1.1, fast-glob@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.1.0, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5539,6 +5862,13 @@ fastparse@^1.1.1: resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== +fastq@^1.6.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" + integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + dependencies: + reusify "^1.0.4" + faye-websocket@0.11.3, faye-websocket@~0.11.1: version "0.11.3" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" @@ -5577,13 +5907,13 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-loader@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e" - integrity sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ== +file-loader@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" + integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ== dependencies: - loader-utils "^1.2.3" - schema-utils "^2.0.0" + loader-utils "^2.0.0" + schema-utils "^2.6.5" file-uri-to-path@1.0.0: version "1.0.0" @@ -5633,13 +5963,13 @@ finalhandler@1.1.2, finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-cache-dir@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.0.0.tgz#cd4b7dd97b7185b7e17dbfe2d6e4115ee3eeb8fc" - integrity sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw== +find-cache-dir@3.3.1, find-cache-dir@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== dependencies: commondir "^1.0.1" - make-dir "^3.0.0" + make-dir "^3.0.2" pkg-dir "^4.1.0" find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: @@ -5651,15 +5981,6 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-cache-dir@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874" - integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.0" - pkg-dir "^4.1.0" - find-parent-dir@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" @@ -5673,7 +5994,7 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.0.0: +find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= @@ -5695,6 +6016,13 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-versions@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" + integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== + dependencies: + semver-regex "^2.0.0" + firebase-admin@^8.10.0: version "8.10.0" resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-8.10.0.tgz#4a838aec52df49845eba07ad59a40b4df996e815" @@ -5709,10 +6037,10 @@ firebase-admin@^8.10.0: "@google-cloud/firestore" "^3.0.0" "@google-cloud/storage" "^4.1.2" -firebase-functions-test@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/firebase-functions-test/-/firebase-functions-test-0.1.7.tgz#c1f9b82157a1435e38c6707f0943447403ab1703" - integrity sha512-/zVQhaUZ+M7z25aUaZSIah0MIDZIfnRfQxtHYTE8hgUgODmKdaMX20vh5Gv23hnCPauIHuYb7XFTUOZiWU1udA== +firebase-functions-test@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/firebase-functions-test/-/firebase-functions-test-0.2.0.tgz#797125d56c23ac6b175a9308cc7887c669d4bdb0" + integrity sha512-ItONnirBztDIMVgrUeb3sTFfNHnlRhaMopQfTjWt2FZ8COvX946FzgvKMQT708LGwiUVXW/4OjfAOKaW8A2nMw== dependencies: "@types/lodash" "^4.14.104" lodash "^4.17.5" @@ -6082,11 +6410,6 @@ gensync@^1.0.0-beta.1: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - get-caller-file@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -6181,6 +6504,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.1.0, glob-parent@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + glob-parent@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" @@ -6223,10 +6553,10 @@ glob@5.0.x: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.5: - version "7.1.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" - integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== +glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -6243,18 +6573,6 @@ glob@^3.2.11, glob@~3.2: inherits "2" minimatch "0.3" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-dirs@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -6279,6 +6597,18 @@ globals@^9.18.0: resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -6290,18 +6620,6 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -globby@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" - integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= - dependencies: - array-union "^1.0.1" - dir-glob "^2.0.0" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" - google-auth-library@^5.0.0, google-auth-library@^5.5.0: version "5.9.2" resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-5.9.2.tgz#e528f4f1cd10657073d7ae2b9a9ce17ac97c3538" @@ -6678,10 +6996,10 @@ html-comment-regex@^1.1.0: resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== -html-entities@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" - integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= +html-entities@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" + integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== html-escaper@^2.0.0: version "2.0.0" @@ -6830,6 +7148,22 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" +husky@^4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.5.tgz#2b4f7622673a71579f901d9885ed448394b5fa36" + integrity sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ== + dependencies: + chalk "^4.0.0" + ci-info "^2.0.0" + compare-versions "^3.6.0" + cosmiconfig "^6.0.0" + find-versions "^3.2.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^4.2.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" + iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -6837,6 +7171,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: dependencies: safer-buffer ">= 2.1.2 < 3" +icss-utils@^4.0.0, icss-utils@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + idb@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/idb/-/idb-3.0.2.tgz#c8e9122d5ddd40f13b60ae665e4862f8b13fa384" @@ -6859,10 +7200,10 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== image-size@~0.5.0: version "0.5.5" @@ -6884,6 +7225,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-from@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" @@ -6984,23 +7333,23 @@ inquirer-autocomplete-prompt@^1.0.1: figures "^2.0.0" run-async "^2.3.0" -inquirer@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.0.tgz#9e2b032dde77da1db5db804758b8fea3a970519a" - integrity sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ== +inquirer@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" + integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== dependencies: ansi-escapes "^4.2.1" - chalk "^2.4.2" + chalk "^3.0.0" cli-cursor "^3.1.0" cli-width "^2.0.0" external-editor "^3.0.3" figures "^3.0.0" lodash "^4.17.15" mute-stream "0.0.8" - run-async "^2.2.0" - rxjs "^6.4.0" + run-async "^2.4.0" + rxjs "^6.5.3" string-width "^4.1.0" - strip-ansi "^5.1.0" + strip-ansi "^6.0.0" through "^2.3.6" inquirer@^6.2.2: @@ -7054,7 +7403,7 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -7066,11 +7415,6 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -7232,6 +7576,11 @@ is-directory@^0.3.1: resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= +is-docker@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" + integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -7539,7 +7888,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.0: +is-wsl@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== @@ -7664,10 +8013,10 @@ istanbul-lib-instrument@^3.3.0: istanbul-lib-coverage "^2.0.5" semver "^6.0.0" -istanbul-lib-instrument@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz#53321a7970f076262fd3292c8f9b2e4ac544aae1" - integrity sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ== +istanbul-lib-instrument@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" + integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== dependencies: "@babel/core" "^7.7.5" "@babel/parser" "^7.7.5" @@ -7736,15 +8085,7 @@ jasminewd2@0.0.6: resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-0.0.6.tgz#259157f06d2d149fbecb96302c80aa322a377222" integrity sha1-JZFX8G0tFJ++y5YwLICqMio3ciI= -jest-worker@24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== - dependencies: - merge-stream "^2.0.0" - supports-color "^6.1.0" - -jest-worker@^25.1.0: +jest-worker@25.1.0: version "25.1.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.1.0.tgz#75d038bad6fdf58eba0d2ec1835856c497e3907a" integrity sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg== @@ -7752,6 +8093,14 @@ jest-worker@^25.1.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^26.0.0: + version "26.1.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.1.0.tgz#65d5641af74e08ccd561c240e7db61284f82f33d" + integrity sha512-Z9P5pZ6UC+kakMbNJn+tA2RdVdNX5WH1x+5UCBZ9MxIK24pjYtFt96fK+UwBTrjLYm232g1xz0L3eTh51OW+yQ== + dependencies: + merge-stream "^2.0.0" + supports-color "^7.0.0" + jju@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" @@ -7771,11 +8120,6 @@ jquery@^3.4.1: resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== -js-levenshtein@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" - integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -7877,6 +8221,13 @@ json5@^2.1.0: dependencies: minimist "^1.2.0" +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -8132,13 +8483,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - less-loader@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466" @@ -8148,7 +8492,24 @@ less-loader@5.0.0: loader-utils "^1.1.0" pify "^4.0.1" -less@3.10.3, less@^3.10.3: +less@3.11.3: + version "3.11.3" + resolved "https://registry.yarnpkg.com/less/-/less-3.11.3.tgz#2d853954fcfe0169a8af869620bcaa16563dcc1c" + integrity sha512-VkZiTDdtNEzXA3LgjQiC3D7/ejleBPFVvq+aRI9mIj+Zhmif5TvFPM244bT4rzkvOCvJ9q4zAztok1M7Nygagw== + dependencies: + clone "^2.1.2" + tslib "^1.10.0" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + make-dir "^2.1.0" + mime "^1.4.1" + promise "^7.1.1" + request "^2.83.0" + source-map "~0.6.0" + +less@^3.10.3: version "3.10.3" resolved "https://registry.yarnpkg.com/less/-/less-3.10.3.tgz#417a0975d5eeecc52cff4bcfa3c09d35781e6792" integrity sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow== @@ -8164,10 +8525,22 @@ less@3.10.3, less@^3.10.3: request "^2.83.0" source-map "~0.6.0" -license-webpack-plugin@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.3.tgz#656fa6a8b2e711ee35c27ac8e1659a87240ef7f3" - integrity sha512-vTSY5r9HOq4sxR2BIxdIXWKI+9n3b+DoQkhKHedB3TdSxTfXUDRxKXdAj5iejR+qNXprXsxvEu9W+zOhgGIkAw== +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + +license-webpack-plugin@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.4.tgz#c5529a4bb87cc9b4489b486d054ba7cae43a554e" + integrity sha512-1Xq72fmPbTg5KofXs+yI5L4QqPFjQ6mZxoeI6D7gfiEDOtaEIk6PGrdLaej90bpDqKNHNxlQ/MW4tMAL6xMPJQ== dependencies: "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" @@ -8208,7 +8581,16 @@ loader-runner@^2.4.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@2.0.0, loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== @@ -8217,6 +8599,15 @@ loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2. emojis-list "^2.0.0" json5 "^1.0.1" +loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -8461,10 +8852,10 @@ logform@^2.1.1: ms "^2.1.1" triple-beam "^1.3.0" -loglevel@^1.6.4: - version "1.6.6" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" - integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== +loglevel@^1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" + integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== long@^4.0.0: version "4.0.0" @@ -8545,10 +8936,10 @@ magic-string@0.25.3: dependencies: sourcemap-codec "^1.4.4" -magic-string@0.25.4: - version "0.25.4" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.4.tgz#325b8a0a79fc423db109b77fd5a19183b7ba5143" - integrity sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw== +magic-string@0.25.7: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== dependencies: sourcemap-codec "^1.4.4" @@ -8581,6 +8972,13 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-dir@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" + integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== + dependencies: + semver "^6.0.0" + make-fetch-happen@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd" @@ -8603,13 +9001,6 @@ mamacro@^0.0.3: resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -8673,15 +9064,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - memoizee@^0.4.14: version "0.4.14" resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" @@ -8760,6 +9142,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -8784,6 +9171,14 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -8831,7 +9226,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-fn@^2.0.0, mimic-fn@^2.1.0: +mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -8841,10 +9236,10 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mini-css-extract-plugin@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1" - integrity sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw== +mini-css-extract-plugin@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" + integrity sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A== dependencies: loader-utils "^1.1.0" normalize-url "1.9.1" @@ -8901,6 +9296,11 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" @@ -8949,6 +9349,14 @@ minizlib@^1.2.1: dependencies: minipass "^2.9.0" +minizlib@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.0.tgz#fd52c645301ef09a63a2c209697c294c6ce02cf3" + integrity sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -8980,6 +9388,11 @@ mixin-deep@^1.2.0: dependencies: minimist "0.0.8" +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + modify-values@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -9248,13 +9661,18 @@ node-pre-gyp@^0.14.0: semver "^5.3.0" tar "^4.4.2" -node-releases@^1.1.44, node-releases@^1.1.47: +node-releases@^1.1.47: version "1.1.47" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4" integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA== dependencies: semver "^6.3.0" +node-releases@^1.1.53: + version "1.1.53" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" + integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ== + node-sass-tilde-importer@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/node-sass-tilde-importer/-/node-sass-tilde-importer-1.0.2.tgz#1a15105c153f648323b4347693fdb0f331bad1ce" @@ -9329,12 +9747,28 @@ npm-bundled@^1.0.1: dependencies: npm-normalize-package-bin "^1.0.1" +npm-install-checks@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" + integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== + dependencies: + semver "^7.1.1" + npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@6.1.1, npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: +npm-package-arg@8.0.1, npm-package-arg@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.0.1.tgz#9d76f8d7667b2373ffda60bb801a27ef71e3e270" + integrity sha512-/h5Fm6a/exByzFSTm7jAyHbgOqErl9qSNJDQF32Si/ZzgwT2TERVxRxn3Jurw1wflgyVVAxnFR4fRHPM7y1ClQ== + dependencies: + hosted-git-info "^3.0.2" + semver "^7.0.0" + validate-npm-package-name "^3.0.0" + +npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.1" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== @@ -9344,16 +9778,6 @@ npm-package-arg@6.1.1, npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: semver "^5.6.0" validate-npm-package-name "^3.0.0" -npm-package-arg@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-7.0.0.tgz#52cdf08b491c0c59df687c4c925a89102ef794a5" - integrity sha512-xXxr8y5U0kl8dVkz2oK7yZjPBvqM2fwaO5l3Yg13p03v8+E3qQcD0JNhHzjL1vyGgxcKkD0cco+NLR72iuPk3g== - dependencies: - hosted-git-info "^3.0.2" - osenv "^0.1.5" - semver "^5.6.0" - validate-npm-package-name "^3.0.0" - npm-packlist@^1.1.12, npm-packlist@^1.1.6: version "1.4.8" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" @@ -9363,14 +9787,14 @@ npm-packlist@^1.1.12, npm-packlist@^1.1.6: npm-bundled "^1.0.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@3.0.2, npm-pick-manifest@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7" - integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw== +npm-pick-manifest@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.0.0.tgz#bfde7abe95f2670aed1629a3c18245ccb3cc2eb8" + integrity sha512-PdJpXMvjqt4nftNEDpCgjBUF8yI3Q3MyuAmVB9nemnnCg32F4BPL/JFBfdj8DubgHCYUFQhtLWmBPvdsFtjWMg== dependencies: - figgy-pudding "^3.5.1" - npm-package-arg "^6.0.0" - semver "^5.4.1" + npm-install-checks "^4.0.0" + npm-package-arg "^8.0.0" + semver "^7.0.0" npm-pick-manifest@^2.2.3: version "2.2.3" @@ -9381,6 +9805,15 @@ npm-pick-manifest@^2.2.3: npm-package-arg "^6.0.0" semver "^5.4.1" +npm-pick-manifest@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7" + integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw== + dependencies: + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + npm-registry-fetch@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz#2b1434f93ccbe6b6385f8e45f45db93e16921d7a" @@ -9562,12 +9995,13 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/open/-/open-7.0.0.tgz#7e52999b14eb73f90f0f0807fe93897c4ae73ec9" - integrity sha512-K6EKzYqnwQzk+/dzJAQSBORub3xlBTxMz+ntpZpH/LyCa1o6KjXhuN+2npAaI9jaSmU3R1Q8NWf4KUWcyytGsQ== +open@7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" + integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== dependencies: - is-wsl "^2.1.0" + is-docker "^2.0.0" + is-wsl "^2.1.1" open@^6.3.0: version "6.4.0" @@ -9576,6 +10010,11 @@ open@^6.3.0: dependencies: is-wsl "^1.1.0" +opencollective-postinstall@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + opn@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -9601,17 +10040,18 @@ optjs@~3.2.2: resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee" integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4= -ora@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.2.tgz#0e1e68fd45b135d28648b27cf08081fa6e8a297d" - integrity sha512-YUOZbamht5mfLxPmk4M35CD/5DuOkAacxlEUbStVXpBAt4fyhBf+vZHI/HRkI++QUp3sNoeA2Gw4C+hi4eGSig== +ora@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.3.tgz#752a1b7b4be4825546a7a3d59256fa523b6b6d05" + integrity sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg== dependencies: - chalk "^2.4.2" + chalk "^3.0.0" cli-cursor "^3.1.0" cli-spinners "^2.2.0" is-interactive "^1.0.0" log-symbols "^3.0.0" - strip-ansi "^5.2.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" wcwidth "^1.0.1" ora@^3.4.0: @@ -9650,15 +10090,6 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-locale@^3.0.0, os-locale@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -9677,11 +10108,6 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - p-defer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83" @@ -9692,11 +10118,6 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -9704,13 +10125,20 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1, p-limit@^2.2.2: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== dependencies: p-try "^2.0.0" +p-limit@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -9744,6 +10172,13 @@ p-map@^3.0.0: dependencies: aggregate-error "^3.0.0" +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + p-retry@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" @@ -9781,13 +10216,14 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" -pacote@9.5.5: - version "9.5.5" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.5.tgz#63355a393614c3424e735820c3731e2cbbedaeeb" - integrity sha512-jAEP+Nqj4kyMWyNpfTU/Whx1jA7jEc5cCOlurm0/0oL+v8TAp1QSsK83N7bYe+2bEdFzMAtPG5TBebjzzGV0cA== +pacote@9.5.12: + version "9.5.12" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.12.tgz#1e11dd7a8d736bcc36b375a9804d41bb0377bf66" + integrity sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ== dependencies: bluebird "^3.5.3" cacache "^12.0.2" + chownr "^1.1.2" figgy-pudding "^3.5.1" get-stream "^4.1.0" glob "^7.1.3" @@ -9799,9 +10235,10 @@ pacote@9.5.5: mississippi "^3.0.0" mkdirp "^0.5.1" normalize-package-data "^2.4.0" + npm-normalize-package-bin "^1.0.0" npm-package-arg "^6.1.0" npm-packlist "^1.1.12" - npm-pick-manifest "^2.2.3" + npm-pick-manifest "^3.0.0" npm-registry-fetch "^4.0.0" osenv "^0.1.5" promise-inflight "^1.0.1" @@ -9811,18 +10248,17 @@ pacote@9.5.5: safe-buffer "^5.1.2" semver "^5.6.0" ssri "^6.0.1" - tar "^4.4.8" + tar "^4.4.10" unique-filename "^1.1.1" which "^1.3.1" -pacote@9.5.8: - version "9.5.8" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.8.tgz#23480efdc4fa74515855c9ecf39cf64078f99786" - integrity sha512-0Tl8Oi/K0Lo4MZmH0/6IsT3gpGf9eEAznLXEQPKgPq7FscnbUOyopnVpwXlnQdIbCUaojWy1Wd7VMyqfVsRrIw== +pacote@9.5.5: + version "9.5.5" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.5.tgz#63355a393614c3424e735820c3731e2cbbedaeeb" + integrity sha512-jAEP+Nqj4kyMWyNpfTU/Whx1jA7jEc5cCOlurm0/0oL+v8TAp1QSsK83N7bYe+2bEdFzMAtPG5TBebjzzGV0cA== dependencies: bluebird "^3.5.3" cacache "^12.0.2" - chownr "^1.1.2" figgy-pudding "^3.5.1" get-stream "^4.1.0" glob "^7.1.3" @@ -9836,7 +10272,7 @@ pacote@9.5.8: normalize-package-data "^2.4.0" npm-package-arg "^6.1.0" npm-packlist "^1.1.12" - npm-pick-manifest "^3.0.0" + npm-pick-manifest "^2.2.3" npm-registry-fetch "^4.0.0" osenv "^0.1.5" promise-inflight "^1.0.1" @@ -9846,7 +10282,7 @@ pacote@9.5.8: safe-buffer "^5.1.2" semver "^5.6.0" ssri "^6.0.1" - tar "^4.4.10" + tar "^4.4.8" unique-filename "^1.1.1" which "^1.3.1" @@ -9864,6 +10300,13 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0: version "5.1.5" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" @@ -10015,6 +10458,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -10036,6 +10484,11 @@ picomatch@^2.0.4, picomatch@^2.0.7: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== +picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -10070,13 +10523,27 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -pkg-dir@^4.1.0: +pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + +please-upgrade-node@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== + dependencies: + semver-compare "^1.0.0" + plist@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c" @@ -10086,7 +10553,7 @@ plist@^3.0.1: xmlbuilder "^9.0.7" xmldom "0.1.x" -portfinder@^1.0.23, portfinder@^1.0.25: +portfinder@^1.0.23: version "1.0.25" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== @@ -10095,6 +10562,15 @@ portfinder@^1.0.23, portfinder@^1.0.25: debug "^3.1.1" mkdirp "^0.5.1" +portfinder@^1.0.26: + version "1.0.26" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70" + integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.1" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -10247,6 +10723,39 @@ postcss-minify-selectors@^4.0.2: postcss "^7.0.0" postcss-selector-parser "^3.0.0" +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" + integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== + dependencies: + icss-utils "^4.1.1" + postcss "^7.0.16" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.0" + +postcss-modules-scope@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" + integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + postcss-normalize-charset@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" @@ -10375,6 +10884,15 @@ postcss-selector-parser@^5.0.0-rc.4: indexes-of "^1.0.1" uniq "^1.0.1" +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss-svgo@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" @@ -10410,21 +10928,26 @@ postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== +postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + postcss-value-parser@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9" integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ== -postcss@7.0.21: - version "7.0.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" - integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== +postcss@7.0.27: + version "7.0.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9" + integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ== dependencies: chalk "^2.4.2" source-map "^0.6.1" supports-color "^6.1.0" -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.5: +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.5: version "7.0.26" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== @@ -10433,6 +10956,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21 source-map "^0.6.1" supports-color "^6.1.0" +postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.27, postcss@^7.0.6: + version "7.0.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" + integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + prepend-http@^1.0.0, prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -10448,7 +10980,7 @@ pretty-size@^2.0.0: resolved "https://registry.yarnpkg.com/pretty-size/-/pretty-size-2.0.0.tgz#30abccd0e4c9c02007e2d4646a1557d3ae6a66fd" integrity sha1-MKvM0OTJwCAH4tRkahVX065qZv0= -private@^0.1.6, private@^0.1.8: +private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -10698,7 +11230,7 @@ quick-lru@^1.0.0: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -10728,13 +11260,13 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-loader@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-3.1.0.tgz#5e9d399a5a222cc0de18f42c3bc5e49677532b3f" - integrity sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA== +raw-loader@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.0.tgz#d639c40fb9d72b5c7f8abc1fb2ddb25b29d3d540" + integrity sha512-iINUOYvl1cGEmfoaLjnZXt4bKfT2LJnZZib5N/LLyAphC+Dd11vNP9CNVb38j+SAJpFI1uo8j9frmih53ASy7Q== dependencies: - loader-utils "^1.1.0" - schema-utils "^2.0.1" + loader-utils "^1.2.3" + schema-utils "^2.5.0" rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: version "1.2.8" @@ -10943,27 +11475,35 @@ regenerate-unicode-properties@^8.1.0: dependencies: regenerate "^1.4.0" +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + regenerate@^1.2.1, regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== -regenerator-runtime@0.13.3: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" - integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@0.13.5, regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-transform@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" - integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== +regenerator-transform@^0.14.2: + version "0.14.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" + integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== dependencies: - private "^0.1.6" + "@babel/runtime" "^7.8.4" + private "^0.1.8" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" @@ -11002,6 +11542,18 @@ regexpu-core@^4.6.0: unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.1.0" +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + registry-auth-token@^3.0.1: version "3.4.0" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" @@ -11036,7 +11588,7 @@ regjsgen@^0.2.0: resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= -regjsgen@^0.5.0: +regjsgen@^0.5.0, regjsgen@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== @@ -11055,6 +11607,13 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -11141,11 +11700,6 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -11168,6 +11722,11 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -11226,6 +11785,11 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rfdc@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" @@ -11255,10 +11819,10 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2. dependencies: glob "^7.1.3" -rimraf@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b" - integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg== +rimraf@3.0.2, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" @@ -11321,15 +11885,6 @@ rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.5.0, rollup-pluginutils@^2.8.1: dependencies: estree-walker "^0.6.1" -rollup@1.25.2: - version "1.25.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.25.2.tgz#739f508bd8f7ece52bb6c1fcda83466af82b7f6d" - integrity sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg== - dependencies: - "@types/estree" "*" - "@types/node" "*" - acorn "^7.1.0" - rollup@1.29.0: version "1.29.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.29.0.tgz#6a1a79eea43ca9d3d79a90c15a1ceecedc72097b" @@ -11339,6 +11894,13 @@ rollup@1.29.0: "@types/node" "*" acorn "^7.1.0" +rollup@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.1.0.tgz#552e248e397a06b9c6db878c0564ca4ee06729c9" + integrity sha512-gfE1455AEazVVTJoeQtcOq/U6GSxwoj4XPSWVsuWmgIxj7sBQNLDOSA82PbdMe+cP8ql8fR1jogPFe8Wg8g4SQ== + optionalDependencies: + fsevents "~2.1.2" + rollup@^0.36.3: version "0.36.4" resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.36.4.tgz#a224494c5386c1d73d38f7bb86f69f5eb011a3d2" @@ -11371,6 +11933,16 @@ run-async@^2.2.0, run-async@^2.3.0: dependencies: is-promise "^2.1.0" +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" @@ -11397,14 +11969,7 @@ rxjs@6.4.0: dependencies: tslib "^1.9.0" -rxjs@6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a" - integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA== - dependencies: - tslib "^1.9.0" - -rxjs@^6.4.0, rxjs@^6.5.0, rxjs@^6.5.3: +rxjs@6.5.4, rxjs@^6.4.0, rxjs@^6.5.0, rxjs@^6.5.3: version "6.5.4" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== @@ -11433,21 +11998,21 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass-loader@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.0.tgz#e7b07a3e357f965e6b03dd45b016b0a9746af797" - integrity sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w== +sass-loader@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.2.tgz#debecd8c3ce243c76454f2e8290482150380090d" + integrity sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ== dependencies: clone-deep "^4.0.1" loader-utils "^1.2.3" neo-async "^2.6.1" - schema-utils "^2.1.0" + schema-utils "^2.6.1" semver "^6.3.0" -sass@1.23.3: - version "1.23.3" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.23.3.tgz#f07503b9e8d2bcf06ef69e8beea5d085589b1620" - integrity sha512-1DKRZxJMOh4Bme16AbWTyYeJAjTlrvw2+fWshHHaepeJfGq2soFZTnt0YhWit+bohtDu4LdyPoEj6VFD4APHog== +sass@1.26.3: + version "1.26.3" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.26.3.tgz#412df54486143b76b5a65cdf7569e86f44659f46" + integrity sha512-5NMHI1+YFYw4sN3yfKjpLuV9B5l7MqQ6FlkTcC4FT+oHbBRUZoSjHrrt/mE0nFXJyY2kQtU9ou9HxvFVjLFuuw== dependencies: chokidar ">=2.0.0 <4.0.0" @@ -11484,7 +12049,15 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.6.1, schema-utils@^2.6.4: +schema-utils@^2.5.0, schema-utils@^2.6.5: + version "2.6.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a" + integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ== + dependencies: + ajv "^6.12.0" + ajv-keywords "^3.4.1" + +schema-utils@^2.6.1, schema-utils@^2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== @@ -11492,6 +12065,15 @@ schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.6 ajv "^6.10.2" ajv-keywords "^3.4.1" +schema-utils@^2.6.6, schema-utils@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" + schematics-utilities@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/schematics-utilities/-/schematics-utilities-2.0.1.tgz#c763ee078b27d41540a455f3def8f3900edb5d9d" @@ -11529,6 +12111,11 @@ selfsigned@^1.10.7: dependencies: node-forge "0.9.0" +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -11557,6 +12144,11 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" +semver-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" + integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== + "semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -11577,15 +12169,20 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== +semver@7.1.3, semver@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6" + integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA== + semver@^4.3.3: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= -semver@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6" - integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA== +semver@^7.0.0, semver@^7.1.1: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== semver@~5.0.1: version "5.0.3" @@ -11616,6 +12213,13 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== +serialize-javascript@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea" + integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg== + dependencies: + randombytes "^2.1.0" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -11740,6 +12344,11 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + smart-buffer@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" @@ -11845,13 +12454,14 @@ sockjs-client@1.4.0: json3 "^3.3.2" url-parse "^1.4.3" -sockjs@0.3.19: - version "0.3.19" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" - integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== +sockjs@0.3.20: + version "0.3.20" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.20.tgz#b26a283ec562ef8b2687b44033a4eeceac75d855" + integrity sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA== dependencies: faye-websocket "^0.10.0" - uuid "^3.0.1" + uuid "^3.4.0" + websocket-driver "0.6.5" socks-proxy-agent@^4.0.0: version "4.0.2" @@ -11900,14 +12510,6 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.5.16, source-map-support@^0.5.5, source-map-support@~0.5.12: - version "0.5.16" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" - integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@^0.4.0, source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -11915,6 +12517,14 @@ source-map-support@^0.4.0, source-map-support@^0.4.15: dependencies: source-map "^0.5.6" +source-map-support@^0.5.5, source-map-support@~0.5.12: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@~0.2.8: version "0.2.10" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" @@ -11999,10 +12609,10 @@ spdy-transport@^3.0.0: readable-stream "^3.0.6" wbuf "^1.7.3" -spdy@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2" - integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== dependencies: debug "^4.1.0" handle-thing "^2.0.0" @@ -12070,12 +12680,11 @@ ssri@^6.0.0, ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" -ssri@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d" - integrity sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g== +ssri@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808" + integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA== dependencies: - figgy-pudding "^3.5.1" minipass "^3.1.1" stable@^0.1.8: @@ -12185,7 +12794,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: +string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== @@ -12264,7 +12873,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -12317,13 +12926,13 @@ stubs@^3.0.0: resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= -style-loader@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.0.tgz#1d5296f9165e8e2c85d24eee0b7caf9ec8ca1f82" - integrity sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw== +style-loader@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.1.3.tgz#9e826e69c683c4d9bf9db924f85e9abb30d5e200" + integrity sha512-rlkH7X/22yuwFYK357fMN/BxYOorfnfq0eD7+vqlemSK4wEcejFF1dg4zxP0euBW8NrYx2WZzZ8PPFevr7D+Kw== dependencies: loader-utils "^1.2.3" - schema-utils "^2.0.1" + schema-utils "^2.6.4" stylehacks@^4.0.0: version "4.0.3" @@ -12513,6 +13122,30 @@ tar@^4.3.0, tar@^4.4.10, tar@^4.4.2, tar@^4.4.8: safe-buffer "^5.1.2" yallist "^3.0.3" +tar@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.1.tgz#7b3bd6c313cb6e0153770108f8d70ac298607efa" + integrity sha512-bKhKrrz2FJJj5s7wynxy/fyxpE0CmCjmOQ1KV4KkgXFWOgoIT/NbTMnB1n+LFNrNk0SSBVGGxcK5AGsyC+pW5Q== + dependencies: + chownr "^1.1.3" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.0" + mkdirp "^1.0.3" + yallist "^4.0.0" + +tar@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.2.tgz#5df17813468a6264ff14f766886c622b84ae2f39" + integrity sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.0" + mkdirp "^1.0.3" + yallist "^4.0.0" + tcp-port-used@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-1.0.1.tgz#46061078e2d38c73979a2c2c12b5a674e6689d70" @@ -12552,22 +13185,22 @@ term-size@^2.1.0: resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== -terser-webpack-plugin@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.3.tgz#b89043168bd414153bab86f4362ac23d537b78b0" - integrity sha512-gWHkaGzGYjmDoYxksFZynWTzvXOAjQ5dd7xuTMYlv4zpWlLSb6v0QLSZjELzP5dMs1ox30O1BIPs9dgqlMHuLQ== - dependencies: - cacache "^13.0.1" - find-cache-dir "^3.2.0" - jest-worker "^25.1.0" - p-limit "^2.2.2" - schema-utils "^2.6.4" - serialize-javascript "^2.1.2" +terser-webpack-plugin@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-3.0.3.tgz#23bda2687b197f878a743373b9411d917adc2e45" + integrity sha512-bZFnotuIKq5Rqzrs+qIwFzGdKdffV9epG5vDSEbYzvKAhPeR5RbbrQysfPgbIIMhNAQtZD2hGwBfSKUXjXZZZw== + dependencies: + cacache "^15.0.4" + find-cache-dir "^3.3.1" + jest-worker "^26.0.0" + p-limit "^2.3.0" + schema-utils "^2.6.6" + serialize-javascript "^3.1.0" source-map "^0.6.1" - terser "^4.4.3" + terser "^4.6.13" webpack-sources "^1.4.3" -terser-webpack-plugin@^1.4.1: +terser-webpack-plugin@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== @@ -12582,16 +13215,16 @@ terser-webpack-plugin@^1.4.1: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser@4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.5.1.tgz#63b52d6b6ce344aa6fedcd0ee06a695799eb50bd" - integrity sha512-lH9zLIbX8PRBEFCTvfHGCy0s9HEKnNso1Dx9swSopF3VUnFLB8DpQ61tHxoofovNC/sG0spajJM3EIIRSTByiQ== +terser@4.6.10: + version "4.6.10" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.10.tgz#90f5bd069ff456ddbc9503b18e52f9c493d3b7c2" + integrity sha512-qbF/3UOo11Hggsbsqm2hPa6+L4w7bkr+09FNseEe8xrcVD3APGLFqE+Oz1ZKAxjYnFsj80rLOfgAtJ0LNJjtTA== dependencies: commander "^2.20.0" source-map "~0.6.1" source-map-support "~0.5.12" -terser@^4.1.2, terser@^4.3.8, terser@^4.4.3: +terser@^4.1.2, terser@^4.3.8: version "4.6.3" resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== @@ -12600,6 +13233,15 @@ terser@^4.1.2, terser@^4.3.8, terser@^4.4.3: source-map "~0.6.1" source-map-support "~0.5.12" +terser@^4.6.13: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + text-extensions@^1.0.0: version "1.9.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" @@ -12972,21 +13614,16 @@ typedoc@^0.16.4: typedoc-default-themes "^0.7.2" typescript "3.7.x" -typescript@3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" - integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== +typescript@3.6.5, typescript@~3.6.4: + version "3.6.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.5.tgz#dae20114a7b4ff4bd642db9c8c699f2953e8bbdb" + integrity sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ== typescript@3.7.x, typescript@^3.6.3: version "3.7.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== -typescript@~3.6.4: - version "3.6.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.5.tgz#dae20114a7b4ff4bd642db9c8c699f2953e8bbdb" - integrity sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ== - uglify-js@^3.1.4: version "3.7.6" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.6.tgz#0783daa867d4bc962a37cc92f67f6e3238c47485" @@ -13043,6 +13680,11 @@ unicode-match-property-value-ecmascript@^1.1.0: resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + unicode-property-aliases-ecmascript@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" @@ -13096,7 +13738,7 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -universal-analytics@^0.4.16, universal-analytics@^0.4.20: +universal-analytics@0.4.20, universal-analytics@^0.4.16: version "0.4.20" resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.20.tgz#d6b64e5312bf74f7c368e3024a922135dbf24b03" integrity sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw== @@ -13304,12 +13946,17 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.2.tgz#7ff5c203467e91f5e0d85cfcbaaf7d2ebbca9be6" + integrity sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw== + uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho= -uuid@^3.0.0, uuid@^3.0.1, uuid@^3.3.2: +uuid@^3.0.0, uuid@^3.3.2, uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -13402,10 +14049,10 @@ webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz#27c3b5d0f6b6677c4304465ac817623c8b27b89c" - integrity sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw== +webpack-dev-server@3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz#8f154a3bce1bcfd1cc618ef4e703278855e7ff8c" + integrity sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -13415,31 +14062,31 @@ webpack-dev-server@3.9.0: debug "^4.1.1" del "^4.1.1" express "^4.17.1" - html-entities "^1.2.1" + html-entities "^1.3.1" http-proxy-middleware "0.19.1" import-local "^2.0.0" internal-ip "^4.3.0" ip "^1.1.5" is-absolute-url "^3.0.3" killable "^1.0.1" - loglevel "^1.6.4" + loglevel "^1.6.8" opn "^5.5.0" p-retry "^3.0.1" - portfinder "^1.0.25" + portfinder "^1.0.26" schema-utils "^1.0.0" selfsigned "^1.10.7" semver "^6.3.0" serve-index "^1.9.1" - sockjs "0.3.19" + sockjs "0.3.20" sockjs-client "1.4.0" - spdy "^4.0.1" + spdy "^4.0.2" strip-ansi "^3.0.1" supports-color "^6.1.0" url "^0.11.0" webpack-dev-middleware "^3.7.2" webpack-log "^2.0.0" ws "^6.2.1" - yargs "12.0.5" + yargs "^13.3.2" webpack-log@^2.0.0: version "2.0.0" @@ -13464,17 +14111,17 @@ webpack-sources@1.4.3, webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-s source-list-map "^2.0.0" source-map "~0.6.1" -webpack-subresource-integrity@1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.3.4.tgz#4554e0c622d6787f880eba009cdb73139c107bad" - integrity sha512-6XbGYzjh30cGQT/NsC+9IAkJP8IL7/t47sbwR5DLSsamiD56Rwv4/+hsgEHsviPvrEFZ0JRAQtCRN3UsR2Pw9g== +webpack-subresource-integrity@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.4.0.tgz#44963a64c9a214ad729158e7f46d52c2525cc88a" + integrity sha512-GB1kB/LwAWC3CxwcedGhMkxGpNZxSheCe1q+KJP1bakuieAdX/rGHEcf5zsEzhKXpqsGqokgsDoD9dIkr61VDQ== dependencies: webpack-sources "^1.3.0" -webpack@4.41.2: - version "4.41.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.2.tgz#c34ec76daa3a8468c9b61a50336d8e3303dce74e" - integrity sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A== +webpack@4.42.0: + version "4.42.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8" + integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -13496,10 +14143,17 @@ webpack@4.41.2: node-libs-browser "^2.2.1" schema-utils "^1.0.0" tapable "^1.1.3" - terser-webpack-plugin "^1.4.1" + terser-webpack-plugin "^1.4.3" watchpack "^1.6.0" webpack-sources "^1.4.1" +websocket-driver@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + integrity sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY= + dependencies: + websocket-extensions ">=0.1.1" + websocket-driver@>=0.5.1: version "0.7.3" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" @@ -13560,6 +14214,11 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + which@^1.2.1, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -13638,10 +14297,10 @@ worker-farm@^1.7.0: dependencies: errno "~0.1.7" -worker-plugin@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-3.2.0.tgz#ddae9f161b76fcbaacf8f54ecd037844584e43e7" - integrity sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q== +worker-plugin@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-4.0.3.tgz#7c42e600d5931ad154d3d5f187a32446df64db0f" + integrity sha512-7hFDYWiKcE3yHZvemsoM9lZis/PzurHAEX1ej8PLCu818Rt6QqUAiDdxHPCKZctzmhqzPpcFSgvMCiPbtooqAg== dependencies: loader-utils "^1.1.0" @@ -13653,6 +14312,15 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -13738,6 +14406,11 @@ xhr2@^0.1.4: resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= +xhr2@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.2.0.tgz#eddeff782f3b7551061b8d75645085269396e521" + integrity sha512-BDtiD0i2iKPK/S8OAZfpk6tyzEDnKKSjxWHcMBVmh+LuqJ8A32qXTyOx+TVOg2dKvq6zGBq2sgKPkEeRs1qTRA== + xml2js@0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" @@ -13788,7 +14461,7 @@ y18n@^3.2.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: +y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== @@ -13808,18 +14481,15 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yaml@^1.7.2: + version "1.10.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" + integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== -yargs-parser@^13.0.0: - version "13.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" - integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" @@ -13832,40 +14502,46 @@ yargs-parser@^16.1.0: camelcase "^5.0.0" decamelize "^1.2.0" -yargs@12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== +yargs-parser@^18.1.0: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== dependencies: - cliui "^4.0.0" + camelcase "^5.0.0" decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" + +yargs@15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.0.tgz#403af6edc75b3ae04bf66c94202228ba119f0976" + integrity sha512-g/QCnmjgOl1YJjGsnUg2SatC7NUYEiLXJqxNOQU9qSpjzGtGXda9b+OKccr1kLTy8BN9yqEyqfq5lxlwdc13TA== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" require-directory "^2.1.1" - require-main-filename "^1.0.1" + require-main-filename "^2.0.0" set-blocking "^2.0.0" - string-width "^2.0.0" + string-width "^4.2.0" which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" + y18n "^4.0.0" + yargs-parser "^18.1.0" -yargs@13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301" - integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg== +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== dependencies: - cliui "^4.0.0" + cliui "^5.0.0" find-up "^3.0.0" get-caller-file "^2.0.1" - os-locale "^3.1.0" require-directory "^2.1.1" require-main-filename "^2.0.0" set-blocking "^2.0.0" string-width "^3.0.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^13.0.0" + yargs-parser "^13.1.2" yargs@^15.0.2: version "15.1.0"